GuozhongCrawler实现一个完整爬虫

来源:互联网 发布:xyz域名 co 编辑:程序博客网 时间:2024/05/17 08:06

原文转载自:http://my.oschina.net/u/1377701/blog/403282

由于版本问题,此项目API已过时。


经过上一节开发环境搭建中的百度新闻的爬虫例子,相信大家已经对GuozhongCrawler简洁的API产生浓厚兴趣了。不过这个还不算一个入门例子。只是完成了简单的下载和解析。现在我们来完成一个比较完整的爬虫吧。

    为了体现GuozhongCrawler适应业务灵活性。我们以抓取西刺代理(http://www.xici.net.co/nn/1)的代理IP为需求。需要遍历每一页所有的IP并抓取下来,直到抓完所有的IP为止。

    网页如下:

    

    1、新建一个Java项目命名为XiciCrawler并且添加依赖项目为GuozhongCrawler或者直接加入GuozhongCrawler.jar为依赖库。如果大家不知道怎么建依赖项目请看我的GuozhongCrawler开发环境搭建。

    

    2、新建一个爬虫入口Class名为StartCrawXici.java。包名自行拟定。这里命名为guozhong.crawler.impl。选中public static void main(String[]args)生成main方法。StartCrawXici.java代码如下



public class StartCrawXici {

    /**
     * @param args
     */
    public static void main(String[] args) {
        CrawlTask task = new CrawlTask("西刺抓代理IP");//给任务取个名字
        CrawlManager.prepareCrawlTask(task)
        .withThread(5)//设置下载线程数5.  默认值是5
        .withStartUrl("http://www.xici.net.co/nn/1", "utf-8")//设置入口URL 并设置页面编码
        .addPageProccess(new ParseProxyIpPage())//抓取过程中的页面解析器
        .withPipeline(new XiciPipeLine())//离线管道
        .start();//启动
    }

}


3、ParseProxyIpPage.java是处理页面的实现类。需要实现一个PageProcessor Interface。PageProcessor接口设计如下:

/**
 * 网页处理接口
 * @author Administrator
 *
 */
public interface PageProcessor {
    /**
     * 标记这个PageProcessor,应该处理哪种Request请求的页面   初始URL可以返回null
     * @return
     */
    public String getTag();
    
    /**
     * 如果需要页面动态交互JS,定义一个PageScript返回
     * @return
     */
    public PageScript getJavaScript();
    
    /**
     * 当启动代理Ip访问时需要重写此方法,返回正常网页应该带有的字符串标识。比如www.baidu.com带有“百度”
     * @return
     */
    public Pattern getNormalContain();
    
    /**
     * 处理一个页面
     * @param page
     * @param context
     * @return
     */
    public void process(OkPage page,StartContext context,List<Proccessable> result)throws Exception;
    
    /**
     * 处理错误页面
     * @param page
     * @param context
     */
    public void proccessErrorPage(Page page,StartContext context)throws Exception;
}


因为这里是处理入口URL页面。且不需要使用到JS和代理IP。所以getTag()getJavaScript()和getNormalContain()都不需要实现。本节重点解释process()方法如何使用。至于proccessErrorPage()方法实现和process大同小异。无非是处理错误的内容的html罢了。process()实现如下

    @Override
    public void process(OkPage page, StartContext context,
            List<Proccessable> result) throws Exception {
        System.out.println("该页面的URL:"+page.getRequest().getUrl());
        Document doc = Jsoup.parse(page.getContent());
        Pattern pattern = Pattern.//抽取代理IP的正则
                compile("([\\d]{1,3}\\.[\\d]{1,3}\\.[\\d]{1,3}\\.[\\d]{1,3})\\s*(\\d+)\\s*([^\\s]+)\\s*([^\\s]+)\\s*([^\\s]+)");
        Matcher matcher = pattern.matcher(doc.text());
        XiciProxy proxy = null;
        while(matcher.find()){
            proxy = new XiciProxy();
            proxy.setIp(matcher.group(1));
            proxy.setPort(matcher.group(2));
            proxy.setPosition(matcher.group(3));
            proxy.setAnonymity("高匿".equals(matcher.group(4)));
            proxy.setType(matcher.group(5));
            result.add(proxy);//加入到界面处理结果的集合中
        }
        
        //判断有没有下一页的URL。有则取得下一页的URL
        Element next_a = doc.select("a[class=next_page]").first();
        if(next_a != null){
            String next_url = next_a.attr("href");
            Request req = context.createRequest(next_url, null, 0, "utf-8");//第二个参数传Tag因为这里一直是用初始页面处理器也就是ParseProxyIpPage本身。所以可以传null
            //第三个参数是设置request的优先级只有使用PriorityRequestQueue或者DelayedPriorityRequestQueue才有效
            result.add(req);//添加到跟进URL队列
        }
    }

4XiciPipeLine是实现离线存储的管道类。需要实现一个PipeLine Interface。PipeLine接口设计如下:

public interface  Pipeline extends Serializable{
    
    /**
     * 所有的结构化数据将流向这里。在这里存储你的bean
     * @param procdata
     */
    public  void proccessData(List<Proccessable> procdata);
}

XiciPipeLine.java实现如下;

public class XiciPipeLine implements Pipeline {

    @Override
    public void proccessData(List<Proccessable> arg0) {
        if(ProccessableUtil.instanceOfClass(arg0, XiciProxy.class)){//判断集合类型是否是XiciProxy
            List<XiciProxy> list = ProccessableUtil.convert(arg0, XiciProxy.class);//转换
            for (XiciProxy proxy : list) {
                //在这里存储到你想要的任何数据库
                System.out.println("save:"+proxy);
            }
        }
    }

}

至此完成了一个花刺代理的爬虫。现在把项目图贴出来给大家看看吧


是的4个类完成一个爬虫。屌不屌!

在这里补充XiciProxy.java实体类的代码

public class XiciProxy implements Proccessable{
    /**
     *
     */
    private static final long serialVersionUID = 1L;

    private String ip;
    
    private String port;
    
    private String position;
    
    private boolean isAnonymity;
    
    private String type;

//后面getter setter忽略...

}

注:所有实体类都要实现Proccessable接口。只是为了标记作用。让引擎可以统一处理。无其他作用

0 0
原创粉丝点击