记第一次读源代码 -- WebMagic

Summary

阅读了好久 webmagic-core 源码,总想写点什么。。。故在今终结之日(18/01/08),写个小结。
其实,此时又是新的开始~

从何写起?

一开始先介绍一下它的总体框架?我不想这么来,因为作者已经介绍了很清楚。所以,这里直接拿作者的一幅图来概述(更详细的信息可以去参考它的Github主页)。

image

那就先来总结一下我的阅读过程吧!这是我第一次阅读大型框架or系统源码,所以可能走了一些弯路。写于此,希望可以总结经验不断成长。

我大概是按照如下顺序来阅读的:
1. 始于 Spider.java奠定根基
2. 逐个击破各个模块,群雄逐鹿,一统天下
1. downloader
2. scheduler
3. selector
4. pipeline & processor
3. 归于 Spider.java蓦然回首

以上就是大概流程,下面开始稍微详细地回顾。

1. 奠定根基

  • 为何选择要起于 Spider.java

    前期,我使用 WebMagic 做过关于 知乎 的爬取。所以我大概知道了它的流程。之所以从它开始,因为 ++它是整个框架的入口++ 。

  • 这一阶段详细看了哪些,又屏蔽了哪些内容?

    在这个阶段我先是自己写了一个小的爬取案例,然后根据此案例顺藤摸瓜依次来分析 spider 以及与它相关的内容。现在感到这种方法虽然可以快速地入手,但是未免有点以偏概全的感觉(个人理解)。但是,这样做应该是正确的。

    于是,我先从它的 run() 方法开始,然后遇到了各种初始化,紧接着出现了处理过程,最后的出现很明显就是回收了。我记得在这个过程中我几乎每遇到一个方法(除那些该阶段要屏蔽的外)就详细阅读。若大概明白了就在方法上标注 OK ,若有歧义就会弄个 TODO 。现想起来这样做消耗了大量时间,可是当时并不知道其他的方法。。。

    至于此阶段着重的内容,我把 初始化 各个模块间的通信实体 部分回收 当作重点,而屏蔽了 各个模块间的具体实现 。说白了,就是看清它们的 input output。尽管这样,我还是遇到了很多的挑战。比如,未知实现过程就先去了解它们的通信,这往往需要大胆的猜测!!!

  • 这一阶段地收获有哪些?

    对我来使,这一阶段的最大收获就是找到了一个 BUG 。对没错就是一个 bug ,在我发现且经过反复的验证后,在第一个时间通过 issues 提交给了原作者。估计作者太忙了没有给回复,但是有几个网友确认了。我还是很激动的,尽管我给出的修复也被指出了问题( ̄□ ̄||)。

    至于,其他的收获大部分都是关于多线程的。但有种 似有若为 的感觉,希望就像”胖子”所说的那样:++这些都是潜移默化的!++

2. 群雄逐鹿

  • 听说你在与 downloader 争霸时差点 丧命

    你听谁说的(-_-||)!

    Downloader 是我进击的第一个模块,想必大家都能看出它的功能:下载指定页面。下载就要涉及网络、连接了。那么它是怎么实现的呢?通过 先锋官 的几次试探,不难发现它是借用的 httpClient 。既然这样,我便着手 httpClent 。因为知彼知己,方能百战不殆。但,接下来的事万万没想到~

    其实,一开始我想了好几种方案用于研究 HttpClient。但,最后我可能选择了最“浪”的一种(骄傲啦?),直接上官方文档让我来一探究竟。谁知,它是一本 天书 (鸟语性),慢慢品味吧。我愣是硬着头皮读了 20 多页,它介绍的是真的真的详细,部分内容我竟然完全看不懂。感觉自己的网络学的更 shit 一样。++幸好,大学还没结束,一定要补上!++ 唉,这不懂,那也不懂,放弃吧!很是纠结(ー`´ー)。。。

    想当初,一统天下的雄心哪去了?我不会把第一次读源码弄 流产 吧?不!对啊,我可以标 TODO 。于是,我忽略了 证书 SSL SOCKET & Connection pool,它们无伤大雅~~ 最终终于熬过来了。

    现在看来,这里收获颇多。比如,部分理解了 套接字编程 ,还发现了自己在网络方面的漏洞!

  • scheduler so-easy ?

    确实,scheduler 模块很简单,它主要依赖 blockingQueue 完成的。然后,贴一张类图就可以说清楚了。

    image

    虽然简单但是在这里我也有个发现。我通过结合 spiderdownloader 发现,初始化的线程数(也就是设置的并行爬虫数)与后面设置的连接池大小相同。这样设计是合理,一个爬虫正好可以得到一个连接。

  • selector 尽显(作者)英雄本色

    先贴上此部分的类图压压惊。

    image

    没错,就是如此庞大,完全展示了作者的综合实力。其实,此部分的类结构并不是很复杂,但是涉及面比较广。这部分作者使用了 fastJson jsonPath jsoup regex 基于行块分布函数的通用网页正文抽取算法,而且作者巧妙的把它们组合在一起,实现了 链式API。很佩服作者!

  • pipeline & processor 略施小计

    pipeline 定义了输出接口,并给出了几种实现。话不多说很简单。而 processor 只是定义了处理页面(包含 fetch url & save result),需要用户根据自己的爬取需求自定义,就更简单了。

    战事已尽,已近归期。

3. 蓦然回首

看一看我的最终布局(其实是在第一阶段画的,可能有点乱,后期太忙没画~)

image

回顾整个过程,大约有两三周,当然其中有很多时间忙于其他事务。现在一看,说简单也简单,现在可以大概的说明每个地方的功能;说复杂当然也很复杂,自己是不可能设计出来的!

第一次走的路,也不知道有哪些是弯路,期待下次起航!

最后,任重而道远! 还有就是胖子常说的 路漫漫其修远兮,吾将上下而求索