Java爬虫框架WebMagic的使用总结

Posted 程序猿Paul

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java爬虫框架WebMagic的使用总结相关的知识,希望对你有一定的参考价值。

    最近,项目做一个公司新闻网站,分为PC&移动端(h5),数据来源是从HSZX与huanqiu2个网站爬取,主要使用Java编写的WebMagic作为爬虫框架,数据分为批量抓取、增量抓取,批量抓当前所有历史数据,增量需要每10分钟定时抓取一次,由于从2个网站抓取,并且频道很多,数据量大,更新频繁;开发过程中遇到很多的坑,今天腾出时间,感觉有必要做以总结。

工具说明

  • 1、WebMagic是一个简单灵活的爬虫框架。基于WebMagic,你可以快速开发出一个高效、易维护的爬虫。

    • 文档说明:http://webmagic.io/docs/zh/

  • 2、jsoup是Java的一个html解析工作,解析性能很不错。

  • 3、Jdiy一款超轻量的java极速开发框架,javaEE/javaSE环境均适用,便捷的数据库CRUD操作API。支持各大主流数据库。

使用到的技术,如下

WebMagic作为爬虫框架、httpclient作为获取网页工具、Jsoup作为分析页面定位抓取内容、ExecutorService线程池作为定时增量抓取、Jdiy作为持久层框架。

项目简介

历史抓取代码(忽略,可以查看源码)

增量抓取代码,如下((忽略,可以查看源码))

说明:增量每10分钟执行一次,每次只抓取最新一页数据,根据增量标识(上一次第一条新闻newsid), 存在相同newsid或一页爬完就终止抓取。

定时抓取,配置如下

web.xml重配置 监听

 
   
   
 
  1.   <listener>

  2.       <listener-class>com.spider.utils.AutoRun</listener-class>

  3.   </listener>

定时代码

 
   
   
 
  1.   package com.spider.utils;

  2.   /**

  3.    * 描        述:监听增量抓取Job

  4.    * 创建时间:2016-11-4

  5.    * @author Jibaole

  6.    */

  7.   public class AutoRun implements ServletContextListener {

  8.     public void contextInitialized(ServletContextEvent event) {

  9.         ScheduledExecutorService scheduExec =  Executors.newScheduledThreadPool(6);

  10.       /*

  11.        * 这里开始循环执行 HSJob()方法了

  12.        * scheduleAtFixedRate(param1, param2,param3)这个函数的三个参数的意思分别是:

  13.        *    param1:你要执行的方法;param2:延迟执行的时间,单位毫秒;param3:循环间隔时间,单位毫秒

  14.        */

  15.       scheduExec.scheduleAtFixedRate(new HSJob1(), 1*1000*60,1000*60*10,TimeUnit.MILLISECONDS);

  16.       //延迟3分钟,设置没10分钟执行一次

  17.       scheduExec.scheduleAtFixedRate(new HSJob2(), 3*1000*60,1000*60*10,TimeUnit.MILLISECONDS);

  18.       scheduExec.scheduleAtFixedRate(new HQJob1(), 5*1000*60,1000*60*10,TimeUnit.MILLISECONDS);  

  19.       scheduExec.scheduleAtFixedRate(new HQJob2(), 7*1000*60,1000*60*10,TimeUnit.MILLISECONDS);

  20.       scheduExec.scheduleAtFixedRate(new HQJob3(), 9*1000*60,1000*60*14,TimeUnit.MILLISECONDS);  

  21.       scheduExec.scheduleAtFixedRate(new HQJob4(), 11*1000*60,1000*60*10,TimeUnit.MILLISECONDS);

  22.     }

  23.     public void contextDestroyed(ServletContextEvent event) {

  24.         System.out.println("=======timer销毁==========");

  25.       //timer.cancel();

  26.     }

  27.   }

具体执行业务(举一个例子)

 
   
   
 
  1.   package com.spider.huasheng.timer;

  2.   /**

  3.    * 描        述:GJ、SH、GN、PL等频道定时任务

  4.    * 创建时间:2016-11-9

  5.    * @author Jibaole

  6.    */

  7.   public class HSJob1 implements Runnable{

  8.       @Override

  9.       public void run() {

  10.           System.out.println("======>>>开始:xxx-任务1====");

  11.     try {

  12.         runNews();

  13.           runNews1();

  14.           runNews2();

  15.        } catch (Throwable t) {

  16.            System.out.println("Error");

  17.        }

  18.          System.out.println("======xxx-任务1>>>结束!!!====");

  19.       }

  20.       /**

  21.        * 抓取-NEWS 频道列表

  22.        */

  23.       public void runNews(){

  24.           List<String> strList=new ArrayList<String>();

  25.           /**##############>>>16、国际<<<##################*/

  26.           //国际视野

  27.           strList.add("http://xxx/class/2199.html?pindao=国际");

  28.           /**##############>>>17、社会<<<##################*/

  29.           //社会

  30.           strList.add("http://xxx/class/2200.html?pindao=社会");

  31.           /**##############>>>18、国内<<<##################*/

  32.           //国内动态

  33.           strList.add("http://xxx/class/1922.html?pindao=国内");

  34.           HQNewsTaskDao.runNewsList(strList);

  35.       }

  36.       /**

  37.        * 抓取-评论 频道列表

  38.        */

  39.       public void runNews1(){

  40.           List<String> strList=new ArrayList<String>();

  41.           /**##############>>>19、评论<<<##################*/

  42.           //华声视点

  43.           strList.add("http://xxx/class/709.html?pindao=评论");

  44.           //财经观察

  45.           strList.add("http://xxx/class/2557.html?pindao=评论");

  46.           /**##############>>>20、军事<<<##################*/

  47.           //军事

  48.           strList.add("http://xxx/class/2201.html?pindao=军事");

  49.           HQNewsTaskDao.runNewsList(strList);

  50.       }

  51.       /**

  52.        * 抓取-财经 频道列表

  53.        */

  54.       public void runNews2(){

  55.           List<String> strList=new ArrayList<String>();

  56.           /**##############>>>24、财经<<<##################*/

  57.           //财讯

  58.           strList.add("http://xxx/class/2353.html?pindao=财经");

  59.           //经济观察

  60.           strList.add("http://xxx/class/2348.html?pindao=财经");

  61.           /**##############>>>30、人文<<<##################*/

  62.           //历史上的今天

  63.           strList.add("http://xxx/class/1313.html?pindao=人文");

  64.           //正史风云

  65.           strList.add("http://xxx/class/1362.html?pindao=人文");

  66.           HSTaskDao2.runNewsList(strList);

  67.       }

  68.   }

遇到的坑

增量抓取经常遇到这2个异常,如下

抓取超时:Jsoup 获取页面内容,替换为 httpclient获取,Jsoup去解析页面gzip异常(这个问题特别坑,导致历史、增量抓取数据严重缺失,线上一直有问题)

解决方案:

增加:Site..addHeader("Accept-Encoding", "/")这个是WebMagic的框架源码有点小Bug,如果没有设置Header,默认页面Accept-Encoding为:gzip

定时抓取

由ScheduledExecutorService多线程并行执行任务,替换Timer单线程串行原方式代码,如下:

 
   
   
 
  1.    package com.spider.utils;

  2.    /**

  3.     * 描    述:监听增量抓取Job

  4.     * 创建时间:2016-11-4

  5.     * @author Jibaole

  6.     */

  7.    public class AutoRun implements ServletContextListener {

  8.      //HS-job

  9.      private Timer hsTimer1 = null;

  10.      private Timer hsTimer2 = null;

  11.      //HQZX-job

  12.      private Timer hqTimer1 = null;

  13.      private Timer hqTimer2 = null;

  14.      private Timer hqTimer3 = null;

  15.      private Timer hqTimer4 = null;

  16.      public void contextInitialized(ServletContextEvent event) {

  17.        hsTimer1 = new Timer(true);

  18.        hsTimer2 = new Timer(true);

  19.        hqTimer1 = new Timer(true);

  20.        hqTimer2 = new Timer(true);

  21.        hqTimer3 = new Timer(true);

  22.        hqTimer4 = new Timer(true);

  23.        /*

  24.         * 这里开始循环执行 HSJob()方法了

  25.         * schedule(param1, param2,param3)这个函数的三个参数的意思分别是:

  26.         *    param1:你要执行的方法;param2:延迟执行的时间,单位毫秒;param3:循环间隔时间,单位毫秒

  27.         */

  28.        hsTimer1.scheduleAtFixedRate(new HSJob1(), 1*1000*60,1000*60*10);  //延迟1分钟,设置没10分钟执行一次

  29.        hsTimer2.scheduleAtFixedRate(new HSJob2(), 3*1000*60,1000*60*10);  //延迟3分钟,设置没10分钟执行一次

  30.        hqTimer1.scheduleAtFixedRate(new HQJob1(), 5*1000*60,1000*60*10);  //延迟5分钟,设置没10分钟执行一次

  31.        hqTimer2.scheduleAtFixedRate(new HQJob2(), 7*1000*60,1000*60*10);  //延迟7分钟,设置没10分钟执行一次

  32.        hqTimer3.scheduleAtFixedRate(new HQJob3(), 9*1000*60,1000*60*10);  //延迟9分钟,设置没10分钟执行一次

  33.        hqTimer4.scheduleAtFixedRate(new HQJob4(), 11*1000*60,1000*60*10);  //延迟11分钟,设置没10分钟执行一次

  34.      }

  35.      public void contextDestroyed(ServletContextEvent event) {

  36.          System.out.println("=======timer销毁==========");

  37.        //timer.cancel();

  38.      }

  39.    }

定时多个任务时,使用多线程,遇到某个线程抛异常终止任务

解决方案:在多线程run()方法里面,增加try{}catch{}

通过HttpClient定时获取页面内容时,页面缓存,抓不到最新内容

一些方面的处理

页面抓取规则调整

先抓列表,在抓内容;改为 抓取列表的同时,需要获取内容详情

保存数据方式作调整

先抓取标题等概要信息,保存数据库,然后,更新内容信息,根据业务需求再删除一些非来源文章(版权问题);改为:直接控制来源,得到完整数据,再做批量保存;

页面有一个不想要的内容,处理方法

注释、JS代码、移除无用标签块

>>>划重点



关注公众号(长按识别二维码)


以上是关于Java爬虫框架WebMagic的使用总结的主要内容,如果未能解决你的问题,请参考以下文章

爬虫学习之webmagic源码剖析

WebMagic爬虫Demo

JAVA 爬虫框架webmagic

程序源代码开源的Java垂直爬虫框架

签名图片一键批量生成 使用Java的Webmagic爬虫实现

java爬虫框架webmagic学习