当前位置: 首页 > 工具软件 > io.spider > 使用案例 >

对webmagic总体构架的理解与代码分析——Spider篇

公良文彬
2023-12-01

不得不说webmagic是一个很优秀的爬虫框架,但是我要怎么做才能吃透它呢?我是爬虫初学者,我接下来要做的是将webmagic的代码梳理一遍,不知道我能不能将其整理好,并且灵活运用,举一反三呢。在这个过程中会遇到很多别的知识点,我会另外写博文,来总结其他我不会的东西,现在我要做的就是先分析webmagic的代码。(我自己的理解与分析会用黑色字体,而webmagic框架,黄亿华老师的东西,我会用其他颜色来标注上)

WebMagic的结构分为DownloaderPageProcessorSchedulerPipeline四大组件,并由Spider将它们彼此组织起来。这四大组件对应爬虫生命周期中的下载、处理、管理和持久化等功能。WebMagic的设计参考了Scapy,但是实现方式更Java化一些。

既然webmagic的组件由Spider组织起来,那么我就直接从Spider入手吧。由于代码太多了,在这里面复制出来太多了,http://webmagic.io/  这是webmagic的连接,里面什么都有


控制爬虫运转的引擎Spider类:

Spider类给我的感觉是webmagic框架的大集合,将webmagic框架里面所有有用的东西都整合到这一个类里面了,所以黄亿华老师在文档中才会说到WebMagic的结构分为DownloaderPageProcessorSchedulerPipeline四大组件,并由Spider将它们彼此组织起来。这四大组件对应爬虫生命周期中的下载、处理、管理和持久化等功能。而Spider则将这几个组件组织起来,让它们可以互相交互,流程化的执行,可以认为Spider是一个大的容器,它也是WebMagic逻辑的核心。即,webmagic的入口就是Spider,要想实现一个爬虫程序,首先从Spider入手,结合下面的例子会更好的理解“Spider是爬虫的入口,它封装了爬虫的创建、启动、停止、多线程等功能。”!

代码1:

public static void main(String[] args) {
    Spider.create(new GithubRepoPageProcessor())                                 //1定义专门的PageProcessor
              
            .addUrl("https://github.com/code4craft")                             //2从https://github.com/code4craft开始抓 
            
            .setScheduler(new RedisScheduler("localhost"))                       //3设置Scheduler,使用Redis来管理URL队列
              
            .addPipeline(new JsonFilePipeline("D:\\data\\webmagic"))             //4设置Pipeline,将结果以json方式保存到文件
            
            .thread(5)                                                           //5开启5个线程同时执行
            
            .run();                                                              //6启动爬虫
}
这个例子是执行爬虫的主方法,在主方法之外的该爬虫类,还应该有一个专门的方法来定制本类专门的PageProcessor。

PageProcessor负责解析页面,抽取有用信息,以及发现新的链接。WebMagic使用Jsoup作为HTML解析工具,并基于其开发了解析XPath的工具Xsoup

在这四个组件中,PageProcessor对于每个站点每个页面都不一样,是需要使用者定制的部分。

换句话来说,PageProcessor就是来解析网页的,通过PageProcessor类来解析你要抓取的网页,学习完XPath并结合我的例子就会更好的理解我说的这一句话了。

代码2:

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

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.pipeline.Pipeline;
import us.codecraft.webmagic.processor.PageProcessor;
import us.codecraft.webmagic.scheduler.PriorityScheduler;

public class MarketPriceDemo2 implements PageProcessor {
    
    private Site site = Site.me().setRetryTimes(3).setSleepTime(0);
    
    String date = getcurrdate();

    public  final String URL_LIST = "http://www\\.87050\\.com/\\w+/\\w+/.*";

    public  final String URL_POST = "/plushtml/pluprice/bjd\\d+"+ date +"\\.htm";

    @Override
    public void process(Page page) {
        if (page.getUrl().regex(URL_LIST).match()) {
            page.putField("goodsName", page.getHtml().xpath("//title/tidyText()"));
            if (page.getResultItems().get("goodsName") == null) {
                page.setSkip(true);
                System.out.println("没有匹配到相应的url");
            }
            page.putField("Data", page.getHtml().xpath("//table[@width='778' and@border='1']"));

            page.addTargetRequests(page.getHtml().links().regex(URL_POST).all());
            //addTargetRequests传入的参数是数组
            //这里面不能继续用.all()了,这里面的.all是深度和宽度爬虫的集合,我要自己写一个单独的链表只完成宽度爬虫。
        }
    }
    public  String getcurrdate() {//返回当天日期
        long now = System.currentTimeMillis();
        Date CurrTime = new Date(now);
        SimpleDateFormat dateformat = new SimpleDateFormat("yyyyMMdd");
        String rq = dateformat.format(CurrTime);
        return rq;
        }
    
    @Override
    public Site getSite() {
        return site;
    }

    public static void main(String[] args) {
        Spider.create(new MarketPriceDemo2()).setScheduler(new PriorityScheduler())
                .addUrl("http://www.87050.com/asp/jghq/index_ssjg.asp?scid=101").addPipeline(new FilePipeline("D:\\webmagic1")).thread(5).run();
    }
}

这个程序是我根据黄老师给的例子自己写的一个爬虫小程序,而我做到,通过初步接触webmagic,我只是粗略的利用到了webmagic里面的PageProcessor(通过粗略的学习了XPath,得到我想抓取网页的一个块,这应该怎么说?就是html里面的一个特定的table,这个table里面存在着我想要抓取的数据)PipeLine(将前面我想要的table保存到本地,一个我自己指定的本地地址)。后面的操作呢?人家webgiac说Pipeline可以将数据保存到数据库,但是我呢?由于我刚接触webmagic,又有任务在身,我只好自己写了一个工程,(因为我的PageProcessor抽取的是一大块table,而我想要的是table里面的一个个具体的东西,所以我又利用正则,除去没用的东西,再把有用的东西保存起来。。。)再处理一遍抓取的数据,然后把数据保存到数据库,哎~我对webmagic了解和应用真实太少了。。。我说这些是为了介绍一下我这个爬虫程序应用了webmagic里面的那些组件完成了webmagic的哪些功能。

根据代码1,可以知道我自己改出来的代码2里面的main方法基本是没有变化的,写到这里,我自己也产生了一个疑问,我写这篇博客是一个自我学习的过程,如果你也是刚刚接触webmagic的话,就请见谅了,我会把我知道的和我又疑问的写下来,然后在后面一一解决,你可以把这个博文当成是咱们相互学习的一个平台,我的QQ2715966916.


说一下刚才我提到的疑问,就是我觉得这两个代码里面的main方法里面的“Sprider.create()”括号里面传进的参数我觉得应该是对于每一个爬虫程序来说的特定的PageProcessor才对啊,为什么偏偏传入的参数确实每一个爬虫程序的对象呢?这就需要看Spider的create()方法了。这些东西我不打算写在这一篇博文里面,因为这是PageProcessor内容,我会在后面的博文中写出来。而且我还会总结一下我在学习webmagic的同时学到的其他的知识,像编程的小技巧啊,xpath啊,数据库啊什么的。


------------------------------------------------含金量-------------------------------------------------注意下面-------------------------------------

通过Webmagic框架来编写爬虫程序的话

每一个程序的主类都会有

public static void main(String[] args) {
    Spider.create(new GithubRepoPageProcessor())                                 //1定义专门的PageProcessor
              
            .addUrl("https://github.com/code4craft")                             //2从https://github.com/code4craft开始抓 
            
            .setScheduler(new RedisScheduler("localhost"))                       //3设置Scheduler,使用Redis来管理URL队列
              
            .addPipeline(new JsonFilePipeline("D:\\data\\webmagic"))             //4设置Pipeline,将结果以json方式保存到文件
            
            .thread(5)                                                           //5开启5个线程同时执行
            
            .run();                                                              //6启动爬虫
}
这就是Spider将webmagic组合起来的方便之处

这也就需要我们对magic的四个组件深入的了解,才能写出更简单实用的爬虫程序,以后如果是我们自己编写框架的话,也要参考webmagic这种编写的模式,有具体个数的组件去达到我们想要完成的任务,再将组件整合,简单运用,也就是java面向对象的思想!


至于Spider的具体代码,我个人觉得,大致的看一遍,没啥用,深入的看,,,,,记不住,哈哈。


接下来就是理解PageProcessor了,我觉得我写这篇博客让我对webmagic的思路更加清晰了。。。你也要自己写哦~







 类似资料: