从之前的项目提取了个抓取的功能,稍微改了下放到 GitHub 上了。
说来惭愧学习 Ruby&Rails 差不多 9 年了(05 年开始应该,算业余爱好吧)还是第一次写 Gem。
这两个类用了挺久了,综合了自己的一些需求,满足个人大概 85% 以上的场景需求。
项目地址:
https://github.com/hjleochen/the_scrap
Why
网页数据的抓取最基本的工作流程为:
- 确定要抓取的起始 URL,如:https://ruby-china.org/topics
- 抓取列表信息,一般列表信息按照 tr,li,div,dd 等呈现,每个节点为一条记录,如:上述 URL 中的 CSS Selector 为:".topics .topic"
- 提取记录的相关信息,标题,作者,分类,详细页面的 URL 等。
- 抓取详细页面信息,一般列表只有部分信息,完整获取需要进入详细页面进行数据提取。
- 数据源有分页的情况还需要循环抓取多页信息。
- 数据加工。
- 数据入库或输出,排重处理等。
在处理以上任务是往往会遇到如下问题:
- 源 HTML 无法直接使用,需要进行一些处理
- 抓取的条目需要过滤无效数据。
- 需要对抓取的各种 URL 进行处理,如:链接或者图片往往不是完整的 URL,需要通过当前页面地址进行合并处理。
- 提取的数据需要进行特殊处理。还是 RubyChina 的例子比如帖子阅读次数:".info leader" 下的内容为: "· 618 次阅读",需要的只是:618
- 每个网站都有不同的分页机制,和分页 URL 的规则,处理起来相当麻烦。
- 输出过程往往需要将之前提取的单个信息组合成一个对象或者 Hash 等。
很久之前使用 Perl 进行数据抓取,由于个人 Perl 水平问题和语言上的一些限制,处理起来偏麻烦。后来用了很多 Ruby 写的框架都不是很满意 (Scrubyt 应该是我用过的比较不错的一个)
故根据实际需要慢慢总结形成了现在的方式:
- 定义列表和详细页面抓取规则
- 需要提取的信息和提取规则通过 Method missing 方式存入 Hash 中。
- 规则可以根据需要提取不同属性和数据,Link 的 href 和 IMG 的 src 自动进行 URI.join(current_url) 处理
- 实现列表多个节点的 Join 或者返回 Array,如 tags。
- 实现多种分页方式支持。
- 自动通过抓取列表数据取得的详细页面地址抓取详细信息,并合并到同一个结果记录中。
- 抓取的结果为一个 Hash,适当定义名称可以直接使用各种 ORMapping 实现进行入库,无需重新组装。
- 使用 Ruby 的 lambda 实现 Html 处理、数据过滤、结果处理等,自定义程度和适应性有所提高 (以上内容属于自我感觉良好,请自动忽略)。
之前写 READMD.md 的时候就觉得这么简单的两个类写清楚还挺麻烦的,一直没写完整。
听从 @huacnlee 的意见完善了下文档。