我的第一个开源项目

2019-10-09 09:32:06来源:博客园 阅读 ()

新老客户大回馈,云服务器低至5折

我的第一个开源项目

Fork me on Gitee

地址

gitee地址,GitHub网速较慢,没有上传到GitHub

项目介绍

  1. 一个简单的多线程爬虫,具有断点爬取功能,以及自动推测网页编码功能

  2. 使用jdk11+,maven构建,我使用jdk11.0.2时会报错,见https://bugs.openjdk.java.net/browse/JDK-8213202,jdk8却没有,jdk本身的bug,所以我换了最新版的jdk11.0.4

  3. 解析网页主要使用了Jsoup和正则表达式,所以这两个需要会用

思路

  1. 先有一个或多个具体的初始链接,假如说把这些初始链接的页面类型记为seed

  2. 定义一个规则,规则主要由Jsoup选择器(类似于css选择器)、正则表达式、页面类型type组成,选择器一般定位到a标签。seed页面通过应用规则就可以自动获取标签中符合正则表达式的链接,并将这些链接存储到h2中,这些链接就是下一层要爬取的链接,假如将这些链接所代表的页面记为page1(type设置成了page1)

  3. 重复上一步,也是定义规则,唯一的区别就是应用这些规则的页面不是seed,而是page1页面。也就是说这些规则是有顺序的,除了第一个规则应用于seed页面之外,其余的每一个规则都是应用于上一个规则获取到的页面,以此类推,多少层都可以

  4. 结合示例查看源代码能更快的理解

示例及说明

ZongHeng zh = new ZongHeng();
zh.setCacheDirectory("f:/spider");
zh.config().setInterval(50).setBreakPoint(false);
//添加一个初始链接
zh.addSeed("http://www.zongheng.com/");
//添加一个规则,按照这个规则在初始链接页面取链接,并将取到的链接代表的页面记为category
zh.addRule("ul#data-groupdom li a", "http://www.zongheng.com/category/\\d+.html", "category");
//添加规则,在category页面取链接
zh.addRegex("http://book.zongheng.com/book/\\d+.html", "book");
zh.start();

每一个具体的爬虫都继承自Spider类,上面的代码就定义了一个简单的爬虫。

  1. 第2行:设置缓存目录f:/spider
  2. 第3行:提交任务间隔最大50毫秒,关闭断点爬取
  3. 第4行:添加一个初始链接
  4. 第5行:添加一个规则,按照这个规则在初始链接页面取链接,并将取到的链接代表的页面记为category
  5. 第6行:添加一个规则,按照这个规则在category页面取链接,并将取到的链接代表的页面记为category
  6. 第7行:启动爬虫

启动后爬虫就能自己去获取符合规则的网页,但获取网页不是我们的最终目的,我们的最终目的是从网页中提取自己需要的信息,所以继承Spider后还有一个必须重写的方法

@Override
public void parse(Page page) {
    if (!page.isSeed()) {
        String text = page.urlText();
        System.out.println(text + "---" + page.link() + "---" + page.prevLink());
    }
    if (page.typeEquals("category")) {
        //category页面取得的下层链接的标签的文本去掉空白后长度大于1
        page.setNextLinksFilter(e -> e.hasText() && e.text().replaceAll("\\s+", "").length() > 1);
    }
}

解析主要就是应用Jsoup里面的方法,通过page.getDoc()方法可以获取org.jsoup.nodes.Document对象,或者直接调用page.select(String cssQuery)方法解析,这就不多说了。

要说一下就是Page里面的3个高阶函数,所谓高阶函数就是接收函数作为参数的函数,这3个函数分别是setNextLinksFilter,setNextInfoFunc,setNextLinkUnary,作用分别是筛选符合条件的链接作为下层链接,携带信息到下一层,链接映射。

上面的代码就用到了筛选的方法,传入的函数是这样的:函数的参数是org.jsoup.nodes.Element类型的对象,一般代表a标签,函数返回boolean类型,返回值为true的Element才能作为下一层链接的提供者。

手动获取下层链接

上面说的是自动获取下层链接,即只需要通过规则爬虫就能一层一层的获取链接,但有时候这样可能行不通,需要手动的获取链接然后添加到下一层,怎么做呢?

看一下这个例子,这其实完全可以自动获取下层链接,为了演示改成了手动获取下层链接,addByHand(String type)方法看源码知道这也是一个规则,只不过是一个只有type属性的规则而已。

//添加一个初始链接
zh.addSeed("http://www.zongheng.com/");
zh.addByHand("category");

可以看到初始链接后面紧跟一个手动添加规则,记为category

if (page.isSeed()) {
    //这样还是用规则获取的下层链接,所以这没必要用手动,这里仅作为示例
    page.addNext(Rule.createRule("ul#data-groupdom li a", "http://www.zongheng.com/category/\\d+.html"));
}

然后在seed页面取链接(这些链接所表示的页面就是category页面)加入到下一层,这就是手动添加了

局限

  • 由于自动缓存的原因,编写好规则并爬取后,如果再次修改规则,如加入筛选条件等,由于从缓存中取数据,此时筛选条件对已经爬取的网页不起作用,要使它起作用,请删除缓存

  • 目前只支持get请求或能转换成get请求的链接

感谢

  • elves:参考了该项目思想
  • WebCollector:参考了该项目思想
  • Jsoup:用于下载和解析网页
  • h2 database:提供缓存
  • DbUtils:操作数据库

原文链接:https://www.cnblogs.com/pdzbokey/p/11639779.html
如有疑问请与原作者联系

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:火眼金睛,Java诊断利器Arthas

下一篇:springcloud学习之路: (四) springcloud集成Hystrix服务保护