WebCollector 自动探测 URL 地址

  • 本文以 《WebCollector 简介与 快速入门》中建的项目为基础继续深入学习 webCollector 的 自动 URL 地址探测
  • 目的是深入理解 WebCollector 官网 中的第一个例子 “ DemoAutoNewsCrawler  ”,本文会用详细的示例进行说明。

自动探测 URL 

  • 这是 BreadthCrawler (广度爬取)类的源码说明,自己的类会继承它然后进行网站爬取
  • 是否进行自动探测 URL 取决于 参数 autoPase;默认为true,自动探测 URL 必须自己指定正则匹配,否则是无效的;手动探测时 autoPase 设置为 false 即可,如果 autoPase 为 true ,但是不指定 正则匹配时也是不影响的,建议设置为 false。
  • 提示:webCollector 爬取步骤:
  1. 注入种子(即要被爬取的网址)
  2. 添加 URL 正则规则
  3. 启动爬取进行爬取(会根据 url 正则规则获取目标页面中符合规则的所有链接地址,包括 js、css、a标签的href、img标签的src、video和audio的src 等等,如果这些链接使用的是相对地址,则webCollector会自动解析为绝对地址)
package cn.edu.hfut.dmic.webcollector.plugin.rocks;

import cn.edu.hfut.dmic.webcollector.crawler.AutoParseCrawler;

/**
 * cn.edu.hfut.dmic.webcollector.plugin.rocks.BreadthCrawler是基于RocksDB的插件,于2.72版重新设计
 * BreadthCrawler可以设置正则规律,让遍历器自动根据URL的正则遍历网站,可以关闭这个功能,自定义遍历
 * 如果autoParse设置为true,遍历器会自动解析页面中符合正则的链接,加入后续爬取任务,否则不自动解析链接。
 * 注意,爬虫会保证爬取任务的唯一性,也就是会自动根据CrawlDatum的key进行去重,默认情况下key就是URL,
 * 所以用户在编写爬虫时完全不必考虑生成重复URL的问题。
 * 断点爬取中,爬虫仍然会保证爬取任务的唯一性。
 *
 * @author hu
 */
public abstract class BreadthCrawler extends AutoParseCrawler {

      /**
       * 构造一个基于RocksDB的爬虫
       * RocksDB文件夹为crawlPath,crawlPath中维护了历史URL等信息
       * 不同任务不要使用相同的crawlPath
       * 两个使用相同crawlPath的爬虫并行爬取会产生错误
       * 
       * @param crawlPath RocksDB使用的文件夹
       * @param autoParse 是否根据设置的正则自动探测新URL
       */
      public BreadthCrawler(String crawlPath, boolean autoParse) {
        super(autoParse);
        this.dbManager=new RocksDBManager(crawlPath);
    }
    
}

人大代表动态

需求分析

  • 如下图所示是一个微信公众号其中的一个菜单用PC上的浏览器打开后的结构,需求是爬取这些文章列表中的文章内容(包括文章标题、发布时间、正文、以及正文中的图片),这里以下面的 “ 市人大 ” 中文章为例

  • 如下所示为 “ 市人大 ” 文章列表网页中点击右键 “ 查看网页源代码 ” 的情况,它的 文章列表的超链接地址使用的相对地址
  • 自动探测时 webCollector 会自动处理这些 URL 地址
            <section id="haveResult" class="mheight">
            <ul class="list list_mobile">
               
                        <li><a class="cty-cont" href="CityBasicDetail.aspx?u=WChl82HhwM1kiaMEsCXPSihbvFWLiJESlUzxTojjETdXZqzV3Iikp4HqIPQuq57e&ct=1" target="_self">教科文卫工委组织人大代表视察 医疗条例部分条款实施情况</a><div class="time">2018-07-17</div></li>                        
                    
                        <li><a class="cty-cont" href="CityBasicDetail.aspx?u=WChl82HhwM1kiaMEsCXPSgSrRXexaYHe413m40QEaozjL%2fJs1%2bwj%2bbc2BfwHin%2bz&ct=1" target="_self">市检察院召开人大代表建议办理情况答复会 12名代表听取答复</a><div class="time">2018-05-31</div></li>                        
                    
                        <li><a class="cty-cont" href="CityBasicDetail.aspx?u=WChl82HhwM1kiaMEsCXPSgBv17P37Fpn%2b7qoKWUBzfN1OdawVbtNn8kQDD3YRUob&ct=1" target="_self">外事侨务工委召开市六届人大六次会议代表建议督办会议</a><div class="time">2018-05-16</div></li>                        
                    
                        <li><a class="cty-cont" href="CityBasicDetail.aspx?u=WChl82HhwM1kiaMEsCXPSmHqDtMkDoXFkgXvcJIdsro9tz%2fpvYa7fXuvhw9UkDTo&ct=1" target="_self">蒋宇扬率队视察我市职业病防治情况</a><div class="time">2018-05-13</div></li>                        
                    
                        <li><a class="cty-cont" href="CityBasicDetail.aspx?u=WChl82HhwM1kiaMEsCXPSg9PncbadG4W44pAETNu2NmdQfD2wTqpEhZDWStT25Si&ct=1" target="_self">教科文卫工委组织人大代表视察 光明新区文化场馆设施建设情况</a><div class="time">2018-05-09</div></li>                        
                    
                        <li><a class="cty-cont" href="CityBasicDetail.aspx?u=WChl82HhwM1kiaMEsCXPSolhCJTzj%2f7CxiWQXK8XBe4yrm7QDflVypC2Q7AZu4hg&ct=1" target="_self">教科文卫工委组织人大代表视察坪山区体育场馆设施建设情况</a><div class="time">2018-04-24</div></li>                        
                    
            </ul>
            <div class="clear"></div>
            <div id="ucAjaxPage_divPage">
  • 如下所示为 “ 市人大 ” 文章列表中具体的文章内容结构,需求是爬取文章的标题、发布时间、正文、以及正文中的图片地址

  • 如下所示为具体文章网页的结构,文章正文中的图片地址使用的是绝对地址
<html>
<head>
    <title>代表动态</title>
    <meta charset="utf-8" name="viewport" content="width=device-width,initial-scale=1,user-scalable=1,maximum-scale=2" />
    <link href="../css/jquery.mobile-1.2.0.min.css" rel="Stylesheet" type="text/css" />
    <link href="../css/public.css" rel="Stylesheet" type="text/css" />
    <link href="../css/list.css" rel="Stylesheet" type="text/css" />
    <link href="../css/new-style.css" rel="Stylesheet" type="text/css" />
    <script type="text/javascript" src="../skin/jquery-1.5.1.js"></script>
    <script type="text/javascript" src="../skin/jquerymobile1.2.0.js"></script>
    <script type="text/javascript" src="../skin/index.js"></script>
</head>
<body class="bgfMobile">
    <div data-role="page">
        <div id="haveResult" class="mheight detail">
            <div class="d_tit" style="color: #084aa5;">
                外事侨务工委召开市六届人大六次会议代表建议督办会议</div>
            <div class="d_more">
                <cite id="showTime">
                    发布日期:2018-05-16</cite></div>
            <div class="d_con dd_con">
                <p>
</p>
<p style="line-height: 150%; text-indent: 2em;"><span style="line-height: 150%; font-size: 16px; font-family: 宋体,SimSun;">5月15日下午,市人大常委会外事侨务工委召开市六届人大六次会议代表建议督办会,对我委跟进的《关于深圳湾口岸实行24小时通关的建议》(第20180052号,陈成就等代表提出)、《关于解决口岸查验单位辅助人员的建议》(第20180572号,陈宏军代表提出)等5件建议进行了督办。会议充分肯定了市政府和相关部门在办理代表建议工作中作出的努力。会议要求,政府各承办单位要克服困难,为市民提供优质通关服务,助推深圳经济社会发展。此次通过督办会,让代表与承办单位面对面、零距离交流沟通旨在建立起良性的代表建议办理督办机制,相信在市人大常委会的监督下,在市政府各部门的努力下,代表提出的建议一定能得到妥善的解决和落实。(外事侨务工委供稿)
</span></p>
<p style="text-align:center"><img src="http://img.szrd.gov.cn/upload/image/20180516/6366206771816542821815706.JPG" title="外事侨务工委召开市六届人大六次会议代表建议督办会议.JPG" alt="外事侨务工委召开市六届人大六次会议代表建议督办会议.JPG" height="600" width="900"></p>
<p style="text-indent:43px;line-height:150%"></p>
<br>
<p></p>
            </div>
        </div>
        
        <div class="clear">
        </div>
    </div>
</body>
</html>

代码爬取

  • 以下是爬取的核心代码
package com.lct.webCollector;

import cn.edu.hfut.dmic.webcollector.model.CrawlDatums;
import cn.edu.hfut.dmic.webcollector.model.Page;
import cn.edu.hfut.dmic.webcollector.plugin.rocks.BreadthCrawler;
import com.lct.util.SystemUtils;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

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

/**
 * Crawling news from github news
 * 自动 弹出 URL 地址,继承 BreadthCrawler(广度爬虫)
 * <p/>
 * cn.edu.hfut.dmic.webcollector.plugin.rocks.BreadthCrawler是基于RocksDB的插件,于2.72版重新设计
 * BreadthCrawler可以设置正则规律,让遍历器自动根据URL的正则遍历网站,可以关闭这个功能,自定义遍历
 * 如果autoParse设置为true,遍历器会自动解析页面中符合正则的链接,加入后续爬取任务,否则不自动解析链接。
 * 注意,爬虫会保证爬取任务的唯一性,也就是会自动根据CrawlDatum的key进行去重,默认情况下key就是URL,
 * 所以用户在编写爬虫时完全不必考虑生成重复URL的问题。
 * 断点爬取中,爬虫仍然会保证爬取任务的唯一性。
 *
 * @author hu
 */
public class MyAutoNewsCrawler extends BreadthCrawler {
    /**
     * 构造一个基于 RocksDB 的爬虫
     * RocksDB文件夹为crawlPath,crawlPath中维护了历史URL等信息
     * 不同任务不要使用相同的crawlPath
     * 两个使用相同crawlPath的爬虫并行爬取会产生错误
     *
     * @param crawlPath RocksDB使用的文件夹
     * @param autoParse 是否根据设置的正则自动探测新URL ,默认为 true
     */
    public MyAutoNewsCrawler(String crawlPath, boolean autoParse) {
        super(crawlPath, autoParse);

        /**设置爬取的网站地址
         * addSeed 表示添加种子
         * 种子链接会在爬虫启动之前加入到抓取信息中并标记为未抓取状态.这个过程称为注入
         * 放入 新闻列表 页面网址
         * */
        this.addSeed("http://md.sqllz.org/wx/CityBasic.aspx?ct=1");

        /**
         * 添加一个 URL 正则规则 正则规则有两种,正正则和反正则
         * URL 符合正则规则需要满足两个条件: 1.至少能匹配一条正正则 2.不能和任何反正则匹配
         * 正正则示例:+abc.*efg 是一条正正则,正则的内容为 abc.*efg ,起始加号表示正正则
         * 反正则示例:-abc.*efg 是一条反正则,正则的内容为 abc.*efg ,起始减号表示反正则
         * (注1)如果一个规则的起始字符不为加号且不为减号,则该正则为正正则,正则的内容为自身,如 a.*c 是一条正正则,正则的内容为 a.*c
         * (注2) 正则的内容与平时 js 与 java 中使用的正则写法是一样的,如 "."表示任意字符、"*"表示0次或多次、[0-9]{4} 表示连续4个数字
         * */
        this.addRegex("http://md.sqllz.org/wx/CityBasicDetail.aspx?.*");

        /**
         * 过滤 jpg|png|gif 等图片地址 时:
         * this.addRegex("-.*\\.(jpg|png|gif).*");
         */

        /**
         * 过滤 链接值含 "#" 的地址
         */
        this.addRegex("-.*#.*");

        /**设置线程数*/
        setThreads(10);
        getConf().setTopN(100);

        /**
         * 是否进行断电爬取,默认为 false
         * setResumable(true);
         */
    }

    /**
     * 必须重写 visit 方法,作用是:
     * 在整个抓取过程中,只要抓到符合要求的页面,webCollector 就会回调该方法,并传入一个包含了页面所有信息的 page 对象
     *
     * @param page :Page是爬取过程中,内存中保存网页爬取信息的一个容器,Page只在内存中存放,用于保存一些网页信息,方便用户进行自定义网页解析之类的操作。
     * @param next :可以手工将希望后续采集的任务加到next中(会参与自动去重),即如果需要后续再次进行爬取的,则可以添加进去
     */
    @Override
    public void visit(Page page, CrawlDatums next) {
        String url = page.url();
        /**
         * 判断当前 Page 的 URL 是否和输入正则匹配
         * 如果此页面地址 确实是要求爬取网址,则进行取值
         */
        if (page.matchUrl("http://md.sqllz.org/wx/CityBasicDetail.aspx?.*")) {

            /**
             * 通过 选择器 获取页面 标题以及 正文内容、时间
             * 这些选择器语法就是 Jsoup,类似于 JQuery 的选择器,非常方便
             * 可以参考 Jsoup 官网:https://jsoup.org/cookbook/extracting-data/selector-syntax
             * select:返回的是 Elements
             * selectText:是直接获取元素的文本内容,只要是此元素下的,无论嵌套多少层在下面,都会进行获取
             * "." 是 样式选择器、"#"是 id 选择器
             * <div class="d_con dd_con"><p>...</p></div>:当样式有多个时,选择器使用"."号连接
             * 因为 "空格" 本身就是一个层级选择器,"A B" 表示查找A元素下的所有B元素
             * */
            String title = page.select("div.d_tit").first().text();
            String content = page.selectText("div.d_con.dd_con");
            String dateStr = page.selectText("cite#showTime");

            /**
             * 获取正文中的所有图片元素,不存在时 Elements 大小为 0
             */
            Elements imgElements = page.select("div.d_con.dd_con img");

            System.out.println("开始爬取 URL::" + url);
            System.out.println("title::" + title);
            System.out.println("content::" + content);

            for (Element imgElement : imgElements) {
                System.out.println("文章图片:" + imgElement.attr("src"));
            }

            /**
             * 自己封装的一个系统工具类,用于解析文本中日期
             */
            Date date = SystemUtils.parseDateStr(dateStr);
            if (date == null) {
                System.out.println("发布时间:" + date);
            } else {
                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                System.out.println("发布时间:" + dateFormat.format(date));
            }
        }
    }

    public static void main(String[] args) throws Exception {
        /**
         * MyAutoNewsCrawler 构造器中会进行 数据初始化,这两个参数接着会传给父类
         * super(crawlPath, autoParse);
         * crawlPath:表示设置保存爬取记录的文件夹,本例运行之后会在应用根目录下生成一个 "crawl" 目录存放爬取信息
         * autoParse:表示进行 URL自动探测
         * */
        MyAutoNewsCrawler crawler = new MyAutoNewsCrawler("crawl", true);
        /**
         * 启动爬虫,爬取的深度为2层
         * 添加的第一层种子链接,为第1层
         */
        crawler.start(2);
    }
}
  • 上面代码中爬取的日期文本需要解析,用到的工具类方法如下
package com.lct.util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by Administrator on 2018/8/15 0015.
 * 系统工具类
 */
public class SystemUtils {
    /**
     * 解析日期字符串,如:"发布日期:2018-05-31"、"2018-08-13 07:44 来源: 经济日报"、 "2018年08月15日 07:13:30 参考消息"	等等
     *
     * @param dateStr 返回解析好的 日期对象,解析失败时,返回 null
     * @return
     */
    public static Date parseDateStr(String dateStr) {
        if (dateStr == null || "".equals(dateStr)) {
            return null;
        }
        /**
         * dateRegexYMDHMS:针对 年月日 时分秒
         * dateRegexYMDHM:针对 年月日 时分
         * dateRegexYMDH:针对 年月日 时
         * dateRegexYMDH:针对 年月日
         */
        String dateRegexYMDHMS = "([1-2][0-9]{3})[^0-9]{1,5}?([0-1]?[0-9])[^0-9]{1,5}?([0-9]{1,2})[^0-9]{1,5}?([0-2]?[1-9])[^0-9]{1,5}?([0-9]{1,2})[^0-9]{1,5}?([0-9]{1,2})";
        String dateRegexYMDHM = "([1-2][0-9]{3})[^0-9]{1,5}?([0-1]?[0-9])[^0-9]{1,5}?([0-9]{1,2})[^0-9]{1,5}?([0-2]?[1-9])[^0-9]{1,5}?([0-9]{1,2})";
        String dateRegexYMDH = "([1-2][0-9]{3})[^0-9]{1,5}?([0-1]?[0-9])[^0-9]{1,5}?([0-9]{1,2})[^0-9]{1,5}?([0-2]?[1-9])";
        String dateRegexYMD = "([1-2][0-9]{3})[^0-9]{1,5}?([0-1]?[0-9])[^0-9]{1,5}?([0-9]{1,2})";

        Pattern pattern = Pattern.compile(dateRegexYMDHMS);
        Matcher matcher = pattern.matcher(dateStr);

        StringBuffer dateSourceBf = new StringBuffer();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        try {
            if (matcher.find()) {
                /**年月日 时分秒*/
                dateSourceBf.append(matcher.group(1)).append("-");
                dateSourceBf.append(matcher.group(2).length() == 1 ? "0" + matcher.group(2) : matcher.group(2)).append("-");
                dateSourceBf.append(matcher.group(3).length() == 1 ? "0" + matcher.group(3) : matcher.group(3)).append(" ");
                dateSourceBf.append(matcher.group(4).length() == 1 ? "0" + matcher.group(4) : matcher.group(4)).append(":");
                dateSourceBf.append(matcher.group(5).length() == 1 ? "0" + matcher.group(5) : matcher.group(5)).append(":");
                dateSourceBf.append(matcher.group(6).length() == 1 ? "0" + matcher.group(6) : matcher.group(6));
                Date date = simpleDateFormat.parse(dateSourceBf.toString());
                return date;
            }
            if (dateSourceBf.length() <= 1) {
                /**年月日 时分*/
                pattern = Pattern.compile(dateRegexYMDHM);
                matcher = pattern.matcher(dateStr);
                if (matcher.find()) {
                    dateSourceBf.append(matcher.group(1)).append("-");
                    dateSourceBf.append(matcher.group(2).length() == 1 ? "0" + matcher.group(2) : matcher.group(2)).append("-");
                    dateSourceBf.append(matcher.group(3).length() == 1 ? "0" + matcher.group(3) : matcher.group(3)).append(" ");
                    dateSourceBf.append(matcher.group(4).length() == 1 ? "0" + matcher.group(4) : matcher.group(4)).append(":");
                    dateSourceBf.append(matcher.group(5).length() == 1 ? "0" + matcher.group(5) : matcher.group(5)).append(":00");
                    Date date = simpleDateFormat.parse(dateSourceBf.toString());
                    return date;
                }
            }
            if (dateSourceBf.length() <= 1) {
                /**年月日 时*/
                pattern = Pattern.compile(dateRegexYMDH);
                matcher = pattern.matcher(dateStr);
                if (matcher.find()) {
                    dateSourceBf.append(matcher.group(1)).append("-");
                    dateSourceBf.append(matcher.group(2).length() == 1 ? "0" + matcher.group(2) : matcher.group(2)).append("-");
                    dateSourceBf.append(matcher.group(3).length() == 1 ? "0" + matcher.group(3) : matcher.group(3)).append(" ");
                    dateSourceBf.append(matcher.group(4).length() == 1 ? "0" + matcher.group(4) : matcher.group(4)).append(":00:00");
                    Date date = simpleDateFormat.parse(dateSourceBf.toString());
                    return date;
                }
            }
            if (dateSourceBf.length() <= 1) {
                /**年月日*/
                pattern = Pattern.compile(dateRegexYMD);
                matcher = pattern.matcher(dateStr);
                if (matcher.find()) {
                    dateSourceBf.append(matcher.group(1)).append("-");
                    dateSourceBf.append(matcher.group(2).length() == 1 ? "0" + matcher.group(2) : matcher.group(2)).append("-");
                    dateSourceBf.append(matcher.group(3).length() == 1 ? "0" + matcher.group(3) : matcher.group(3)).append(" 00:00:00");
                    Date date = simpleDateFormat.parse(dateSourceBf.toString());
                    return date;
                }
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }
}

运行结果

  • 爬取完成成功
.............
2018-08-15 16:05:27 INFO cn.edu.hfut.dmic.webcollector.fetcher.Fetcher  - -activeThreads=6, spinWaiting=0, fetchQueue.size=0
开始爬取 URL::http://md.sqllz.org/wx/CityBasicDetail.aspx?u=WChl82HhwM1kiaMEsCXPSg9PncbadG4W44pAETNu2NmdQfD2wTqpEhZDWStT25Si&ct=1
title::教科文卫工委组织人大代表视察 光明新区文化场馆设施建设情况
content::5月3日下午,教科文卫工委组织部分市区两级人大代表,由工委原丽萍副主任带队实地视察了光明新区文化馆和图书馆并召开座谈会,新区党工委(管委会)综合办和文体局负责同志就新区近年来的文体场馆设施规划建设情况进行了汇报。 (教科文卫工委供稿)
文章图片:http://img.szrd.gov.cn/upload/image/20180509/6366148434690345285474538.jpg
文章图片:http://img.szrd.gov.cn/upload/image/20180509/6366148434360657439400886.jpg
文章图片:http://img.szrd.gov.cn/upload/image/20180509/6366148434118860413227885.jpg
开始爬取 URL::http://md.sqllz.org/wx/CityBasicDetail.aspx?u=WChl82HhwM1kiaMEsCXPSihbvFWLiJESlUzxTojjETdXZqzV3Iikp4HqIPQuq57e&ct=1
title::教科文卫工委组织人大代表视察 医疗条例部分条款实施情况
content::2018年7月12日下午,市人大常委会教科文卫工委组织部分市人大代表,由教科文卫工委主任王薇带队,视察医疗条例部分条款实施情况。市人大代表实地视察了市中医院,听取市卫计委关于医疗条例部分条款实施情况的汇报,并提出意见建议。市卫生计生委副巡视员张英姬陪同视察并参加座谈会。(教科文卫工委供稿)
文章图片:http://img.szrd.gov.cn/upload/image/20180717/6366743978345479345189903.jpg
文章图片:http://img.szrd.gov.cn/upload/image/20180717/6366743978361788266475517.jpg
文章图片:http://img.szrd.gov.cn/upload/image/20180717/6366743978483174662176640.jpg
开始爬取 URL::http://md.sqllz.org/wx/CityBasicDetail.aspx?u=WChl82HhwM1kiaMEsCXPSolhCJTzj%2f7CxiWQXK8XBe4yrm7QDflVypC2Q7AZu4hg&ct=1
title::教科文卫工委组织人大代表视察坪山区体育场馆设施建设情况
content::4月16日,市人大常委会教科文卫委组织部分市人大代表,由工委王薇主任、原丽萍副主任带队,实地视察坪山区体育中心体育馆和深圳(坪山)国际网球中心,并就坪山区文化体育设施建设情况召开座谈会,听取市、区人大代表意见建议。坪山区人大常委会主任孙新华、副主任蒋道超以及区人大常委会教科文卫工委、区委宣传部(区文体旅游局)等部门负责同志参加了视察和座谈会。省略300字....
文章图片:http://img.szrd.gov.cn/upload/image/20180424/6366017207610077456185956.jpg
文章图片:http://img.szrd.gov.cn/upload/image/20180424/6366017207656659413113962.jpg
文章图片:http://img.szrd.gov.cn/upload/image/20180424/6366017207893963849955053.jpg
开始爬取 URL::http://md.sqllz.org/wx/CityBasicDetail.aspx?u=WChl82HhwM1kiaMEsCXPSmHqDtMkDoXFkgXvcJIdsro9tz%2fpvYa7fXuvhw9UkDTo&ct=1
title::蒋宇扬率队视察我市职业病防治情况
content::2018年是我国第16个《职业病防治法》宣传周。4月27日下午,市人大常委会副主任蒋宇扬率部分市人大代表视察我市职业病防治情况,省略300字....
文章图片:http://img.szrd.gov.cn/upload/image/20180503/6366096670456073567290731.jpg
文章图片:http://img.szrd.gov.cn/upload/image/20180503/6366096670520822808419093.jpg
文章图片:http://img.szrd.gov.cn/upload/image/20180503/6366096670555099816692148.jpg
发布时间:2018-05-09 00:00:00
开始爬取 URL::http://md.sqllz.org/wx/CityBasicDetail.aspx?u=WChl82HhwM1kiaMEsCXPSgSrRXexaYHe413m40QEaozjL%2fJs1%2bwj%2bbc2BfwHin%2bz&ct=1
title::市检察院召开人大代表建议办理情况答复会 12名代表听取答复
content::深圳特区报讯(记者 上官文复 通讯员 孟广军)5月29日下午,深圳市检察院召开人大代表建议办理情况答复会。检察长王雁林主持答复会,副检察长周荣生、余新喜及各业务部部长参会,12名提出建议或附议的深圳市人大代表到会听取答复。省略500字....
发布时间:2018-05-13 00:00:00
发布时间:2018-04-24 00:00:00
发布时间:2018-05-31 00:00:00
2018-08-15 16:05:27 INFO cn.edu.hfut.dmic.webcollector.fetcher.Fetcher  - done: [200] Key: http://md.sqllz.org/wx/CityBasicDetail.aspx?u=WChl82HhwM1kiaMEsCXPSg9PncbadG4W44pAETNu2NmdQfD2wTqpEhZDWStT25Si&ct=1 (URL: http://md.sqllz.org/wx/CityBasicDetail.aspx?u=WChl82HhwM1kiaMEsCXPSg9PncbadG4W44pAETNu2NmdQfD2wTqpEhZDWStT25Si&ct=1)
发布时间:2018-07-17 00:00:00
2018-08-15 16:05:27 INFO cn.edu.hfut.dmic.webcollector.fetcher.Fetcher  - done: [200] Key: http://md.sqllz.org/wx/CityBasicDetail.aspx?u=WChl82HhwM1kiaMEsCXPSgSrRXexaYHe413m40QEaozjL%2fJs1%2bwj%2bbc2BfwHin%2bz&ct=1 (URL: http://md.sqllz.org/wx/CityBasicDetail.aspx?u=WChl82HhwM1kiaMEsCXPSgSrRXexaYHe413m40QEaozjL%2fJs1%2bwj%2bbc2BfwHin%2bz&ct=1)
2018-08-15 16:05:27 INFO cn.edu.hfut.dmic.webcollector.fetcher.Fetcher  - done: [200] Key: http://md.sqllz.org/wx/CityBasicDetail.aspx?u=WChl82HhwM1kiaMEsCXPSihbvFWLiJESlUzxTojjETdXZqzV3Iikp4HqIPQuq57e&ct=1 (URL: http://md.sqllz.org/wx/CityBasicDetail.aspx?u=WChl82HhwM1kiaMEsCXPSihbvFWLiJESlUzxTojjETdXZqzV3Iikp4HqIPQuq57e&ct=1)
2018-08-15 16:05:27 INFO cn.edu.hfut.dmic.webcollector.fetcher.Fetcher  - done: [200] Key: http://md.sqllz.org/wx/CityBasicDetail.aspx?u=WChl82HhwM1kiaMEsCXPSolhCJTzj%2f7CxiWQXK8XBe4yrm7QDflVypC2Q7AZu4hg&ct=1 (URL: http://md.sqllz.org/wx/CityBasicDetail.aspx?u=WChl82HhwM1kiaMEsCXPSolhCJTzj%2f7CxiWQXK8XBe4yrm7QDflVypC2Q7AZu4hg&ct=1)
2018-08-15 16:05:27 INFO cn.edu.hfut.dmic.webcollector.fetcher.Fetcher  - done: [200] Key: http://md.sqllz.org/wx/CityBasicDetail.aspx?u=WChl82HhwM1kiaMEsCXPSmHqDtMkDoXFkgXvcJIdsro9tz%2fpvYa7fXuvhw9UkDTo&ct=1 (URL: http://md.sqllz.org/wx/CityBasicDetail.aspx?u=WChl82HhwM1kiaMEsCXPSmHqDtMkDoXFkgXvcJIdsro9tz%2fpvYa7fXuvhw9UkDTo&ct=1)
2018-08-15 16:05:28 INFO cn.edu.hfut.dmic.webcollector.fetcher.Fetcher  - -activeThreads=1, spinWaiting=0, fetchQueue.size=0
开始爬取 URL::http://md.sqllz.org/wx/CityBasicDetail.aspx?u=WChl82HhwM1kiaMEsCXPSgBv17P37Fpn%2b7qoKWUBzfN1OdawVbtNn8kQDD3YRUob&ct=1
title::外事侨务工委召开市六届人大六次会议代表建议督办会议
content::5月15日下午,市人大常委会外事侨务工委召开市六届人大六次会议代表建议督办会,对我委跟进的《关于深圳湾口岸实行24小时通关的建议》(第20180052号,陈成就等代表提出)、《关于解决口岸查验单位辅助人员的建议》(第20180572号,陈宏军代表提出)等5件建议进行了督办。会议充分肯定了市政府和相关部门在办理代表建议工作中作出的努力。省略300字....
文章图片:http://img.szrd.gov.cn/upload/image/20180516/6366206771816542821815706.JPG
发布时间:2018-05-16 00:00:00
2018-08-15 16:05:28 INFO cn.edu.hfut.dmic.webcollector.fetcher.Fetcher  - done: [200] Key: http://md.sqllz.org/wx/CityBasicDetail.aspx?u=WChl82HhwM1kiaMEsCXPSgBv17P37Fpn%2b7qoKWUBzfN1OdawVbtNn8kQDD3YRUob&ct=1 (URL: http://md.sqllz.org/wx/CityBasicDetail.aspx?u=WChl82HhwM1kiaMEsCXPSgBv17P37Fpn%2b7qoKWUBzfN1OdawVbtNn8kQDD3YRUob&ct=1)
2018-08-15 16:05:29 INFO cn.edu.hfut.dmic.webcollector.fetcher.Fetcher  - -activeThreads=0, spinWaiting=0, fetchQueue.size=0
2018-08-15 16:05:29 INFO cn.edu.hfut.dmic.webcollector.fetcher.Fetcher  - clear all activeThread
2018-08-15 16:05:29 INFO cn.edu.hfut.dmic.webcollector.fetcher.Fetcher  - close generator:cn.edu.hfut.dmic.webcollector.plugin.rocks.RocksGenerator
2018-08-15 16:05:30 INFO cn.edu.hfut.dmic.webcollector.fetcher.Fetcher  - close segmentWriter:cn.edu.hfut.dmic.webcollector.plugin.rocks.RocksDBManager
2018-08-15 16:05:30 INFO cn.edu.hfut.dmic.webcollector.crawler.Crawler  - depth 2 finish: 
	total urls:	6
	total time:	6 seconds

Process finished with exit code 0

中国政府网

需求分析

  • 需求是爬取 中国政府网 中的所有要闻,同理需要爬取文章中的 标题、发布时间、正文、以及正文中的图片

  • 如下所示为“ 要闻列表 ” 网页右击查看的源码情况,可以看出 文章列表超链接为相对地址,不过没有关系,webCollector 会自动处理链接地址
<li>
    <h4><a href="/xinwen/2018-08/15/content_5313873.htm" target="_blank"  >我国四处工程入选世界灌溉工程遗产</a>
         <span class="date">2018-08-15</span></h4>
</li>

<li>
    <h4><a href="/xinwen/2018-08/15/content_5313871.htm" target="_blank"  >稳投资补短板 地方政府专项债券高效发行</a>
         <span class="date">2018-08-15</span></h4>
</li>

<li>
     <h4><a href="/xinwen/2018-08/15/content_5313865.htm" target="_blank"  >2020年信息消费规模6万亿</a>
         <span class="date">2018-08-15</span></h4>
</li>
  • 这是具体的内容页面结构

  • 如下图所示为内容页的源码结构

代码爬取

  • 爬取的核心代码如下,同理其中使用了一个解析日期文本的工具类,在本文的上一部分已经发布了源码,在此不再累述
package com.lct.webCollector;

import cn.edu.hfut.dmic.contentextractor.ContentExtractor;
import cn.edu.hfut.dmic.webcollector.model.CrawlDatums;
import cn.edu.hfut.dmic.webcollector.model.Page;
import cn.edu.hfut.dmic.webcollector.plugin.rocks.BreadthCrawler;
import com.lct.util.SystemUtils;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

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

/**
 * Crawling news from github news
 * 自动 弹出 URL 地址,继承 BreadthCrawler(广度爬虫)
 * <p/>
 * cn.edu.hfut.dmic.webcollector.plugin.rocks.BreadthCrawler是基于RocksDB的插件,于2.72版重新设计
 * BreadthCrawler可以设置正则规律,让遍历器自动根据URL的正则遍历网站,可以关闭这个功能,自定义遍历
 * 如果autoParse设置为true,遍历器会自动解析页面中符合正则的链接,加入后续爬取任务,否则不自动解析链接。
 * 注意,爬虫会保证爬取任务的唯一性,也就是会自动根据CrawlDatum的key进行去重,默认情况下key就是URL,
 * 所以用户在编写爬虫时完全不必考虑生成重复URL的问题。
 * 断点爬取中,爬虫仍然会保证爬取任务的唯一性。
 *
 * @author hu
 */
public class MyAutoNewsCrawler extends BreadthCrawler {
    /**
     * 构造一个基于 RocksDB 的爬虫
     * RocksDB文件夹为crawlPath,crawlPath中维护了历史URL等信息
     * 不同任务不要使用相同的crawlPath
     * 两个使用相同crawlPath的爬虫并行爬取会产生错误
     *
     * @param crawlPath RocksDB使用的文件夹
     * @param autoParse 是否根据设置的正则自动探测新URL ,默认为 true
     */
    public MyAutoNewsCrawler(String crawlPath, boolean autoParse) {
        super(crawlPath, autoParse);

        /**
         * 只有在autoParse和autoDetectImg都为true的情况下
         * 爬虫才会自动解析图片链接
         */
        getConf().setAutoDetectImg(true);

        /**设置爬取的网站地址
         * addSeed 表示添加种子
         * 种子链接会在爬虫启动之前加入到抓取信息中并标记为未抓取状态.这个过程称为注入
         * 放入爬取的目标网址
         * */
        this.addSeed("http://www.gov.cn/xinwen/yaowen.htm");
//        this.addSeed("http://www.gov.cn/xinwen/2018-08/13/content_5313418.htm");

        /**
         * 添加一个 URL 正则规则 正则规则有两种,正正则和反正则
         * URL 符合正则规则需要满足两个条件: 1.至少能匹配一条正正则 2.不能和任何反正则匹配
         * 正正则示例:+abc.*efg 是一条正正则,正则的内容为 abc.*efg ,起始加号表示正正则
         * 反正则示例:-abc.*efg 是一条反正则,正则的内容为 abc.*efg ,起始减号表示反正则
         * (注1)如果一个规则的起始字符不为加号且不为减号,则该正则为正正则,正则的内容为自身,如 a.*c 是一条正正则,正则的内容为 a.*c
         * (注2) 正则的内容与平时 js 与 java 中使用的正则写法是一样的,如 "."表示任意字符、"*"表示0次或多次、[0-9]{4} 表示连续4个数字
         * */
        this.addRegex("http://www.gov.cn/xinwen/[0-9]{4}-[0-9]{2}/[0-9]{2}/content_.*");
        /**将网页中的图片链接也留下来
         * 此时不要再讲图片过滤出去了*/
        this.addRegex(".*/images/.*.(jpg|png|gif)");

        /**
         * 过滤 jpg|png|gif 等图片地址 时:
         * this.addRegex("-.*\\.(jpg|png|gif).*");
         */

        /**
         * 过滤 链接值含 "#" 的地址
         */
        this.addRegex("-.*#.*");

        /**设置线程数*/
        setThreads(10);
        getConf().setTopN(100);

        /**
         * 是否进行断电爬取,默认为 false
         * setResumable(true);
         */
    }

    /**
     * 必须重写 visit 方法,作用是:
     * 在整个抓取过程中,只要抓到符合要求的页面,webCollector 就会回调该方法,并传入一个包含了页面所有信息的 page 对象
     *
     * @param page :Page是爬取过程中,内存中保存网页爬取信息的一个容器,Page只在内存中存放,用于保存一些网页信息,方便用户进行自定义网页解析之类的操作。
     * @param next :可以手工将希望后续采集的任务加到next中(会参与自动去重),即如果需要后续再次进行爬取的,则可以添加进去
     */
    @Override
    public void visit(Page page, CrawlDatums next) {
        String url = page.url();

        System.out.println(" page 类型:" + page.contentType());
        System.out.println("开始爬取 URL::" + url);

        /**
         * 判断当前 Page 的 URL 是否和输入正则匹配
         * 如果此页面地址 确实是要求爬取网址,则进行取值,contentType 是页面请求的内容类型,可以通过浏览器 F12 查看
         */
        if (page.contentType().startsWith("text/html")) {
            /**
             * page 为 html 网页类型
             */
            if (page.matchUrl("http://www.gov.cn/xinwen/[0-9]{4}-[0-9]{2}/[0-9]{2}/content_.*")) {

                /**
                 * 通过 选择器 获取页面 标题、以及 正文内容、时间
                 * 这些选择器语法就是 Jsoup,类似于 JQuery 的选择器,非常方便
                 * 可以参考 Jsoup 官网:https://jsoup.org/cookbook/extracting-data/selector-syntax
                 * select:返回的是 Elements
                 * selectText:是直接获取元素的文本内容,只要是此元素下的,无论嵌套多少层在下面,都会进行获取
                 * <div class="d_con dd_con"><p>...</p></div>:当样式有多个时,选择器使用"."号连接
                 * 因为 "空格" 本身就是一个层级选择器,"A B" 表示查找A元素下的所有B元素
                 * */

                String title = page.selectText("div.article.oneColumn.pub_border>h1");
                String content = page.selectText("div#UCAP-CONTENT");
                String dateStr = page.selectText("div.pages-date");

                System.out.println("title::" + title);
                /**解析日期文本的自定义工具类*/
                Date date = SystemUtils.parseDateStr(dateStr);
                if (date == null) {
                    System.out.println("发布时间:null");
                } else {
                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    System.out.println("发布时间:" + simpleDateFormat.format(date));
                }
                System.out.println("content::" + content);

                /**
                 * 获取正文中的所有图片元素,方法一:仍然和以前一样使用 获取图片元素的方式,这样当页面图片地址是相对路径时
                 * 如 <img src="../images/hh13.png"/>,则获取的值也是相对路径,解决办法之一是自己根据上下文关系去拼接成一个合法的地址
                 *
                 * 本例还会使用 webCollector 自动探测页面超链接时,将图片链接也一并获取出来,
                 * 因为 webCollector 根据 http 请求地址获取,所以会是完整的绝对路径
                 */
                Elements imgElements = page.select("div#UCAP-CONTENT img");
                for (Element imgElement : imgElements) {
                    System.out.println("文章图片(Elements方式):" + imgElement.attr("src") + "\n");
                }
            }
        } else if (page.contentType().startsWith("image")) {
            /**
             * page 为 图像类型
             */
            System.out.println("图片地址(page.contentType()方式):" + url);
        }
    }

    public static void main(String[] args) throws Exception {

        ContentExtractor contentExtractor;

        /**
         * MyAutoNewsCrawler 构造器中会进行 数据初始化,这两个参数接着会传给父类
         * super(crawlPath, autoParse);
         * crawlPath:表示设置保存爬取记录的文件夹,本例运行之后会在应用根目录下生成一个 "crawl" 目录存放爬取信息
         * autoParse:表示进行 URL自动探测
         * */
        MyAutoNewsCrawler crawler = new MyAutoNewsCrawler("crawl", true);
        /**
         * 启动爬虫,爬取的深度为3层
         * 添加的第一层种子链接,为第1层,本例层级如下:
         * 第一层:爬取的目标网址,即文章列表页
         * 第二层:具体的文章内容页(此时需要获取的图片恰好就在其中)
         * 第三层:就是为了获取第二层中的图片地址
         */
        crawler.start(3);
    }
}

运行结果

  • 因为爬取的内容比较多,文章正文又长,所以只截取其中具有代表性进行展示
page 类型:text/html
开始爬取 URL::http://www.gov.cn/xinwen/2018-05/28/content_5294179.htm
title::“一带一路”农业协作蓝图正在展开
发布时间:2018-05-28 09:41:00
content::与“一带一路”相关国家农产品进口总额占中国农产品进口总额的19%左右,出口占30%左右 ——“一带一路”农业协作蓝图正在展开 图为陕西杨凌中哈苹果友谊园。(新华社发) 在“一带一路”倡议框架下,传统农业往来早已发展为以科技、人才、商贸、基础设施等为重点的全方位农业大协作,一张“一带一路”农业协作的宏伟蓝图正在徐徐展开。 日前,中国工程院院士、中国农业科学院副院长吴孔明在接受经济日报记者专访时表示,在全球化的今天,国与国之间的相互依存空前紧密,利益共生不断深化,国际社会愈发需要增强互信、协同合作,共同应对气候变化、自然资源匮乏、人口不断增长等诸多挑战。为保障世界农产品有效供给,推进“一带一路”农业合作意义重大。省略500字。。。。。。
 page 类型:text/html
开始爬取 URL::http://www.gov.cn/xinwen/2018-05/21/content_5292486.htm
title::820万大学毕业生带来的就业新动向
发布时间:2018-05-21 17:34:00
content::新华社武汉5月21日电 题:820万大学毕业生带来的就业新动向 新华社记者 2018届全国普通高校毕业生人数再创新高,预计达到820万人。省略800字。。。。。。
开始爬取 URL::http://www.gov.cn/xinwen/2016-12/30/content_5154716.htm
 page 类型:image/jpeg
开始爬取 URL::http://www.gov.cn/govweb/xhtml/zhuanti/2017lysy/images/guohui.jpg
图片地址(page.contentType()方式):http://www.gov.cn/govweb/xhtml/zhuanti/2017lysy/images/guohui.jpg
 page 类型:image/jpeg
开始爬取 URL::http://www.gov.cn/govweb/xhtml/zhuanti/20180629zgjjbnb/images/2018jjbnb.jpg
图片地址(page.contentType()方式):http://www.gov.cn/govweb/xhtml/zhuanti/20180629zgjjbnb/images/2018jjbnb.jpg
开始爬取 URL::http://www.gov.cn/xinwen/2018-02/14/content_5266805.htm
title::商务部外资司负责人谈2017年全年全国吸收外资情况
title::习近平:提高脱贫质量聚焦深贫地区 扎扎实实把脱贫攻坚战推向前进
发布时间:2018-01-16 21:47:00
文章图片(Elements方式):5257283/images/10f730ac8c1a40968281c986ed55ec60.jpg

发布时间:2018-02-14 12:01:00
文章图片(Elements方式):5266805/images/dd79359955b74b04ae97b084ee73b8d3.jpg

文章图片(Elements方式):5266805/images/2a14c410eb254b928cd2bee1a1047ef7.jpg

文章图片(Elements方式):5266805/images/cce8b2c98682486c924b5dbb0204646d.jpg

文章图片(Elements方式):5266805/images/b63479a818854116960138daf07e9c20.jpg

2018-08-15 17:09:51 INFO cn.edu.hfut.dmic.webcollector.fetcher.Fetcher  - done: [200] Key: http://www.gov.cn/xinwen/2018-01/16/content_5257283.htm (URL: http://www.gov.cn/xinwen/2018-01/16/content_5257283.htm)
2018-08-15 17:09:51 INFO cn.edu.hfut.dmic.webcollector.fetcher.Fetcher  - done: [200] Key: http://www.gov.cn/xinwen/2018-02/14/content_5266805.htm (URL: http://www.gov.cn/xinwen/2018-02/14/content_5266805.htm)
 page 类型:text/html
开始爬取 URL::http://www.gov.cn/xinwen/2018-02/14/content_5266801.htm
 page 类型:text/html
开始爬取 URL::http://www.gov.cn/xinwen/2018-02/21/content_5267867.htm
title::商务部外资司负责人谈2018年1月全国吸收外资情况
title::五类虚假违法互联网广告将被重点整治
发布时间:2018-02-14 11:36:00
 page 类型:text/html
开始爬取 URL::http://www.gov.cn/xinwen/2018-06/27/content_5301508.htm
文章图片(Elements方式):5298667/images/b5357a31309944acac3260d6d889bae0.jpg

文章图片(Elements方式):5298667/images/8f18491b7de94d24aa27515457eb4e29.jpg

文章图片(Elements方式):5298667/images/31188b6989334153806bf8e74e053e62.jpg

 page 类型:text/html
开始爬取 URL::http://www.gov.cn/xinwen/2018-06/27/content_5301501.htm
title::教育部等三部门印发通知 自今年7月1日起全面取消国内高等教育学历学位认证服务收费
title::超200万制造业企业入驻“双创”平台
2018-08-15 17:17:19 INFO cn.edu.hfut.dmic.webcollector.crawler.Crawler  - depth 3 finish: 
	total urls:	100
	total time:	11 seconds

Process finished with exit code 0

猜你喜欢

转载自blog.csdn.net/wangmx1993328/article/details/81699494