爬虫入门系列
本系列文章介绍一下爬虫入门的相关技术,如:
- 爬虫介绍
- 网页下载模块
- 如何分析网页请求
- 如何按照深度来进行网页抓取
- 如何在抓取中使用模板
- 其他一些爬虫相关
爬虫介绍
网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。另外一些不常使用的名字还有蚂蚁、自动索引、模拟程序或者蠕虫。—— [ 百度百科 ]
网页下载
网络下载部分是爬虫最重要的组件之一,选择一个好的网络下载工具,能够提高开发效率,节省开发时间。通用的有
项目 | 价格 |
---|---|
urlconnection | jdk自带,据我所知,基本爬虫没有使用这个的 |
httpclient | apache提供,大部分爬虫都使用这个 |
Okhttp | 谷歌出品,最开始使用在android,现在慢慢在爬虫上也有使用的 |
htmlunit | 一个java的无界面浏览器,出发点是好的,兼容性实在是垃圾 |
selenium+有界面浏览器系列 | 能够访问所有的网页,包括控件,唯一的问题是速度和资源 |
selenium+phantomjs | 能够处理很大一部分网页,在linux下也很好,网络渲染也不错,但是在采集某些网页的情况容易出现诡异问题。 |
本篇文章主要介绍使用httpclient下载网页,以及对httpclient进行初步封装,本篇文章的代码请参考Github
- 使用httpclient get请求
- 使用httpclient post请求
- 封装httpclient
使用httpclient get请求
- 声明一个httpclient对象
- 声明httpget方法,通过这个方法get请求具体的url
- 执行httpget请求
- 取得网页源码
下面是httpclient官方网站的一个例子
import java.io.IOException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class ClientWithResponseHandler {
public final static void main(String[] args) throws Exception {
// 声明一个httpclient对象,然后所有的访问都使用这个httpclient
CloseableHttpClient httpclient = HttpClients.createDefault();
try {
// 声明httpget方法,通过这个方法get请求具体的url
HttpGet httpget = new HttpGet("http://httpbin.org/");
// 输出结果 GET http://httpbin.org/ HTTP/1.1
// GET 请求方法
// http://httpbin.org/ 请求url
// HTTP/1.1 请求的http协议
System.out.println("Executing request " + httpget.getRequestLine());
// 这个在一般的爬虫中不需要这么处理,可以换一种方式
// Create a custom response handler
ResponseHandler<String> responseHandler = new ResponseHandler<String>() {
@Override
public String handleResponse(
final HttpResponse response) throws ClientProtocolException, IOException {
int status = response.getStatusLine().getStatusCode();
if (status >= 200 && status < 300) {
HttpEntity entity = response.getEntity();
return entity != null ? EntityUtils.toString(entity) : null;
} else {
throw new ClientProtocolException("Unexpected response status: " + status);
}
}
};
// 执行httpget请求 这里可以使用下面的代码
String responseBody = httpclient.execute(httpget, responseHandler);
System.out.println("----------------------------------------");
// 输出网页源码
System.out.println(responseBody);
} finally {
httpclient.close();
}
}
}
使用httpclient post请求
使用httpclient 进行post请求和get请求很类似
- 声明一个httpclient对象
- 声明httppost方法,通过这个方法post请求具体的url
- 将post数据添加到httppost对象上
- 执行httppost请求
- 取得网页源码
这里本想使用hc官网例子,但是官网例子是提交文件,不适合初学者,所以使用其他例子。
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
public class Snippet {
public static void main(String[] args) {
CloseableHttpClient httpClient = HttpClients.createDefault();
try {
// httppost的url 这里用上本机的某个工程做测试
HttpPost post = new HttpPost("http://localhost/....");
// 创建参数列表,这里是form表单的形式
List<NameValuePair> list = new ArrayList<NameValuePair>();
list.add(new BasicNameValuePair("j_username", "admin"));
list.add(new BasicNameValuePair("j_password", "admin"));
// url格式编码
UrlEncodedFormEntity uefEntity = new UrlEncodedFormEntity(list, "UTF-8");
// 将postdata添加到post方法上
post.setEntity(uefEntity);
// 执行请求
CloseableHttpResponse httpResponse = httpClient.execute(post);
try {
HttpEntity entity = httpResponse.getEntity();
if (null != entity) {
System.out.println("-------------------------------------------------------");
System.out.println(EntityUtils.toString(uefEntity));
System.out.println("-------------------------------------------------------");
}
} finally {
httpResponse.close();
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
httpClient.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
封装httpclient
封装httpclient是对爬虫开发工作是十分重要的,封装的好处。
- 统一调用HttpGet ,HttpPost方法
- 方便对httpclient进行升级,或者改变为其他的请求组件,如OKHttp等
- 代码复用,便于阅读
- 所有功能统一处理
以上面两个例子为例,将相同部分统一处理 (注意,这里只是初步封装,代码未经测试,具体请以Github上为准)
没啥说的这里肯定使用一个了。
// 声明一个httpclient对象,然后所有的访问都使用这个httpclient
CloseableHttpClient httpClient = HttpClients.createDefault();
这里是不一样的,每次访问都需要new的,那有相同的吗?答案是有 通过观察类结构发现 httpget和httpPost都继承过HttpRequestBase类,那么好可以改写成
// 声明httpget方法,通过这个方法get请求具体的url
HttpGet httpget = new HttpGet("http://httpbin.org/");
// httppost的url 这里用上本机的某个工程做测试
HttpPost post = new HttpPost("http://localhost/....");
// 初步封装后
String methodstr = "get";
HttpRequestBase method = null;
if ("get".equals(methodstr)) {
method = new HttpGet("");
} else {
HttpPost post = new HttpPost("");
List<NameValuePair> list = new ArrayList<NameValuePair>();
list.add(new BasicNameValuePair("j_username", "admin"));
list.add(new BasicNameValuePair("j_password", "admin"));
// url格式编码
UrlEncodedFormEntity uefEntity = new UrlEncodedFormEntity(list, "UTF-8");
// 将postdata添加到post方法上
post.setEntity(uefEntity);
method = post;
}
这里尽管例子代码就这些,但是实际有很多需要处理的比如302处理,404处理,网页编码或字节处理,或传输方式处理,这些都要在下面这段代码处理
// 执行请求
CloseableHttpResponse httpResponse = httpClient.execute(post);
try {
HttpEntity entity = httpResponse.getEntity();
if (null != entity) {
System.out.println("-------------------------------------------------------");
System.out.println(EntityUtils.toString(uefEntity));
System.out.println("-------------------------------------------------------");
}
} finally {
httpResponse.close();
}
总结
httpclient是一个十分好用的工具,这里只是初步介绍一下,作者水平有限,可能有错误的地方欢迎指正,转载请注明出处(http://blog.csdn.net/qq329966505/article/details/52145024),谢谢