WebCollector 教程——MatchUrl 和 MatchType

MatchUrl和MatchType是WebCollector新特性中的trick,可以大大提升爬虫开发的效率(尤其是MatchType)。

MatchUrl

在早期的用WebCollector开发的爬虫中,下面这种代码很常见:

 @Override
    public void visit(Page page, CrawlDatums next) {
        //如果是博客内容页(根据URL正则判断)
        if(Pattern.matches(page.matchUrl("http://blog.csdn.net/.*/article/details/.*", page.url()){
          //抽取代码
        }
    }

在新版本的WebCollector中,可以直接用page.matchUrl(String regex)来判断当前页面URL是否与正则匹配

 @Override
    public void visit(Page page, CrawlDatums next) {
        //如果是博客内容页(根据URL正则判断)
        if (page.matchUrl("http://blog.csdn.net/.*/article/details/.*")) {
          //抽取代码
        }
    }

MatchType

阅读此教程之前建议先学习WebCollector教程——MetaData

MetaData特性使得WebCollector在注入或探测链接时为其添加附属信息,提升开发效率,在附属信息中,页面类型信息是一个及其重要的信息。这里说的页面类型不是Http协议中的Content-Type信息,而是用户自定义的用于区分不同解析方案的信息,例如在采集豆瓣图书时,会遇到标签页、列表页和图书详情页,只有知道页面的类型,才可以选取对应的抽取及新链接探测方案。

大多数其它的Java爬虫是通过网页URL的正则匹配来判断页面类型的,但正则匹配并不能解决所有的问题,对于一些网站,可能不同类型的页面享有相同的URL模式。抛开URL正则,换个角度思考。当我们设计豆瓣图书爬虫时(手动解析),有如下的关系:

A.注入种子页(标签页)
B.从标签页中解析获得列表页的URL
C.从列表页中解析获得内容页的URL

与其根据URL正则获得页面的类型,为何不直接在上述A(注入)、B(探测)、C(探测)时直接将页面类型标记在链接(CrawlDatum)中呢?在新版本WebCollector中,可通过如下几种形式为链接(CrawlDatum)添加类型信息。

CrawlDatum datum = new CrawlDatum("网页URL", "页面类型");
CrawlDatum datum = new CrawlDatum("网页URL").type("页面类型");
//在Crawler中注入时
addSeed("网页URL", "页面类型");
//在visit中往next中添加探测到的链接时
next.add("网页URL", "页面类型");

在解析时,可直接通过page.matchType("页面类型")来判断网页是否符合指定的页面类型。

注意:页面类型信息本质是MetaData中一个key为”type”的附属信息,建议开发者在使用MetaData特性时不要将自定义的附属信息的key设置为”type”,以免发生冲突。

下面是一个完整的利用MatchType特性抓取豆瓣图书的代码:

import cn.edu.hfut.dmic.webcollector.model.CrawlDatums;
import cn.edu.hfut.dmic.webcollector.model.Page;
import cn.edu.hfut.dmic.webcollector.plugin.ram.RamCrawler;


/**
 * 
 * WebCollector 2.40新特性 page.matchType
 * 在添加CrawlDatum时(添加种子、或在抓取时向next中添加任务),
 * 可以为CrawlDatum设置type信息
 * 
 * type的本质也是meta信息,为CrawlDatum的附加信息
 * 在添加种子或向next中添加任务时,设置type信息可以简化爬虫的开发
 * 
 * 例如在处理列表页时,爬虫解析出内容页的链接,在将内容页链接作为后续任务
 * 将next中添加时,可设置其type信息为content(可自定义),在后续抓取中,
 * 通过page.matchType("content")就可判断正在解析的页面是否为内容页
 * 
 * 设置type的方法主要有3种:
 * 1)添加种子时,addSeed(url,type)
 * 2)向next中添加后续任务时:next.add(url,type)或next.add(links,type)
 * 3)在定义CrawlDatum时:crawlDatum.type(type)
 *
 * @author hu
 */
public class DemoTypeCrawler extends RamCrawler {

    /*
        该教程是DemoMetaCrawler的简化版

        该Demo爬虫需要应对豆瓣图书的三种页面:
        1)标签页(taglist,包含图书列表页的入口链接)
        2)列表页(booklist,包含图书详情页的入口链接)
        3)图书详情页(content)

        另一种常用的遍历方法可参考TutorialCrawler
     */
    @Override
    public void visit(Page page, CrawlDatums next) {

        if(page.matchType("taglist")){
            //如果是列表页,抽取内容页链接
            //将内容页链接的type设置为content,并添加到后续任务中
             next.add(page.links("table.tagCol td>a"),"booklist");
        }else if(page.matchType("booklist")){
            next.add(page.links("div.info>h2>a"),"content");
        }else if(page.matchType("content")){
            //处理内容页,抽取书名和豆瓣评分
            String title=page.select("h1>span").first().text();
            String score=page.select("strong.ll.rating_num").first().text();
            System.out.println("title:"+title+"\tscore:"+score);
        }

    }

    public static void main(String[] args) throws Exception {
        DemoTypeCrawler crawler = new DemoTypeCrawler();
        crawler.addSeed("https://book.douban.com/tag/","taglist");


        /*可以设置每个线程visit的间隔,这里是毫秒*/
        //crawler.setVisitInterval(1000);
        /*可以设置http请求重试的间隔,这里是毫秒*/
        //crawler.setRetryInterval(1000);
        crawler.setThreads(30);
        crawler.start(3);
    }

}

You may also like...

发表评论

电子邮件地址不会被公开。 必填项已用*标注

推荐文章
加QQ群下载完整Eclipse项目

WebCollector网络爬虫:250108697(已满)

WebCollector网络爬虫2群:345054141

热门