抓取 500 万个网页的最有效(时间、成本)方式?

sam*_*sam 8 scraping amazon-ec2

我有一个需要抓取、解析然后将结果数据存储在数据库中的网页列表。总数约为 5,000,000。

我目前对解决此问题的最佳方法的假设是部署约 100 个 EC2 实例,为每个实例提供 50,000 个页面进行抓取,然后让它继续运行,然后在该过程完成后将数据库合并在一起。假设运行大约需要一天时间(加载、解析和保存每个页面需要 600 毫秒)。

有没有人有在有限的时间内完成如此大量页面抓取的经验?我以前做过大数字(1.5m),但那是从一台机器上完成的,只花了一个多星期才完成。

我的情况的瓶颈是页面的下载,解析时间不超过 2 毫秒,所以可以简化页面下载过程的东西就是我正在寻找的。

cyb*_*x86 7

假设下载时间(因此带宽使用)是您的限制因素,我会提出以下建议:

首先,选择 m1.large 实例。在 I/O 性能的三个“级别”(包括带宽)中,m1.large 和 m1.xlarge 实例都提供“高”I/O 性能。由于您的任务不受 CPU 限制,因此其中最便宜的将是首选。

其次,您的实例的下载速度将远远快于任何站点可以提供页面的速度 - 不要在给定实例上一次下载一个页面,同时运行任务 - 您应该能够同时执行至少 20 个页面(尽管,我猜你可以毫无困难地做 50-100 次)。(以从您的评论中的论坛下载为例 - 这是一个动态页面,需要服务器时间来生成 - 还有其他用户使用该站点的带宽等)。继续增加并发,直到达到实例带宽的限制。(当然,不要同时向同一个站点发出多个请求)。

如果您真的想最大限度地提高性能,您可以考虑在地理位置合适的区域启动实例以最大限度地减少延迟(但这需要对所有 URL 进行地理定位,这可能不切实际)。

需要注意的一件事是实例带宽是可变的,有时您会获得更高的性能,而有时您将获得更低的性能。在较小的实例上,性能的变化更为显着,因为物理链接由更多服务器共享,其中任何一个都可能减少您的可用带宽。在 m1.large 实例之间,在 EC2 网络(同一可用区)内,您应该获得接近理论千兆位吞吐量。

一般来说,使用 AWS 时,使用较大的实例几乎总是比使用多个较小的实例更有效(除非您特别关注诸如故障转移等需要多个实例的情况)。

我不知道你的设置需要什么,但是当我之前尝试过这个(1 到 200 万个链接,定期更新)时,我的方法是维护一个链接数据库,在发现新链接时添加新链接,并分叉过程抓取和解析页面。将检索(随机)一个 URL 并在数据库中标记为进行中,脚本将下载页面,如果成功,将 url 标记为在数据库中下载并将内容发送到另一个解析页面的脚本,新链接被发现时被添加到数据库中。这里数据库的优势是集中化——多个脚本可以同时查询数据库,并且(只要事务是原子的)可以确保每个页面只会被下载一次。

需要额外提及的几点 - 您一次可以运行的按需实例的数量有限制(我认为是 20 个) - 如果您计划超过这些限制,您将需要请求 AWS 增加您账户的限制。运行 Spot 实例并在 Spot 价格较低时扩大数量(可能是一个按需实例以保持一切井井有条,其余的 Spot 实例)对您来说会更经济。

如果时间对您来说比成本更重要,集群计算实例提供 10Gbps 带宽 - 并且应该产生最大的下载带宽。

总结:尝试几个大实例(而不是许多小实例)并在每个实例上运行多个并发下载 - 如果您发现带宽有限,请添加更多实例,如果您发现 CPU/内存受限,请移至更大的实例。