springBoot接入webMagic实现页面上控制断点启动

参考文档地址

webmagic中文文档:http://webmagic.io/docs/zh/

一:引入依赖

pom.xml中添加

   

        <properties>

       <webmagic.version>0.7.3webmagic.version>

    properties>

    <dependency>

           <groupId>us.codecraftgroupId>

           <artifactId>webmagic-coreartifactId>

           <version>${webmagic.version}version>

           <exclusions>

              <exclusion>

                  <groupId>org.slf4jgroupId>

                  <artifactId>slf4j-log4j12artifactId>

              exclusion>

           exclusions>

       dependency>

       <dependency>

           <groupId>us.codecraftgroupId>

           <artifactId>webmagic-extensionartifactId>

           <version>${webmagic.version}version>

       dependency>

       <dependency>

           <groupId>us.codecraftgroupId>

           <artifactId>webmagic-saxonartifactId>

           <version>${webmagic.version}version>

       dependency>

       <dependency>

           <groupId>us.codecraftgroupId>

           <artifactId>webmagic-seleniumartifactId>

           <version>${webmagic.version}version>

       dependency>

   

二:实现PageProcessor

/**

 * 解析器,基础处理类

 *

 * @author zhangjianzhong

 *

 */

public class BasePageAdapters implements PageProcessor {

    private Site site;

    protected CrwlerTaskVO task;// 包含采集的规则

    public static final String KEY_PARSER = "parser";

 

    public BasePageAdapters(Site site, CrwlerTaskVO task) {

       this.site = site;

       this.task = task;

       this.site = Site.me();

       // 设置重试次数

       this.site.setRetryTimes(3);

       // 抓取间隔时间

       this.site.setSleepTime(5000);

       this.site.setTimeOut(5000);

       this.site.setCycleRetryTimes(10);

    }

 

    @Override

    public void process(Page page) {

       // TODO Auto-generated method stub

       try {

           Request request = page.getRequest();

           // 获取当前页面的数据信息,这个信息会贯穿整个数据请求串

 

           ParserVO parser = (ParserVO) request.getExtra(KEY_PARSER);// 获取解析器

           // 如果也没有传递进来解析器

           if (parser == null) {

              List parsers = this.task.getParsers();

              for (ParserVO p : parsers) {

                  // 如果能找到解析器,那么处理该请求

                  this.analysis(page, p);

              }

           } else {// 如果有解析器跟着解析器处理

              // 因为没有infoID所有认为这是一条新的信息

              this.analysis(page, parser);

           }

       } catch (Exception e) {

           // TODO: handle exception

       }

 

    }

 

 

    private void analysis(Page page, ParserVO parser) {

 

       Html html = page.getHtml();

       ParserEntity pe = parser.getParser();

       // 获取数据区域

       Selectable area = html.$(pe.getArea());// 数据所在区域

       Selectable group = null;

       if (pe.getItemSelector() != null) {

           group = area.$(pe.getItemSelector());// 数据项的选择器

           // 说明有列表项目

       } else {

           group = area;

       }

       List nodes = group.nodes();//拿到采集规则解析之后的值

    }

    @Override

    public Site getSite() {

       // TODO Auto-generated method stub

       return this.site;

    }

}

三:启动采集

@Service

public class PageReptilesService {

    /**

     * 线程数量

     */

    private int threadNum = 1;

    private String configPath;

    private String chromedriverPath;

 

    public PageReptilesService() {

       String basePath = System.getProperty("user.dir");

       this.configPath = basePath + File.separator + "configs/selenuim_config.ini";

       System.setProperty("selenuim_config", this.configPath);

 

       String drivers = basePath + File.separator + "drivers";

       this.chromedriverPath = drivers + File.separator + "chromedriver.exe";

    }

 

    /**

     * 启动采集

     *

     * @param rule   规则

     * @param parser 解析器

     * @author JYInfo

     */

    public void startReptile(RuleEntity rule, BasePageAdapters parser) {

 

       Spider spider = Spider.create(parser);

 

       // 比如从"https://www.baidu.com"开始抓

//     this.seedUrl(spider, rule);

 

       spider.addUrl("");

       List spiderListeners = new ArrayList();

       // 根据访问方式类型写入不同的监听器

       BasePageListener basePageListener = new BasePageListener();

       spiderListeners.add(basePageListener);

 

       SeleniumDownloader seleniumDownloader = new SeleniumDownloader(this.chromedriverPath);

       if (rule.getSleepTime() != null) {// 设置等待页面初始换时间

           seleniumDownloader.setSleepTime(rule.getSleepTime());

           // 例如天气页面是通过js渲染,需等待1-2s.

       }

       spider.setDownloader(seleniumDownloader);

       SeleniumPageListener spListener = new SeleniumPageListener(seleniumDownloader);

       spiderListeners.add(spListener);

 

       // 写入监听器

       spider.setSpiderListeners(spiderListeners);

       //

       // 开启5个线程抓取

       spider.thread(threadNum);

       spider.run();

    }

}

四:实现页面启动停止

  1. 修改SpiderMonitor

private Map spiderStatuses = new HashMap();

    public synchronized MySpiderMonitor register(Spider...  spiderStatuses.put(spider.getUUID(),spiderStatusMBean);)

         

 

 

  1. SpiderStatus添加get方法

public Spider getSpider()

    {

        return this.spider;

    }

  1. 注册spider方法到spiderMonitor

 MySpiderMonitor spiderMonitor = MySpiderMonitor.instance();

spider.setUUID(uuID);

    spiderMonitor.register(spider);

 

  1. 实现启动和停止

//获取到注册的spiderStatus

MySpiderMonitor spiderMonitor = MySpiderMonitor.instance();

Map spiderStatuses = spiderMonitor.getSpiderStatuses();

MySpiderStatus spiderStatus = spiderStatuses.get(uuID);

//既然有了spiderStatus就可以在页面上控制开、关和查看过程信息了。

1spiderStatus.getSpider().run();//掉它启动

2spiderStatus.stop();//掉它关闭

3//获取启动过程中详细信息

    spiderStatus.getTotalPageCount();

    spiderStatus.getStatus();

    …

   

 

 

  1. 实现断点启动功能

//通过反射拿到队列中没有执行完的请求信息

QueueScheduler b = ((QueueScheduler) spiderStatus.getSpider().getScheduler());

           Class classes = b.getClass();

           Field[] fs = classes.getDeclaredFields();

           for (Field f : fs) {

               f.setAccessible(true);

               @SuppressWarnings("unchecked")

               BlockingQueue queue = (BlockingQueue) f.get(b);

               if (queue.size() > 0) {

                  Set sss = new HashSet();

                  queue.forEach(qu -> {

                      sss.add(qu);//放到set

                  });

                  redisUtil.set(ruleId, sss);//存入redis或序列化之后写入数据库或者本地文件都可以

               }

           }

           // 停止

           spiderStatus.stop();

//再次启动的时候把这些请求add进去就ok

 

以上修改实现了页面端直接调用启动、关闭爬虫任务。

你可能感兴趣的:(java)