Veiking百草园


老狗啃爬虫-小爬虫初长成之PageProcessor

老狗啃骨头   @Veiking   2020-12-02

老狗啃爬虫-小爬虫初长成之PageProcessor

摘要:

WebMagic是一个简单灵活的Java爬虫框架。其简单的API,容易上手,模块化的结构,便于轻松扩展;同时也功能完备,且提供多线程和分布式支持。基于WebMagic,我们可以快速开发出一个高效、易维护的爬虫。WebMagic框架主要由Downloader、PageProcessor、Scheduler、Pipeline四大组件组成

WebMagic初探

  WebMagic是一个简单灵活的Java爬虫框架。其简单的API,容易上手,模块化的结构,便于轻松扩展;同时也功能完备,且提供多线程和分布式支持。基于WebMagic,我们可以快速开发出一个高效、易维护的爬虫
  WebMagic框架主要由DownloaderPageProcessorSchedulerPipeline四大组件组成,并由Spider提供组织联系与功能整合,其大概的工作流程如下图所示:



  其中,Downloader负责从互联网上下载页面,以便后续处理;PageProcessor负责解析页面,抽取有用信息,以及发现新的链接等Scheduler负责管理待抓取的URL,以及一些去重的工作Pipeline负责抽取结果的处理,包括计算、持久化到文件、数据库等。
  在实现爬虫的过程中,我们主要的工作是针对不同网站不同页面,来实现我们自己的PageProcessor;然后再通过对Pipeline的定制,来实现我们最终的数据抓取、处理、保存工作。
  Spider是WebMagic整个工作流程的核心中枢,负责将这些工作穿连起来。我们下面就针对PageProcessor进行开发,实现一个简单的测试案例。

一个简单的小爬虫

  我们从『爱古风』网站找了一个页面,内容是介绍先秦爱国大学者屈原的,我们准备用程序抓取它页面上的标题、人物头像地址、人物简介这三个内容:



  首先,我们在包路径cn.veiking下新建个叫processor的新包,然后创建名为SpiderLarvaProcessor的java文件,我们来尝试实现WebMagic的PageProcessor,代码如下:

package cn.veiking.processor;

import org.springframework.stereotype.Component;
import cn.veiking.base.common.logs.SimLogger;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.processor.PageProcessor;

/**
* @author    :Veiking
* @version    :2020年12月1日
* 说明        :蜘蛛幼儿,初写测试
*/
@Component
public class SpiderLarvaProcessor implements PageProcessor {
    SimLogger logger = new SimLogger(this.getClass());
    @Override
    public Site getSite() {
        Site site = Site.me().setRetryTimes(5).setSleepTime(1000).setTimeOut(10000);
        return site;
    }
    // 重写process,获取title、authorImg、content 三数据
    @Override
    public void process(Page page) {
        String title = page.getHtml().xpath("//*[@id=\"content\"]/div/div[1]/div[2]/div[1]/h1/a/text()").get();
        String authorImg = page.getHtml().xpath("//*[@id=\"content\"]/div/div[1]/div[2]/div[1]/a/img/@src").toString();
        String content = page.getHtml().xpath("//*[@id=\"icontentContent\"]/text()").toString();

        logger.info("AigufengCelebrityProcessor getAigufengCelebrity[title={}, authorImg={}, content={},]", title, authorImg, content);
    }
}

  我们需要留意,在这个重写的方法process里,我们用了三个变量,title、authorImg、content来承接我们从页面上抓取到的对应的值,并用日志的形式打印了出来。
  其中,注意这个xpath()方法,Xpath是一种用于xml、html等脚本文件定位元素信息的解释语言,我们在目标页面上抓取我们想要的信息,借助的就是这种技术运用,随后我们单另拿出来详细的说一说。
  这个是主要的功能代码,接下来我们看看怎么将他运行起来。
  一般来说,程序写到上面这个程度,我们需要做简单测试的时候,只需写一个main方法即可,但这里不准备这么做,因为之后一系列代码,很多地方我们都想用spring注解的方式进行,我们还准备将整个程序注册成springboot的微服务节点,以供管理中枢调用;设想最后这些实验代码,适当的做些修改,我们就可以直接用于实际应用。所以我们尽可能的模拟spring容器实际运行的方式,这里我们指定测试方式,都将基于junit这个单元测试框架进行。
  于是,我们就在src/test/java的文件路径下,创建与src/main/java对应的包,然后在包路径cn.veiking.processor下,创建我们的测试入口SpiderLarvaTest,代码如下:

package cn.veiking.processor;

import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import cn.veiking.StartTest;
import cn.veiking.base.common.logs.SimLogger;
import cn.veiking.processor.SpiderLarvaProcessor;
import us.codecraft.webmagic.Spider;

/**
* @author    :Veiking
* @version    :2020年12月1日
* 说明        :SpiderLarvaProcessor 测试
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = StartTest.class)
public class SpiderLarvaTest {
    SimLogger logger = new SimLogger(this.getClass());

    @Autowired
    private SpiderLarvaProcessor spiderLarvaProcessor;

    private static final String url = "http://www.aigufeng.com/celebrity/article-1000056/page.html";

    @Test
    public void testSpider() {
        long startTime, endTime;
        logger.info("SpiderLarvaTest testSpider [start={}] ", "开始爬取数据");
        startTime = System.currentTimeMillis();
        Spider.create(spiderLarvaProcessor).addUrl(url).thread(3).run();
        endTime = System.currentTimeMillis();
        logger.info("SpiderLarvaTest testSpider [end={}] ", "爬取结束,耗时约" + ((endTime - startTime) / 1000) + "秒");
    }
}

  注意这里,如果我们想顺利的启动运行,测试时就必须得创建所需的启动类,并在启动文件类这里做一个扫描动作

package cn.veiking;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

/**
* @author    :Veiking
* @version    :2020年11月30日
* 说明        :测试启动入口
*/
@SpringBootApplication
//开启通用注解扫描

@MapperScan(value = {"cn.veiking.biz.dao"})
@ComponentScan(value = {"cn.veiking.processor"})
public class StartTest {
    public static void main(String[] args) {
        SpringApplication.run(StartTest.class, args);
    }
}

  特别注意:@ComponentScan(value = {“cn.veiking.processor”})
  这行代码即表示,在程序启动的时候,程序会扫描这个包路径,将包内的类注册到spring容器内,这样我们就可以通过@Autowired标签,直接将类实例化使用。
  关于spring框架的注解式开发,这里要额外啰嗦一下,注解式开发摈弃了spring原来高度依赖的xml配置形式,理论上的优劣咱不扯,但在实际开发过程中,操作更为灵活,代码统一性更好。其实早些年写个类实现个功能,就去xml做同步的添加修改,也是挺让人崩溃的,这样说吧,注解式是历史的必然选择,哈哈哈。

  好了,测试入口准备好了,我们测试用例右键Run As(运行)->Junit Test,执行之后…报错:



  Caused by: java.lang.ClassNotFoundException: org.junit.platform.launcher.core.LauncherFactory
  大事不妙,明显缺包,无法支持测试,根据关键信息词:junit.platform.launcher,我们赶紧去搜一个,加上:

    <dependency>
        <groupId>org.junit.platform</groupId>
        <artifactId>junit-platform-launcher</artifactId>
        <scope>test</scope>
    </dependency>

  然后更新(maven->update)项目,再尝试运行,OK,Junit框显示条绿色通过,我们再看Console打印的日志信息:



  我们看到,已经打印出来预期的信息了,页面抓取完成,测试OK!
  以上,就是一个简单爬虫的实现过程。

结语

  最后要留意的是,我们获取页面信息的时候,用的这个xpath()方法,这个路径参数,可能会让一些新手比较蒙,这个是xpath语言,是用来在 XML、HTML文档中定位查找信息用的。
  我们在获取这个xpath路径的时候,需要在浏览器里打开调试(按F12键),找到我们需要的数据块处,右键如下:



  这样我们就可以获取这个xpath路径。
  通过上面的代码我们可以看到,PageProcessor的主要工作就是对页面HTML进行数据的解析提取,关于解析,我们就要知道一些开发爬虫关于HTML解析必需的基础知识,接下来我们整理梳理下这些东西。


老狗啃骨头



慷慨发言

(您提供的信息将用于后续必要的反馈联系,本站会恪守隐私)

潜影拾光

陌道向南天

此海之南,有一个美丽的地方,叫台湾。

扫码转发

二维码
二维码
二维码
二维码
二维码
二维码

博文标签