基于jsoup框架的爬虫系统,包括接口爬、定时爬、多线程爬,spring-boot + jsoup 20190818

基于jsoup框架的爬虫系统,包括接口爬、定时爬、多线程爬
GitHub地址:https://github.com/HappyWjl/spider-jsoup
如果该项目对您有帮助,您可以点右上角 “Star” 支持一下 谢谢!
或者您可以 “follow” 一下,该项目将持续更新,不断完善功能。
转载还请注明出处,谢谢了
博主QQ:820155406

一、简介

  • 本博客基于jsoup框架搭建爬虫系统,属于入门案例,仅爬取静态网页(代码案例基于古诗文网进行演示https://www.gushiwen.org/),动态网页可自行研究puppeteer,或者其他高大上的技术方案~
  • jsoup:百度百科地址 https://baike.baidu.com/item/jsoup
  • 个人理解,这个框架就是根据url,将整个网页抓取成一份文档(Document),然后通过select方法进行标签筛选,过滤符合要求的内容,还可以根据attr方法进行属性值获取。整体简单高效,但局限在静态网页的爬取中,动态网页或者网站规范不正确时,爬取会比较困难。

二、环境搭建

  • IDEA:http://www.ilearn1234.com/#/tool?id=1&type=tool
  • JDK11:http://www.ilearn1234.com/#/tool?id=4&type=tool 注意:这里需要下载jdk11的版本
  • Postman:http://www.ilearn1234.com/#/tool?id=9&type=tool

三、项目讲解

  • 项目结构如图:
    基于jsoup框架的爬虫系统,包括接口爬、定时爬、多线程爬,spring-boot + jsoup 20190818_第1张图片
  • 手动爬虫
  • 首先打开ManualController,可以看到有两个接口,“根据url抓取数据”、“根据url抓取数据列表”
    基于jsoup框架的爬虫系统,包括接口爬、定时爬、多线程爬,spring-boot + jsoup 20190818_第2张图片
  • 我们打开StartServiceImpl文件,可以看到具体的实现方法
    基于jsoup框架的爬虫系统,包括接口爬、定时爬、多线程爬,spring-boot + jsoup 20190818_第3张图片
    基于jsoup框架的爬虫系统,包括接口爬、定时爬、多线程爬,spring-boot + jsoup 20190818_第4张图片
  • 第一个测试抓取url为:https://so.gushiwen.org/shiwenv_ee16df5673bc.aspx,第二个测试抓取的url为:https://so.gushiwen.org/shiwen/default.aspx?page=1&type=4&id=1(PS:注意下方第二个请求截图传参是这个地址:https://so.gushiwen.org/shiwen/default.aspx?page=%s&type=4&id=1,因为需要拼接分页参数)
  • 由于两个地址内容结构有点差异,所以写了两个封装古诗词对象的方法
  • 首先启动项目,打开SpiderJsoupApplication文件,启动main方法,正常启动无报错即可
  • 然后我们使用postman,模拟第一个接口的请求:
    基于jsoup框架的爬虫系统,包括接口爬、定时爬、多线程爬,spring-boot + jsoup 20190818_第5张图片
  • 接口成功返回了我们需要的数据,核心代码为下图,这段代码根据网页上的标签,进行解析,将包含的内容成功地赋值到ancientPoetry中:
    基于jsoup框架的爬虫系统,包括接口爬、定时爬、多线程爬,spring-boot + jsoup 20190818_第6张图片
  • 我们检查一下对应的页面内容,可以发现网页标签中和抓取代码是匹配的,根据特定的标签+类选择器,即可爬取到对应的内容:
    基于jsoup框架的爬虫系统,包括接口爬、定时爬、多线程爬,spring-boot + jsoup 20190818_第7张图片

其实剩下的博文,都类似上方讲解,介意的勿往下看,可以直接下载源码,自行研究就好。
GitHub地址:https://github.com/HappyWjl/spider-jsoup
如果该项目对您有帮助,您可以点右上角 “Star” 支持一下 谢谢!
或者您可以 “follow” 一下,该项目将持续更新,不断完善功能。
转载还请注明出处,谢谢了
博主QQ:820155406

  • 再然后我们使用postman,模拟第二个接口的请求:
    基于jsoup框架的爬虫系统,包括接口爬、定时爬、多线程爬,spring-boot + jsoup 20190818_第8张图片
  • 可以看到,接口已经将结果返回,这个接口定义了循环几页去抓取内容,通过pageMaxNo进行控制(PS:分页是从1开始的,这个需要注意下,接口最好使用POST请求,入股采用GET请求,url的除第一个参数外,其他参数会丢失)
  • 具体代码如下,采用for循环,进行分页轮询,将每页的抓取结果,存放到ancientPoetryList中,最后返回:
    基于jsoup框架的爬虫系统,包括接口爬、定时爬、多线程爬,spring-boot + jsoup 20190818_第9张图片
  • 讲完接口手动抓取,再来讲讲job定时触发,因为很多网站晚上12点才会更新内容,为了更快地抓取新的数据,我们需要定时去抓取的,代码里延迟2小时进行数据抓取
  • 我们打开job文件,可以看到代码很简单,cron的定时器语法,可参见百度。job任务结合已经写好的接口,只需要将url传入进去触发。url可以配置到application.properties中,或者自行放到数据库中,再写个查询方法即可
    基于jsoup框架的爬虫系统,包括接口爬、定时爬、多线程爬,spring-boot + jsoup 20190818_第10张图片
  • 使用job定时器时,启动文件需要加上指定注解,方便在启动时,加载相关配置
    基于jsoup框架的爬虫系统,包括接口爬、定时爬、多线程爬,spring-boot + jsoup 20190818_第11张图片
  • 最后讲讲多线程抓取,参见spider包中代码,这里的代码非博主原创,由博主同事提供,多谢我大坤哥~
    基于jsoup框架的爬虫系统,包括接口爬、定时爬、多线程爬,spring-boot + jsoup 20190818_第12张图片
  • 多线程抓取,启动文件为SpiderService,调用main方法,即可开启多线程抓取
  • 这里采用了建造者模式,通过传入的列表url,再进行列表中url抓取每个文章的跳转链接,根据抓取的链接,分别访问每一个详情页,进行抓取详细内容
  • GswAuthorCrawler(古诗文网作者信息爬虫)和GswContentCrawler(古诗文网内容爬虫)是演示的两个页面的爬虫文件,里面个性化定义了网站地址、分页次数、抓取标签、组装内容等操作
package com.jsoup.api.spider.crawler;

import com.jsoup.api.spider.Crawler;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.LinkedList;

/**
 * 自定义网站抓取爬虫(古诗文作者)
 *
 * Created by Happy王子乐 on 2019/8/17.
 */
@Service
public class GswAuthorCrawler implements Crawler {

    @Override
    public String name() {
        return "古诗文作者";
    }

    @Override
    public Spider newSpider() {
        return new BaiDuImgSpider();
    }

    @Override
    public Analyzer analyzer() {
        return new BaiDuImgAnalyzer();
    }

    @Slf4j
    static class BaiDuImgSpider implements Spider {

        static final String LIST_LINK_FORMAT = "https://so.gushiwen.org/authors/";

        private int page = 3;

        private boolean last = false;

        private LinkedList linkList = new LinkedList<>();

        @Override
        public String nextLink() {
            if (last) {
                return null;
            }
            if (!linkList.isEmpty()) {
                return linkList.removeFirst();
            }
            try {
                String url = String.format(LIST_LINK_FORMAT, page++);
                Connection conn = Jsoup.connect(url);
                Elements elements = conn.get().body().select(".sonspic .cont p");
                if (last = CollectionUtils.isEmpty(elements)) {
                    return null;
                }
                for (Element element : elements) {
                    String jumpUrl = element.select("a").attr("abs:href");
                    if (jumpUrl.contains("authors")) {
                        continue;
                    }
                    linkList.add(jumpUrl);
                }
            } catch (Exception e) {
                e.getStackTrace();
                return null;
            }
            return linkList.removeFirst();
        }
    }

    static class BaiDuImgAnalyzer implements Analyzer {

        @Override
        public String title(Document document) {
            Element headline = document.select("h1").first();
            return headline != null ? headline.text() : null;
        }

        @Override
        public String content(Document document) {
            Element content = document.select(".sonspic .cont").first();
            if (content == null) {
                return null;
            }
            content.removeClass("*");
            return content.html();
        }
    }
}

package com.jsoup.api.spider.crawler;

import com.jsoup.api.spider.Crawler;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 自定义网站抓取爬虫(古诗文网内容)
 *
 * Created by Happy王子乐 on 2019/8/17.
 */
@Service
public class GswContentCrawler implements Crawler {

    @Override
    public String name() {
        return "古诗文内容";
    }

    @Override
    public Spider newSpider() {
        return new GscSpider();
    }

    @Override
    public Analyzer analyzer() {
        return new GscAnalyzer();
    }

    @Slf4j
    static class GscSpider implements Spider {

        static final String LIST_LINK_FORMAT = "https://so.gushiwen.org/shiwen/default.aspx?page=%s&type=4&id=1";

        private int page = 3;

        private boolean last = false;

        private LinkedList linkList = new LinkedList<>();

        @Override
        public String nextLink() {
            if (last) {
                return null;
            }
            if (!linkList.isEmpty()) {
                return linkList.removeFirst();
            }
            try {
                String url = String.format(LIST_LINK_FORMAT, page++);
                Connection conn = Jsoup.connect(url);
                Elements elements = conn.get().body().select(".sons .cont p");
                List elementList = elements.stream().filter(element -> element.select(".source").size() == 0).collect(Collectors.toList());
                if (last = CollectionUtils.isEmpty(elementList)) {
                    return null;
                }
                for (Element element : elementList) {
                    linkList.add(element.select("a").attr("abs:href"));
                }
            } catch (Exception e) {
                e.getStackTrace();
                return null;
            }
            return linkList.removeFirst();
        }
    }

    static class GscAnalyzer implements Analyzer {

        @Override
        public String title(Document document) {
            Element headline = document.select("h1").first();
            return headline != null ? headline.text() : null;
        }

        @Override
        public String content(Document document) {
            Element content = document.select(".contson").first();
            if (content == null) {
                return null;
            }
            content.removeClass("*");
            return content.html();
        }
    }
}

  • 最后通过数据组装,结合html模版,生成html文件,输出到指定文件夹中
    基于jsoup框架的爬虫系统,包括接口爬、定时爬、多线程爬,spring-boot + jsoup 20190818_第13张图片
  • 启动SpiderService中的main方法,找到输出路径文件夹,可以看到抓取内容已经生成为html文件
    基于jsoup框架的爬虫系统,包括接口爬、定时爬、多线程爬,spring-boot + jsoup 20190818_第14张图片
    基于jsoup框架的爬虫系统,包括接口爬、定时爬、多线程爬,spring-boot + jsoup 20190818_第15张图片
  • 我们打开一个白居易.html文件,可以看到图片带作者信息已经抓取下来
    基于jsoup框架的爬虫系统,包括接口爬、定时爬、多线程爬,spring-boot + jsoup 20190818_第16张图片
  • 至此,爬虫项目的大致讲解到这里,入门项目简单,可根据源码自行研究

基于jsoup框架的爬虫系统,包括接口爬、定时爬、多线程爬
GitHub地址:https://github.com/HappyWjl/spider-jsoup
如果该项目对您有帮助,您可以点右上角 “Star” 支持一下 谢谢!
或者您可以 “follow” 一下,该项目将持续更新,不断完善功能。
转载还请注明出处,谢谢了
博主QQ:820155406

你可能感兴趣的:(核心系统,入门项目,互联网公司核心系统入门)