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

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得到的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构建添加依赖

    
    <dependency>
      <groupId>us.codecraftgroupId>
      <artifactId>webmagic-coreartifactId>
      <version>0.5.3version>
    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 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="{"totalPage":100,"curPage":1}">
       <a class="on" href="http://localhost:8000/ershoufang/" data-page="1">1a>
       <a href="http://localhost:8000/ershoufang/pg2/" data-page="2">2a>
       <a href="http://localhost:8000/ershoufang/pg3/" data-page="3">3a>
       <span>...span>
       <a href="http://localhost:8000/ershoufang/pg100/" data-page="100">100a>
       <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,代码不详细写了。

你可能感兴趣的:(webmagic,seimiagent,网页抓取)