构建一个高性能现代网络爬虫
PS:本文为Building a fast modern web crawker的中文译文。
我一直对于爬虫具有很强烈的兴趣。我曾经使用过多种语言比如C++,Node.JS,Python等等来撰写爬虫程序,并且更吸引我的是爬虫背后的理论。
但是首先我们要讨论的问题是:什么是爬虫?
什么是爬虫?
爬虫是一个通过浏览整个因特网从而去定位一些存在的页面、图片、PDF等等的计算机程序,并且允许用户去通过一个搜索引擎去检索它们。这就是隐藏在著名的Google搜索引擎背后的技术。
一个高性能的爬虫程序通常被设计为分布式结构:区别于运行在特定机器上的单个程序,它会在云上的多台机器上运行多个实例,这样的结构带来更好的任务再分配、更好的性能和更大的带宽。(ps:这里使用吞吐量会不会更合适?)
但是分布式软件并不是没有瑕疵的:一些因素可能会给你的的程序带来额外的延迟、或者可能会降低你的程序的性能,比如说网络的延迟、同步的问题、缺乏设计的通信协议等等。
为了追求更好的性能,一个分布式的爬虫应该有足够良好的设计:这让消除许多性能上的瓶颈成为可能,就像法国的海军上将Olivier Lajous说的:
一个链子的强度取决于最薄弱的一环。
Trandoshan:一个暗网爬虫
你可能知道很多非常成功的网络爬虫,比如Google。所以我并不想去做一个同样的东西。我当下想要去构建一个基于暗网的爬虫。(ps:trandoshan是星球大战中的狩猎种族)
什么是暗网?
没必要去使用很多术语去形容什么是暗网,要写起暗网的来龙去脉可能要新建一篇文章。
Web是由三层结构组成的,我们可以将其视为一座冰山:
- 第一层:表面网络,或者说是净网是我们每天最常接触的网络的那部分。它们被一些炙手可热的网络爬虫比如Google,Qwant,Duckduckgo等等所定位。
- 第二层:更深层次的网络,是由一些无法被定位的网页组成的,这意味着你是用搜索引擎都找不到这些网页,但是你却可以直接使用URL和IP地址来访问这些页面。
- 第三层:暗网,这是一类你是用浏览器都无法访问到的网页。你需要使用特定的应用程序或者特定的代理才可以访问。最出名的暗网是隐藏在洋葱头网络下的。你可以使用以.onion结尾的URL去访问它们。
Trandoshan是如何设计的?
在分别讲解这些进程的作用之前,我觉得首先要讲清楚的是这些进程之间如何通信。
进程间通讯(Inter Process Communication, IPC),主要是通过使用一个基于生产者/消费者模式的名为NATS(图中黄色的线)的通讯协议,每个在NATS中的消息都有一个主题(就像邮件里的那样),支持其他进程去识别并且仅读取它们想要读取的消息。NATS支持扩展:比如可以支持十个爬虫进程从一个消息服务器并发的读取消息(许多实例可以同时运行而不出任何bug)并因此可以提升性能。
Trandoshan分为四个主要的进程:
- 爬虫:用于爬取页面的进程:它们从NATS读取将要爬取的页面的URL(消息的主题是"todoUrls"),爬取它,并且获取整个页面中显示的全部URL,并且发送这些URL到NATS中(这些消息的主题是"crawledUrls"),而页面的内容则以主题"content"发送到NATS。
- 调度器:这个进程用于检查URL:它读取主题为"crawledUrls",检查其是否是已经爬取过的URL,如果还没有被爬取过,则将URL以主题"todoUrls"发送到NATS。
- 持久器:这个进程用于网页内容的构建:它读取以"content"为主题的消息,并且存储到非关系型数据库中(MongoDB)
- 接口:给其他进程开放用于聚合数据的进程。比如开放给调度器的用于确定URL是否被爬取过的接口,相比于调度器直接和数据库进行交互,更倾向于调度器和API们交互。
不同的进程们都是使用Go语言进行编写的:因为它的性能很好(可以被编译为二进制文件)并且有很多的库。Go是用来构建高性能的分布式系统的完美解决方案。
Trandoshan的源码在github的这里:https://github.com/trandoshan-io
怎么运行Trandoshan?
就像之前讲过的一样,Trandoshan被设计为运行在一个分布式的系统上,并且可以使用Docker的镜像来运行,这对于云来说是很好的支持。事实上我整理了一个存储着所有部署需要的配置文件的仓库,可以用于部署Trandoshan实例在K8S上。这些文件在这里:https://github.com/trandoshan-io/k8s 并且docker的镜像也都上传到了Docker Hub。
如果你拥有一个配置成功的kubectl(K8S的控制程序),你可以通过一条简单的命令部署Trandoshan:
./bootstrap.sh
不然的话你可以使用Docker和docker-compose在本地运行Trandoshan。在trandoshan-parent这个仓库中有构建文件和shell脚本,所以你可以使用以下命令来运行这个应用:
./deploy.sh
如何使用Trandoshan?
现在有一个小型的Angular应用去检索定位内容。这个页面使用了API进程去完成对于数据库的检索工作。