Java网络爬虫基础
Http基础
网络资源一般是Web服务器上的一些各种格式的文件,通过Http协议传输互联网上的数据.
在Java中,通常通过URL标出网络资源的位置和Web服务器建立链接,获取网页源代码. 爬虫程序通过域名服务(Domain Name Serive,简称 DNS)取得域名对应的IP地址,它首先连接到一个DNS服务器上,由DNS服务器返回域名对应的IP地址.DNS把解析到错误的域名叫做DNS劫持.
Linux常用如下命令来分析DNS解析的问题(以下命令暂以百度为例)
$ dig www.baidu.com
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7_9.5 <<>> www.baidu.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 60412
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;www.baidu.com. IN A
;; ANSWER SECTION:
www.baidu.com. 419 IN CNAME www.a.shifen.com.
www.a.shifen.com. 149 IN A 110.242.68.3
www.a.shifen.com. 149 IN A 110.242.68.4
;; Query time: 1 msec
;; SERVER: 183.60.83.19#53(183.60.83.19)
;; WHEN: Wed Mar 23 22:16:36 CST 2022
;; MSG SIZE rcvd: 90
$ nslookup www.baidu.com
Server: 183.60.83.19
Address: 183.60.83.19#53
Non-authoritative answer:
www.baidu.com canonical name = www.a.shifen.com.
Name: www.a.shifen.com
Address: 110.242.68.4
Name: www.a.shifen.com
Address: 110.242.68.3
在Windows下可以以如下方法查看路由情况.
> tracert -d www.baidu.com
通过最多 30 个跃点跟踪
到 www.a.shifen.com [110.242.68.3] 的路由:
1 <1 毫秒 <1 毫秒 1 ms 192.168.1.1
2 1 ms 1 ms 1 ms 192.168.18.1
3 4 ms 3 ms 2 ms 111.161.232.1
4 3 ms 2 ms 2 ms 117.8.159.205
5 3 ms 3 ms 3 ms 117.10.223.117
6 * * * 请求超时。
7 9 ms 9 ms 9 ms 110.242.66.186
8 * * * 请求超时。
9 * * * 请求超时。
10 * * * 请求超时。
11 * * * 请求超时。
12 * * * 请求超时。
13 9 ms 9 ms 9 ms 110.242.68.3
跟踪完成。
通过Java来获取一个网站所有的IP
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args)
{
try {
List<String> ipList = new ArrayList<>();
InetAddress[] addressesList = InetAddress.getAllByName("www.sina.com.cn");
for(InetAddress address:addressesList)
{
ipList.add(address.getHostAddress());
System.out.println(address.getHostAddress());
}
}catch (Exception e){e.printStackTrace();}
}
}
URL可选择一个指定的端口,它用于建立远程主机TCP(Transmission Control Protocol)连接的端口号,如果未指定端口则默认使用默认端口,80端口.
URI
URI包括URL和URN,但是URN并不常用.URL由3部分组成:
https://finance.sina.com.cn/stock/ 协议名 主机名 资源路径 http finance.sina.com.cn stock
Http规范定义了8种可能的请求方法,爬虫经常用到的有以下三种:
方法 说明 GET 检索URI种标识资源的一个简单请求 HEAD 与GET方法相同,服务器只返回状态行和头标,不返回请求文档 POST 服务器接受被写入客户端输出流中的数据的请求,可以用POST方法来提交表单参数
发送给Web服务器的请求头参数
请求头参数 含义 Accept:text/plain,text/html 说明了可以接收文本类型的信息 Referer:https://www.sina.com.cn/ 此值告诉服务器访问来自于哪个页面,服务器由此可以获得一些信息用于处理,有的网站会利用此参数用于防止图片盗链 Keep-alive:115 是指在同一个链接中发出和接收多次HTTP请求
Web服务器处理返回的状态码分类
状态码 类型 作用 1xx 信息响应类 表示接收到请求并且继续处理 2xx 处理成功响应类 表示动作被成功接收、理解和接受 3xx 重定向响应类 为了完成指定动作,必须接受进一步处理 4xx 客户端错误 客户端请求包含语法错误或者不能正确执行 5xx 服务端错误 服务器不能正确执行一个正确的请求
HTTP常用状态码
状态代码 代码描述 处理方式 200 请求成功 获得响应的内容,进行处理 201 请求完成,结果是创建了新资源.新创建资源的URI可在响应的实体中得到 爬虫不会遇到 202 请求被接受,但处理尚未完成 阻塞等待 204 服务器端已经实现了请求,但没有返回新的信息,如果客户是用户代理,则无须为此更新自身的文档视图 丢弃 300 该状态码不被HTTP/1.0的应用程序直接使用,只是作为3xx类型回应的默认解释,存在多个可用的被请求资源 若程序中能够处理,则进行进一步处理,如果程序中不能处理,则丢弃 301 请求到的资源都会分配一个永久的URL,这样就可以在将来通过该URL来访问此资源 重定向到分配的URL 302 请求到的资源在一个不同的URL处临时保存 重定向到临时的URL 304 请求的资源未更新 丢弃 400 非法请求 丢弃 401 未授权 丢弃 403 禁止 丢弃 404 没有找到 丢弃 500 服务器内部错误 丢弃 502 错误网关 丢弃 503 服务器暂时不可用 丢弃
Get Post Head方法的基础Java代码
Maven依赖:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.3</version>
</dependency>
Head:
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import java.net.URI;
public class Head {
private String url="";
public void setUrl(String url)
{
this.url=url;
}
public void doHead() throws Exception
{
CloseableHttpClient closeableHttpClient= HttpClientBuilder.create().build();
URI uri=new URI(url);
HttpHead method=new HttpHead(uri);
HttpResponse response=closeableHttpClient.execute(method);
Header[] s=response.getAllHeaders();
for(int i=0;i<s.length;i++)
{
Header hd=s[i];
System.out.println("Header Name: "+hd.getName()+" "+"Header Value: "+hd.getValue());
}
}
}
Get:
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Get {
private String url="";
public void setUrl(String url)
{
this.url=url;
}
private String cookie="";
public void setCookie(String cookie)
{
this.cookie=cookie;
}
private Map header=new HashMap();
public void addHeader(String key,String value)
{
header.put(key,value);
}
private String html="";
public String doGet() throws Exception
{
CloseableHttpClient closeableHttpClient= HttpClientBuilder.create().build();
HttpGet httpGet=new HttpGet(url);
/* 传参 */
// httpGet.addHeader("User-Agent","Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36");
// httpGet.setHeader("Cookie","HttpOnly; UM_distinctid=176d650b687fc-0a035a289264ec-1e2e1b0b-1fa400-176d650b688c77; Hm_lvt_080dabacb001ad3dc8b9b9049b36d43b=1609913383; f_city=%E5%A4%A9%E6%B4%A5%7C101030100%7C; Wa_lvt_1=1609913383; CNZZDATA1278536588=1934037795-1609908526-%7C1609918974");
Set<Map.Entry<String,String>> entrySet=header.entrySet();
for(Map.Entry<String,String> entryset:entrySet)
{
httpGet.setHeader(entryset.getKey(),entryset.getValue());
}
HttpResponse response=closeableHttpClient.execute(httpGet);
HttpEntity entity=response.getEntity();
if(entity!=null)
{
html= EntityUtils.toString(entity,"UTF-8");
EntityUtils.consume(entity);
}
return html;
}
}
Post:
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.ByteArrayBuffer;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.util.*;
public class Post {
private String url="";
public void setUrl(String url)
{
this.url=url;
}
private String cookie="";
public void setCookie(String cookie)
{
this.cookie=cookie;
}
private Map<String,String> header=new HashMap<>();
public void addHeader(String key,String value) {
header.put(key,value);
}
private List<NameValuePair> nameValuePairs=new ArrayList<NameValuePair>();
public void addNameValuePairs(String key,String value)
{
nameValuePairs.add(new BasicNameValuePair(key,value));
}
public String doPost() throws Exception
{
CloseableHttpClient httpClient= HttpClientBuilder.create().build();
HttpPost httpPost=new HttpPost(url);
Set<Map.Entry<String,String>> entrySet=header.entrySet();
for(Map.Entry<String,String> entryset:entrySet)
{
httpPost.setHeader(entryset.getKey(),entryset.getValue());
}
/* 传参 */
// httpPost.setHeader("Content-Type","application/x-www-form-urlencoded");
// httpPost.setHeader("Cookie",cookie);
// nameValuePairs.add(new BasicNameValuePair("page","1"));
// nameValuePairs.add(new BasicNameValuePair("rp","12"));
// nameValuePairs.add(new BasicNameValuePair("sortname","_CreateTime"));
// nameValuePairs.add(new BasicNameValuePair("sortorder","desc"));
// nameValuePairs.add(new BasicNameValuePair("query",""));
// nameValuePairs.add(new BasicNameValuePair("qtype",""));
// nameValuePairs.add(new BasicNameValuePair("queryid","flowmystart"));
// nameValuePairs.add(new BasicNameValuePair("condition","_UserName='53c6b305-5bea-450a-b7a1-11ce1feab4b2'"));
httpPost.setHeader("cookie",cookie);
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response=httpClient.execute(httpPost);
HttpEntity entity=response.getEntity();
InputStream inputStream=entity.getContent();
BufferedInputStream bufferedInputStream=new BufferedInputStream(inputStream);
ByteArrayBuffer byteArrayBuffer=new ByteArrayBuffer(20);
int current=0;
while((current=bufferedInputStream.read())!=-1)
{
byteArrayBuffer.append((byte) current);
}
String text=new String(byteArrayBuffer.toByteArray());
System.out.println(text);
return text;
}
}