- 1. WebMagic 概览
- 1.1 设计思想
- 1.2 总体架构
- 1.3 项目组成
- 2. 快速开始
- 2.1 使用Maven
- 2.2 不使用Maven
- 2.3 第一个爬虫项目
- 3. 下载和编译源码
- 3.1 下载源码
- 3.2 导入项目
- 3.3 编译和执行源码
- 4. 编写基本的爬虫
- 4.1 实现 PageProcessor
- 4.2 使用 Selectable 抽取元素
- 4.3 使用Pipeline保存结果
- 4.4 爬虫的配置、启动和终止
- 4.5 Jsoup与Xsoup
- 4.6 爬虫的监控
- 4.7 配置代理
- 4.8 处理非 HTTP GET 请求
- 5. 使用注解编写爬虫
- 5.1 编写Model类
- 5.2 TargetUrl与HelpUrl
- 5.3 使用ExtractBy进行抽取
- 5.4 在类上使用ExtractBy
- 5.5 结果的类型转换
- 5.6 一个完整的流程
- 5.7 AfterExtractor
- 6. 组件的使用和定制
- 6.1 使用和定制 Pipeline
- 6.2 使用和定制 Scheduler
- 6.3 使用和定制 Downloader
- 附录:实例分析
- 列表 + 详情的基本页面组合
- 抓取前端渲染的页面
列表 + 详情的基本页面组合
我们先从一个最简单的例子入手。这个例子里,我们有一个列表页,这个列表页以分页的形式展现,我们可以遍历这些分页找到所有目标页面。
1 示例介绍
这里我们以作者的新浪博客 http://blog.sina.com.cn/flashsword20 作为例子。在这个例子里,我们要从最终的博客文章页面,抓取博客的标题、内容、日期等信息,也要从列表页抓取博客的链接等信息,从而获取这个博客的所有文章。
- 列表页的格式是 http://blog.sina.com.cn/s/articlelist_1487828712_0_1.html ,其中 0_1 中的 1 是可变的页数。
- 文章页的格式是 http://blog.sina.com.cn/s/blog_58ae76e80100g8au.html ,其中 58ae76e80100g8au 是可变的字符。
2 发现文章 URL
在这个爬虫需求中,文章 URL 是我们最终关心的,所以如何发现这个博客中所有的文章地址,是爬虫的第一步。
我们可以使用正则表达式 http://blog\\.sina\\.com\\.cn/s/blog_\\w+\\.html
对 URL 进行一次粗略过滤。这里比较复杂的是,这个 URL 过于宽泛,可能会抓取到其他博客的信息,所以我们必须从列表页中指定的区域获取 URL。
在这里,我们使用 xpath //div[@class=\\"articleList\\"]
选中所有区域,再使用 links() 或者 xpath //a/@href
获取所有链接,最后再使用正则表达式 http://blog\\.sina\\.com\\.cn/s/blog_\\w+\\.html
,对 URL 进行过滤,去掉一些“编辑”或者“更多”之类的链接。于是,我们可以这样写:
page.addTargetRequests(page.getHtml().xpath("//div[@class=\"articleList\"]").links().regex("http://blog\\.sina\\.com\\.cn/s/blog_\\w+\\.html").all());
同时,我们需要把所有找到的列表页也加到待下载的 URL 中去:
page.addTargetRequests(page.getHtml().links().regex("http://blog\\.sina\\.com\\.cn/s/articlelist_1487828712_0_\\d+\\.html").all());
3 抽取内容
文章页面信息的抽取是比较简单的,写好对应的 xpath 抽取表达式就可以了。
page.putField("title", page.getHtml().xpath("//div[@class='articalTitle']/h2"));
page.putField("content", page.getHtml().xpath("//div[@id='articlebody']//div[@class='articalContent']"));
page.putField("date",
page.getHtml().xpath("//div[@id='articlebody']//span[@class='time SG_txtc']").regex("\\((.*)\\)"));
4 区分列表和目标页
现在,我们已经定义了对列表和目标页进行处理的方式,现在我们需要在处理时对他们进行区分。在这个例子中,区分方式很简单,因为列表页和目标页在 URL 格式上是不同的,所以直接用 URL 区分就可以了!
//列表页
if (page.getUrl().regex(URL_LIST).match()) {
page.addTargetRequests(page.getHtml().xpath("//div[@class=\"articleList\"]").links().regex(URL_POST).all());
page.addTargetRequests(page.getHtml().links().regex(URL_LIST).all());
//文章页
} else {
page.putField("title", page.getHtml().xpath("//div[@class='articalTitle']/h2"));
page.putField("content", page.getHtml().xpath("//div[@id='articlebody']//div[@class='articalContent']"));
page.putField("date",
page.getHtml().xpath("//div[@id='articlebody']//span[@class='time SG_txtc']").regex("\\((.*)\\)"));
}
这个例子完整的代码请看 SinaBlogProcessor.java 。
5 总结
在这个例子中,我们的主要使用几个方法:
- 从页面指定位置发现链接,使用正则表达式来过滤链接.
- 在 PageProcessor 中处理两种页面,根据页面 URL 来区分需要如何处理。
有些朋友反应,用 if-else 来区分不同处理有些不方便 #issue83 。WebMagic 计划在将来的 0.5.0 版本中,加入 SubPageProcessor
来解决这个问题。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论