webmagic结合seimiagent实现动态信息页面的采集

时间:2022-02-26 16:56:48

webmagic结合seimiagent实现动态信息页面的采集

简介

webmagic是一个非常流行的已api方式采集网页信息的项目,但是对于动态加载的信息不能很好的支持,而目前大多数网页都或多或少的采用了动态加载方式展示页面信息。

目前webmagic已经有了一个解决方案–webmagic-selenium,采用了自动测试工具selenium为支撑的方式采集,但是笔者发现了另外一个开源项目也能很好的实现这个功能。

存在的问题(坑)

1 seimiagent性能较差,建议对一次采集非动态页面采用原始采集方法,动态页面通过seimiagent采集。

2 seimiagent暂时好像不支持集群的方式(没有详细测试),如果大规模采集可能会遇到技术瓶颈

3 seimiagent只支持post请求,解析HTML页面分析链接时候比较麻烦。

网页分析

以大连链家网为例(http://dl.lianjia.com/ershoufang/rs/),页面下部的翻页按钮都是通过动态加载方式得到的。

虽然我们在浏览器上是能够看到翻页按钮的但是,这部分按钮是执行js后生成,webmagic是不会执行js的,所以在webmagic看来这个网页就是js和html代码并不包含分页按钮部分。

webmagic结合seimiagent实现动态信息页面的采集

通过下面的程序可以查看webmagic得到的html代码

package us.codecraft.webmagic.samples;

import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.pipeline.FilePipeline;
import us.codecraft.webmagic.processor.PageProcessor;


/**
* 大连链家网数据采集
* http://dl.lianjia.com/ershoufang/rs/
* Created by hp on 2016/12/14.
*/

public class LianjiaDLPageProcessor implements PageProcessor {
private Site site = Site.me().setRetryTimes(3).setSleepTime(1000);
@Override
public void process(Page page) {
System.out.println( page.getHtml().toString());
}
@Override
public Site getSite() {
return site;
}
public static void main(String[] args) {
Spider.create(new LianjiaDLPageProcessor()).addUrl("http://dl.lianjia.com/ershoufang/rs/")
.addPipeline(new FilePipeline("/home/hp/lianjia.txt")).thread(40).run();

}
}

seimiagent安装

1 官方文档(http://seimiagent.org/doc/2016/05/29/zh.html)
2 首先你需要一个linux服务器

官方文档上对于部署已经讲的非常清晰了。这里我就不过多的介绍了。笔者采用了目前(2016/12/14)最新的版本1.3.1,部署成功后输入如下:

hp@master:~/software/seimiagent_v1.3.1/bin$ ./seimiagent 
[seimi] SeimiAgent started,listening on : 8000

webmagic构建

采用maven构建添加依赖

    <!-- https://mvnrepository.com/artifact/us.codecraft/webmagic-core -->
<dependency>
<groupId>us.codecraft</groupId>
<artifactId>webmagic-core</artifactId>
<version>0.5.3</version>
</dependency>

调用seimiagent

webmagic提供了Request对象,此对象目前支持post请求。代码示例

package us.codecraft.webmagic.samples;

import org.apache.commons.collections.map.HashedMap;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Request;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.processor.PageProcessor;
import us.codecraft.webmagic.utils.HttpConstant;

import java.util.Map;


/**
* 大连链家网数据采集
*
* Created by hp on 2016/9/9.
*/

public class LianjiaDLPageProcessor implements PageProcessor {

private Site site = Site.me().setTimeOut(300000)
.setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10; rv:33.0) Gecko/20100101 Firefox/33.0")
.addHeader("Accept", "text/html,utf-8,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
.addHeader("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");

@Override
public void process(Page page) {
System.out.println( page.getHtml().toString());
}

@Override
public Site getSite() {
return site;
}

public static void main(String[] args) {
Spider spider = Spider.create(new LianjiaDLPageProcessor());
Request request = new Request("http://localhost:8000/doload");
Map<String, Object> nameValuePair = new HashedMap();
NameValuePair[] values = new NameValuePair[2];
values[0]=new BasicNameValuePair("url","http://dl.lianjia.com/ershoufang/rs/");
values[1]=new BasicNameValuePair("proxy","http://hepan:xxxx@xxxx:8080"); //不用代理上网的可以不加这个参数
nameValuePair.put("nameValuePair", values);

request.setExtras(nameValuePair);
request.setMethod(HttpConstant.Method.POST);
spider.addRequest(request);
spider.run();

}
}

从输出结果我们看到通过seimiagent我们得到了动态加载后的页面信息

     <div class="page-box fr">
<div class="page-box house-lst-page-box" comp-module="page" page-url="/ershoufang/pg{page}/" page-data="{&quot;totalPage&quot;:100,&quot;curPage&quot;:1}">
<a class="on" href="http://localhost:8000/ershoufang/" data-page="1">1</a>
<a href="http://localhost:8000/ershoufang/pg2/" data-page="2">2</a>
<a href="http://localhost:8000/ershoufang/pg3/" data-page="3">3</a>
<span>...</span>
<a href="http://localhost:8000/ershoufang/pg100/" data-page="100">100</a>
<a href="http://localhost:8000/ershoufang/pg2/" data-page="2">下一页</a>
</div>
</div>

还需要解决的问题

1 从上面的链接信息(http://localhost:8000/ershoufang/pg2/)可以看到域名变成了seimiagent的地址,在实际使用的时候需要将这个地址替换成实际网站的地址。
2 如果需要继续分析网站并将链接放入page中(调用addTargetRequest方法)那么还需要从写一个过滤器,因为原来的过滤器使用的是显示的url并非request中的参数,这样我们看到的url就都是localhost:8000这个地址了。需要将url从request中拆解出来然后在放入过滤器。

page中解析url

    @Override
public void process(Page page) {
System.out.println(page.getUrl());
NameValuePair[] values= (NameValuePair[]) page.getRequest().getExtra("nameValuePair");
for(NameValuePair n:values){
System.out.println(n.getName()+" "+n.getValue());
}
}

getExtra("nameValuePair")可以获得main函数中传入的参数。

这样我们就得到了原始的地址了,可以通过原始地址做一些正则的判断之类的代码。

分析链接

在分析链接之后可以通过再构造一个Request对象然后调用page的public void addTargetRequest(String requestString)方法继续调用seimiagent,代码不详细写了。