设计分布式网络抓取工具

时间:2016-01-31 12:58:27

标签: amazon-web-services cloud distributed-computing

问题

最近,我一直在考虑如何抓取某个大型跨国网站的内容,以获取有关该公司销售产品的具体细节。该网站没有API,但您可以通过向产品ID发送带有特定URL的GET请求,为每个产品下载一些XML。至少那是什么。

问题在于可能存在数亿个潜在的产品ID(例如,在000000001和500000000之间),但实际上只存在几十万个产品。并且无法知道哪些产品ID有效。

方便地,根据产品ID是否有效(即产品实际存在),向产品URL发送HEAD请求会产生不同的响应。一旦我们知道该产品确实存在,我们就可以下载完整的XML并抓取所需的数据。

如果要在单个服务器上运行,显然发送数亿个HEAD请求将需要花费大量时间才能完成,所以我想借此机会学习如何开发某种分布式应用程序(对我来说是全新的领域)。此时,我应该提一下,这个特定的网站可以轻松处理每秒大量的传入请求,而不会有DOS的风险。我不想为网站命名,但每天很容易获得数百万次点击。这种刮刀对网站的性能影响微乎其微。但是,如果公司抱怨,我会立即停止它。

设计

我不知道这是否是正确的方法,但我目前的想法是启动单个"协调服务器",以及一些节点与该服务器通信并执行抓取,所有运行作为EC2实例。

每个节点将启动一些进程,并且协调服务器将每个进程指定一个作业,该协调服务器包含要刮取的不同范围的潜在产品ID(例如,产品ID 00001到10000)。这些作业将存储在协调服务器上的数据库表中。每项工作都将包含以下信息:

  • 产品ID起始编号
  • 产品ID结束编号
  • 工作状态(空闲,进行中,完成,已过期)
  • 工作到期时间
  • 时间开始
  • 时间已完成

启动节点时,将向协调服务器发送查询,询问某些配置数据以及要处理的作业。当节点完成作业时,将发送一个查询,更新刚刚完成的作业的状态,以及另一个请求新作业处理的查询。每个作业都有一个到期时间,因此如果进程崩溃,或者节点因任何原因失败,另一个节点可以接管过期作业再次尝试。

为了最大限度地提高系统性能,我需要确定应该一次启动多少个节点,每个节点有多少个进程,发送的HTTP请求速率以及哪个EC2实例类型将提供最物超所值(我猜测高网络性能,高CPU性能和高磁盘I / O将是关键因素?)。

目前,计划是在Python中编写刮刀,在Ubuntu EC2实例上运行,可能在Docker容器中启动,以及某种键值存储数据库来保存协调服务器上的作业(MongoDB?) 。关系数据库也应该可以工作,因为作业表应该是相当低的I / O.

我很想知道更有经验的工程师是否这是正确的方法,或者我是否完全忽略了更好的方法来完成这项任务?

非常感谢,谢谢!

1 个答案:

答案 0 :(得分:3)

您正在尝试设计一个分布式工作流程系统,这实际上是一个已解决的问题。我建议您不要重新发明轮子,而是查看AWS的SWF,它可以轻松地为您完成所有状态管理,让您可以自由地担心编写业务逻辑。

这是使用SWF设计的系统的样子(在这里,我将使用SWF的标准术语 - 您可能需要通过文档来完全理解这些术语):

  • productID开始一个工作流程。
  • 第一个活动将通过提出您提到的HEAD请求来检查此productID是否有效。
  • 如果不是,请终止工作流程。否则,第二个活动将通过发出必要的GET请求来获取相关的XML内容,并在S3中保留它。
  • 第三个活动将获取S3文件,抓取XML数据并对其执行任何操作。

您可以轻松更改上述设计,让一个工作流程处理一批产品ID。

我建议你记住一些其他观点:

  • 了解抓取和抓取之间的区别:抓取意味着从网站抓取相关内容,抓取意味着从中提取必要的数据。
  • 确保您所做的事情是严格合法的!
  • 请勿过度使用网站,否则可能会将您的IP范围列入黑名单。您有两种选择:
    • 在两次抓取之间添加延迟。这也可以在SWF中轻松实现。
    • 使用匿名代理。
  • 不要过多依赖某些未记录的API的XML结果,因为它可以随时更改。
  • 您需要高网络性能的EC2实例。我不认为高CPU或内存性能对你很重要。