WebMagic 入门
WebMagic 采用完全模块化的设计,有着强大的可扩展性,基于 HttpClient 和 Jsoup
核心简单但却涵盖了爬虫的全部流程。
有着丰富的页面抽取 API
支持多线程分布式,支持爬取动态 js
没有框架依赖
WebMagic 架构
WebMagic 框架包含四个组件,PageProcessor、Scheduler、Downloader 和 Pipeline。这四大组件对应爬虫生命周期中的处理、管理、下载和持久化等功能。
这四个组件都是 Spider 中的属性,爬虫框架通过 Spider 启动和管理。
- Downloader: 负责从互联网上下载页面,以便后续处理.一般无需自己实现
- Scheduler: 负责管理待抓取的 URL,以及一些去重工作.一般无需自己实现
- PageProcessor: 负责解析页面,抽取目标信息,以及发现新 URL,需要自定义
- Pipeline: 负责抽取结果的处理,包括计算,持久化等.
数据流转的对象
- Request: 是对 URL 地址的一层封装,一个 Request 对象对应一个 URL 地址
- Page: 代表了从 Downloader 下载到的一个页面,可能是 HTML 页面也可能是其他文本内容(XML,JSON)
- ResultItems: 相当于一个 MAP,保存了 PageProcessor 处理的结果,供 Pipeline 使用
简单实例
环境配置
maven 引入依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <dependency> <groupId>us.codecraft</groupId> <artifactId>webmagic-core</artifactId> <version>0.7.3</version> </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> </exclusions> </dependency>
|
Demo
在 WebMagic 中,实现爬虫只需要编写一个类,实现 PageProcessor 接口即可,这个类基本上包含了抓取一个网站,所需要写的所有代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public class TestPageProcessor implements PageProcessor {
private Site site = Site.me().setRetryTimes(3).setSleepTime(1000);
@Override public void process(Page page) { page.putField("author", page.getUrl().regex("https://github\\.com/(\\w+)/.*").toString()); page.putField("name", page.getHtml().xpath("//h1[@class='entry-title public']/strong/a/text()").toString()); if (page.getResultItems().get("name") == null) { page.setSkip(true); } page.putField("readme", page.getHtml().xpath("//div[@id='readme']/tidyText()"));
page.addTargetRequests(page.getHtml().links().regex("(https://github\\.com/[\\w\\-]+/[\\w\\-]+)").all()); }
@Override public Site getSite() { return site; }
public static void main(String[] args) { Spider.create(new TestPageProcessor()) .addUrl("https://github.com/code4craft") .thread(5) .run(); } }
|
注解模式开发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| @TargetUrl("https://github.com/\\w+/\\w+")
@HelpUrl("https://github.com/\\w+")
public class GithubRepo {
@ExtractBy(value = "//h1[@class='entry-title public']/strong/a/text()", notNull = true) private String name;
@ExtractByUrl("https://github\\.com/(\\w+)/.*") private String author;
@ExtractBy("//div[@id='readme']/tidyText()") private String readme;
public static void main(String[] args) { OOSpider.create(Site.me().setSleepTime(1000) , new ConsolePageModelPipeline(), GithubRepo.class) .addUrl("https://github.com/code4craft").thread(5).run(); } }
|
一个完整流程
编写爬虫
1 2 3 4 5 6 7 8 9 10 11 12 13
| @TargetUrl("https://github.com/\\w+/\\w+") @HelpUrl("https://github.com/\\w+") public class GithubRepo {
@ExtractBy(value = "//h1[@class='entry-title public']/strong/a/text()", notNull = true) private String name;
@ExtractByUrl("https://github\\.com/(\\w+)/.*") private String author;
@ExtractBy("//div[@id='readme']/tidyText()") private String readme; }
|
启动
1 2 3 4 5 6
| public static void main(String[] args) { OOSpider.create(Site.me().setSleepTime(1000) , new ConsolePageModelPipeline(), GithubRepo.class) .addUrl("https://github.com/code4craft").thread(5).run(); }
|
Anything can go right will go right