springboot 2.0集成webmagic(低配置,自动化采集)(下)

简介: springboot 2.0集成webmagic(低配置,自动化采集)(下)

正文


四、webmagic


官方文档


介绍


webmagic的是参考业界最优秀爬虫Scrapy来实现的,使用了HttpClient、Jsoup等Java世界最成熟的工具


架构


WebMagic的结构分为Downloader(下载)、PageProcessor(处理)、Scheduler(管理)、Pipeline(持久化)四个组件,并由Spider(容器)将它们彼此组织起来,可以互相交互、流程化的执行,总体架构图如下


222.png


组件


Downloader


负责从网络上下载页面,以便后续处理,webmagic默认使用httpclient

PageProcessor


负责解析页面,抽取有用信息,以及发现新的链接,使用Jsoup来解析HTML

Scheduler


负责管理待抓取URL,以及一些去重工作。webmagic默认使用JDK自带的内存队列来管理URL,用集合去重,支持redis分布式管理

Pipeline


负责抽取结果的处理,包括计算、持久化到文件、数据库等

XSoup


基于Jsoup开发的一款XPath解析器


五、微服务集成


数据库表设计


-- ----------------------------
-- Table structure for boot_link
-- ----------------------------
DROP TABLE IF EXISTS `boot_link`;
CREATE TABLE `boot_link`  (
  `id` bigint(20) NOT NULL COMMENT 'id',
  `uri` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文章链接',
  `type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '网站类型',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `boot_link` VALUES ('11', 'https://www.cnblogs.com/koushenhai/p/12595630.html', 'bky');
INSERT INTO `boot_link` VALUES ('12', 'https://kcloud.blog.csdn.net/article/details/118633942', 'csdn');
INSERT INTO `boot_link` VALUES ('20', 'https://kcloud.blog.csdn.net/article/details/121491124', 'csdn');
INSERT INTO `boot_link` VALUES ('33', 'https://kcloud.blog.csdn.net/article/details/82109656', 'csdn');
INSERT INTO `boot_link` VALUES ('41', 'https://kcloud.blog.csdn.net/article/details/117769662', 'csdn');
INSERT INTO `boot_link` VALUES ('49', 'https://kcloud.blog.csdn.net/article/details/118660073', 'csdn');
INSERT INTO `boot_link` VALUES ('57', 'https://kcloud.blog.csdn.net/article/details/119720174', 'csdn');
INSERT INTO `boot_link` VALUES ('65', 'https://kcloud.blog.csdn.net/article/details/123179670', 'csdn');
INSERT INTO `boot_link` VALUES ('66', 'https://kcloud.blog.csdn.net/article/details/117635759', 'csdn');
INSERT INTO `boot_link` VALUES ('74', 'https://kcloud.blog.csdn.net/article/details/117771583', 'csdn');
INSERT INTO `boot_link` VALUES ('78', 'https://kcloud.blog.csdn.net/article/details/123039609', 'csdn');
INSERT INTO `boot_link` VALUES ('79', 'https://kcloud.blog.csdn.net/article/details/82588914', 'csdn');
INSERT INTO `boot_link` VALUES ('96', 'https://kcloud.blog.csdn.net/article/details/108021143', 'csdn');
INSERT INTO `boot_link` VALUES ('118', 'https://kcloud.blog.csdn.net/article/details/121305244', 'csdn');
INSERT INTO `boot_link` VALUES ('128', 'https://kcloud.blog.csdn.net/article/details/82110125', 'csdn');
INSERT INTO `boot_link` VALUES ('129', 'https://kcloud.blog.csdn.net/article/details/123630814', 'csdn');
INSERT INTO `boot_link` VALUES ('130', 'https://kcloud.blog.csdn.net/article/details/116420798', 'csdn');
INSERT INTO `boot_link` VALUES ('131', 'https://kcloud.blog.csdn.net/article/details/123484520', 'csdn');
INSERT INTO `boot_link` VALUES ('132', 'https://kcloud.blog.csdn.net/article/details/123013305', 'csdn');
INSERT INTO `boot_link` VALUES ('133', 'https://kcloud.blog.csdn.net/article/details/123390833', 'csdn');
INSERT INTO `boot_link` VALUES ('134', 'https://kcloud.blog.csdn.net/article/details/123311487', 'csdn');
INSERT INTO `boot_link` VALUES ('135', 'https://kcloud.blog.csdn.net/article/details/123292276', 'csdn');
INSERT INTO `boot_link` VALUES ('136', 'https://kcloud.blog.csdn.net/article/details/123123229', 'csdn');
INSERT INTO `boot_link` VALUES ('137', 'https://kcloud.blog.csdn.net/article/details/116704223', 'csdn');
INSERT INTO `boot_link` VALUES ('145', 'https://kcloud.blog.csdn.net/article/details/123739314', 'csdn');
INSERT INTO `boot_link` VALUES ('146', 'https://kcloud.blog.csdn.net/article/details/123688809', 'csdn');
INSERT INTO `boot_link` VALUES ('147', 'https://kcloud.blog.csdn.net/article/details/123673741', 'csdn');
INSERT INTO `boot_link` VALUES ('148', 'https://kcloud.blog.csdn.net/article/details/123628721', 'csdn');
INSERT INTO `boot_link` VALUES ('149', 'https://kcloud.blog.csdn.net/article/details/123599384', 'csdn');
INSERT INTO `boot_link` VALUES ('150', 'https://kcloud.blog.csdn.net/article/details/122181814', 'csdn');
INSERT INTO `boot_link` VALUES ('151', 'https://kcloud.blog.csdn.net/article/details/121557788', 'csdn');
INSERT INTO `boot_link` VALUES ('159', 'https://kcloud.blog.csdn.net/article/details/116449621', 'csdn');
INSERT INTO `boot_link` VALUES ('160', 'https://kcloud.blog.csdn.net/article/details/83623118', 'csdn');
INSERT INTO `boot_link` VALUES ('161', 'https://kcloud.blog.csdn.net/article/details/84777724', 'csdn');
INSERT INTO `boot_link` VALUES ('162', 'https://kcloud.blog.csdn.net/article/details/105587614', 'csdn');
INSERT INTO `boot_link` VALUES ('163', 'https://kcloud.blog.csdn.net/article/details/83515122', 'csdn');
INSERT INTO `boot_link` VALUES ('164', 'https://kcloud.blog.csdn.net/article/details/83451040', 'csdn');
INSERT INTO `boot_link` VALUES ('165', 'https://kcloud.blog.csdn.net/article/details/117252826', 'csdn');
INSERT INTO `boot_link` VALUES ('166', 'https://kcloud.blog.csdn.net/article/details/84826176', 'csdn');
INSERT INTO `boot_link` VALUES ('167', 'https://kcloud.blog.csdn.net/article/details/120031600', 'csdn');
INSERT INTO `boot_link` VALUES ('168', 'https://kcloud.blog.csdn.net/article/details/119685953', 'csdn');
INSERT INTO `boot_link` VALUES ('169', 'https://kcloud.blog.csdn.net/article/details/120147123', 'csdn');
INSERT INTO `boot_link` VALUES ('170', 'https://kcloud.blog.csdn.net/article/details/120245035', 'csdn');
INSERT INTO `boot_link` VALUES ('171', 'https://kcloud.blog.csdn.net/article/details/120190383', 'csdn');
INSERT INTO `boot_link` VALUES ('179', 'https://kcloud.blog.csdn.net/article/details/94590629', 'csdn');
INSERT INTO `boot_link` VALUES ('187', 'https://kcloud.blog.csdn.net/article/details/116949872', 'csdn');
INSERT INTO `boot_link` VALUES ('192', 'https://kcloud.blog.csdn.net/article/details/123789292', 'csdn');
INSERT INTO `boot_link` VALUES ('193', 'https://kcloud.blog.csdn.net/article/details/123780832', 'csdn');
INSERT INTO `boot_link` VALUES ('194', 'https://kcloud.blog.csdn.net/article/details/123771040', 'csdn');
INSERT INTO `boot_link` VALUES ('195', 'https://kcloud.blog.csdn.net/article/details/122522290', 'csdn');
INSERT INTO `boot_link` VALUES ('196', 'https://kcloud.blog.csdn.net/article/details/123833614', 'csdn');
DROP TABLE IF EXISTS `boot_article`;
CREATE TABLE `boot_article`  (
  `id` bigint(20) NOT NULL COMMENT 'id',
  `title` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文章链接',
  `content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '网站类型',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;


微服务


引入依赖


        <dependency>
            <groupId>us.codecraft</groupId>
            <artifactId>webmagic-core</artifactId>
            <version>0.7.3</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>us.codecraft</groupId>
            <artifactId>webmagic-extension</artifactId>
            <version>0.7.3</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-api</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.esotericsoftware</groupId>
            <artifactId>reflectasm</artifactId>
            <version>1.11.7</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
        </dependency>


代码架构


333.png


核心代码(以采集csdn为例)


创建CsdnArticleSpider类


/**
 * 爬虫默认实现
 * @author Kou Shenhai
 * @version 1.0
 * @date 2020/11/15 0015 下午 4:40
 */
@Configuration
@Slf4j
public class CsdnArticleSpider implements PageProcessor {
    private ProcessStrategy processStrategy;
    private static final int SLEEP_TIME = 3000;
    private static final int TIMEOUT = 3000;
    private static final int RETRY_TIMES = 10;
    private static final int RETRY_SLEEP_TIME = 3000;
    private static final String CHARSET = "utf-8";
    private static final String DOMAIN = "csdn.net";
    private static final String USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36";
    /**
     *
     * @param site 抓取网站的相关配置,包括编码、重试次数、抓取间隔
     */
    private Site site = Site
            .me()
            .setRetryTimes(RETRY_TIMES)
            .setRetrySleepTime(RETRY_SLEEP_TIME)
            .setDomain(DOMAIN)
            .setSleepTime(SLEEP_TIME)
            .setTimeOut(TIMEOUT)
            .setCharset(CHARSET)
            .setUserAgent(USER_AGENT)
            .addHeader("Cookie","");
    public void setProcessStrategy(ProcessStrategy processStrategy) {
        this.processStrategy = processStrategy;
    }
    /**
     *
     * @param page process是定制爬虫逻辑的核心接口,在这里编写抽取逻辑
     */
    @Override
    public void process(Page page) {
        if (processStrategy == null) {
            throw new NullPointerException();
        }
        /**
         * 开始
         */
        preProcess(page);
        //策略模式
        processStrategy.process(page);
        /**
         * 结束
         */
        afterProcess(page);
    }
    @Override
    public Site getSite() {
        return site;
    }
    public Spider getSpider() {
        return Spider.create(this);
    }
    /**
     * 下面两个方法用于扩展自定义的process方法,比如加入迭代url等等,主要逻辑放在processStategy
     */
    protected void preProcess(Page page) {
        log.info("开始爬取...");
    }
    protected void afterProcess(Page page) {
        log.info("完成爬取...");
    }
}


创建CsdnArticleHandler


/**
 * @author Kou Shenhai
 */
@Component
public class CsdnArticleHandler extends AbstractArticleHandler{
    @Autowired
    private CsdnArticleSpider csdnArticleSpider;
    @Autowired
    private ArticlePipeline articlePipeline;
    @Override
    protected ArticleTypeEnum getArticleTypeEnum() {
        return ArticleTypeEnum.CSDN;
    }
    @Autowired
    private PipelineObserver pipelineObserver;
    @Override
    @Async
    protected void articlePull(String[] uris) {
        HttpClientDownloader httpClientDownloader = new HttpClientDownloader();
        articlePipeline.addObserver(pipelineObserver);
        csdnArticleSpider.setProcessStrategy(new IteratorProcess(new CsdnArticleProcess()));
        csdnArticleSpider.getSpider().addUrl(uris)
                .setDownloader(httpClientDownloader)
                // 开启线程抓取
                .thread(2 * Runtime.getRuntime().availableProcessors())
                .addPipeline(articlePipeline)
                //启动爬虫
                .start();
    }
}


创建ArticlePipeline


public class ArticlePipeline implements CallablePipeline{
    private Vector<Observer> obs;
    public ArticlePipeline() {
        obs = new Vector<>(1);
    }
    @Override
    public void process(ResultItems resultItems, Task task) {
        notifyObservers(resultItems.getAll());
    }
    @Override
    public synchronized void addObserver(Observer o) {
        if (o == null) {
            throw new NullPointerException();
        }
        if (!obs.contains(o)) {
            obs.addElement(o);
        }
    }
    @Override
    public synchronized void notifyObservers(Object arg) {
        Object[] arrLocal;
        synchronized (this) {
            arrLocal = obs.toArray();
        }
        for (int i = arrLocal.length - 1; i >= 0; i--) {
            ((Observer)arrLocal[i]).update(this, arg);
        }
    }
    @Override
    public synchronized void deleteObserver(Observer o) {
        obs.removeElement(o);
    }
}


创建CsdnArticleProcess


/**
 *
 * @author Kou Shenhai
 * @version 1.0
 * @date 2021/4/24 0024 下午 4:05
 */
public class CsdnArticleProcess implements ProcessStrategy{
    @Override
    public void process(Page page) {
        String content = page.getHtml().xpath("//*[@id='mainBox']/main/div[1]/article").get();
        String title = page.getHtml().xpath("//*[@id='articleContentId']/text()").get();
        page.putField("content",content);
        page.putField("title",title);
    }
}


六、测试


数据采集运行概况


参考教程菜鸟教程-设计模式


参考教程webmagic文档


本项目仅作为技术学习研究使用,禁止用于任何商业用途,禁止任何损害网站利益的行为

本项目仅作为技术学习研究使用,禁止用于任何商业用途,禁止任何损害网站利益的行为

本项目仅作为技术学习研究使用,禁止用于任何商业用途,禁止任何损害网站利益的行为



目录
相关文章
|
1月前
|
敏捷开发 测试技术 持续交付
探索软件测试中的自动化与持续集成
在快速迭代的软件开发环境中,自动化测试和持续集成(CI)已成为确保产品质量和加速交付的关键策略。本文将深入探讨自动化测试的基本原理、实施步骤以及它如何与持续集成流程相结合,以提高软件开发的效率和可靠性。我们将通过实际案例分析,展示自动化测试和CI的最佳实践,以及它们如何帮助企业实现更快的市场响应时间和更高的客户满意度。
60 16
|
1月前
|
jenkins 测试技术 持续交付
软件测试中的自动化与持续集成:提升效率与质量的关键
在快节奏的软件开发环境中,自动化测试和持续集成已经成为不可或缺的部分。本文将探讨自动化测试和持续集成的重要性,以及它们如何协同工作以提高软件开发的效率和质量。通过分析自动化测试的策略、工具选择以及持续集成的实践,我们将揭示这些技术如何帮助开发团队快速响应变化,减少错误,并加速产品上市时间。
|
1月前
|
机器学习/深度学习 人工智能 jenkins
软件测试中的自动化与持续集成实践
在快速迭代的软件开发过程中,自动化测试和持续集成(CI)是确保代码质量和加速产品上市的关键。本文探讨了自动化测试的重要性、常见的自动化测试工具以及如何将自动化测试整合到持续集成流程中,以提高软件测试的效率和可靠性。通过案例分析,展示了自动化测试和持续集成在实际项目中的应用效果,并提供了实施建议。
|
9天前
|
机器学习/深度学习 人工智能 jenkins
探索软件测试中的自动化与持续集成
【10月更文挑战第21天】 在软件开发的生命周期中,软件测试扮演着至关重要的角色。随着技术的进步和开发模式的转变,自动化测试和持续集成已经成为提高软件质量和效率的关键手段。本文将深入探讨自动化测试和持续集成的概念、实施策略以及它们如何相互配合以优化软件开发流程。我们将通过分析实际案例,展示这些技术如何在实际项目中发挥作用,以及面临的挑战和解决方案。此外,文章还将讨论未来趋势,包括人工智能在测试领域的应用前景。
53 17
|
1月前
|
数据采集
使用 Puppeteer 绕过 Captcha:实现商家数据自动化采集
本文介绍了如何使用Puppeteer结合代理IP和用户伪装技术,轻松绕过大众点评的Captcha验证,实现商家信息的高效采集。通过配置Puppeteer、设置代理和用户伪装参数、模拟人类操作等步骤,成功提取了目标页面的数据。该方法不仅提高了爬虫的稳定性和隐蔽性,还为市场研究和商业分析提供了有力支持。注意,数据采集需遵守法律法规及网站政策。
使用 Puppeteer 绕过 Captcha:实现商家数据自动化采集
|
22天前
|
jenkins 测试技术 持续交付
软件测试中的自动化与持续集成
在现代软件开发过程中,自动化测试和持续集成已成为不可或缺的组成部分。本文将深入探讨自动化测试和持续集成的重要性、优势以及如何有效实施它们以提升软件质量和开发效率。通过具体案例分析,我们将展示这些技术如何在实际项目中发挥作用,并讨论其面临的挑战及应对策略。
45 3
|
1月前
|
jenkins 测试技术 持续交付
探索自动化测试在持续集成中的应用与挑战
本文深入探讨了自动化测试在现代软件开发流程,特别是持续集成(CI)环境中的关键作用。通过分析自动化测试的优势、实施策略以及面临的主要挑战,旨在为开发团队提供实用的指导和建议。文章不仅概述了自动化测试的基本原理和最佳实践,还详细讨论了如何克服实施过程中遇到的技术难题和管理障碍,以实现更高效、更可靠的软件交付。
|
29天前
|
jenkins 机器人 测试技术
自动化与持续集成
自动化和持续集成(CI)是现代软件开发的重要实践。自动化通过技术手段执行任务,减少人工干预,提升效率和质量。持续集成则强调频繁将代码变更集成至共享库,伴随自动化构建和测试,旨在早期发现问题,加速迭代,提高代码质量。常见CI工具有Jenkins、Travis CI等,支持多语言和框架,促进高效协作与快速反馈。
|
29天前
|
监控 安全 测试技术
在实施自动化和持续集成的过程中,如何确保代码的安全性和合规性
在自动化和持续集成中,确保代码安全与合规至关重要。措施包括集成自动化安全工具、执行自动化合规检查、进行代码质量与安全检测、评估开源代码安全、实施基础设施即代码的安全标准、采用多层防御策略、加强安全教育与文化建设、使用合规性检测工具及许可证合规分析等,共同提升代码安全性与合规水平。