c httpclient抓取网页(如何开发一个Java爬虫(的设计机制及原理))
优采云 发布时间: 2021-09-15 13:25c httpclient抓取网页(如何开发一个Java爬虫(的设计机制及原理))
最近,我正在编写一个小爬虫来爬升一些网页数据,以便进行模型训练。在考虑如何抓取网页和分析网页时,我参考了OSC站的一些项目,特别是webmagic的设计机制和原理——如何开发@Huang Yihua编写的Java爬虫。Webmagic是一个垂直爬虫,我想写的是一个通用的爬虫,主要是爬上中文的网站内容。对于HTTP协议和消息处理,没有比httpclient组件更好的选择了。对于HTML代码解析,在比较了Htmlparser和jsoup之后,后者在API使用方面有明显的优势,简单易懂。在确定使用的开源组件之后,我们开始考虑如何捕获和解析这两个基本函数
对于我的爬虫爬行功能,只需根据网页的URL抓取HTML代码,然后解析HTML代码中的链接和链接
标记的文本是OK的,因此解析结果可以用page类表示。这个课程纯粹是一个POJO。如何使用httpclient和jsup直接解析为页面对象
在httpclient4.2在中,提供了responsehandler来处理httpresponse。因此,通过实现此接口,可以将返回的HTML代码解析为所需的页面对象。其主要思想是读取httpresponse中的数据,将其转换为HTML代码,然后使用jsoup对其进行解析
标签和标签。代码如下
公共类PageResponseHandler实现ResponseHandler
{
private Page page;
public PageResponseHandler(Page page) {
this.page = page;
}
public void setPage(Page page) {
this.page = page;
}
public Page getPage() {
return page;
}
@Override
public Page handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
StatusLine statusLine = response.getStatusLine();
HttpEntity entity = response.getEntity();
if (statusLine.getStatusCode() >= 300) {
EntityUtils.consume(entity);
throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase());
}
if (entity == null)
return null;
// 利用HTTPClient自带的EntityUtils把当前HttpResponse中的HttpEntity转化成HTML代码
String html = EntityUtils.toString(entity);
Document document = Jsoup.parse(html);
Elements links = document.getElementsByTag("a");
for (int i = 0; i < links.size(); i++) {
Element link = links.get(i);
page.addAnchor(link.attr("href"), link.text());
}
// parse context of plain text from HTML code,
Elements paragraphs = document.getElementsByTag("p");
StringBuffer plainText = new StringBuffer(html.length() / 2);
for (int i = 0; i < paragraphs.size(); i++) {
Element paragraph = paragraphs.get(i);
plainText.append(paragraph.text()).append("\n");
}
page.setPlainText(plainText.toString());
return page;
}
}
代码不超过40行,非常简单。现在可以直接返回页面对象。编写一个测试类来测试pageresponsehandler。测试此类的函数不需要复杂的代码
公共类页面响应HandlerTest{
HttpClient httpclient;
PageResponseHandler pageResponseHandler;
final String url = "http://news.163.com/13/0903/11/97RHS2NS0001121M.html";
Page page = new Page(url);
@Before
public void setUp() throws Exception {
httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet(url);
pageResponseHandler = new PageResponseHandler(page);
httpclient.execute(httpget, pageResponseHandler);
}
@After
public void tearDown() throws Exception {
httpclient.getConnectionManager().shutdown();
}
@Test
public void test() {
System.out.println(page.getPlainText());
assertTrue(page.getPlainText().length() > 0);
assertTrue(page.getAnchors().size() > 0);
}
}
到目前为止,该爬虫程序中的爬虫和分析功能运行良好。它也能很好地分析汉语。细心的读者会发现这些代码中没有字符集或字符集转换。稍后我们将讨论httpclient4.2组件中字符集的处理
首先,回顾内容类型在HTTP协议RFC规范中的作用。它指示发送给收件人的HTTP实体内容的媒体类型。对于文本类型httpentity,它通常采用以下形式,指定httpentity的媒体类型以及用于编码的字符集。此外,RFC规范还规定,如果内容类型未指定字符集,则默认情况下使用iso-8859-1字符集对HTTP实体进行编码
一,
内容类型:text/html;字符集=UTF-8
此时,您应该能够猜测httpclient4.2如何正确编码——也就是说,使用内容类型头中收录的字符集作为编码的输入源。有关特定代码,请参见entityutils类第212行开始的代码。Entityutils首先从httpentity对象获取内容类型。如果内容类型的字符集不是空的,它将使用内容类型对象中指定的字符集进行编码。否则,它将使用开发人员指定的字符集进行编码。如果开发人员未指定字符集,则使用默认字符集iso-8859-1进行编码。当然,编码是实现的,或者调用JDK的reader类
ContentType ContentType=ContentType.getOrDefault(实体)
Charset Charset=contentType.getCharset()
if(字符集==null){
charset=defaultCharset
}
if(字符集==null){