7

下一句在 Wget 的手册中引起了我的注意

wget --spider --force-html -i bookmarks.html

This feature needs much more work for Wget to get close to the functionality of real web spiders.

我发现以下与 wget 中的蜘蛛选项相关的代码行。

src/ftp.c
780:      /* If we're in spider mode, don't really retrieve anything.  The
784:      if (opt.spider)
889:  if (!(cmd & (DO_LIST | DO_RETR)) || (opt.spider && !(cmd & DO_LIST)))
1227:      if (!opt.spider)
1239:      if (!opt.spider)
1268:      else if (!opt.spider)
1827:          if (opt.htmlify && !opt.spider)

src/http.c
64:#include "spider.h"
2405:  /* Skip preliminary HEAD request if we're not in spider mode AND
2407:  if (!opt.spider
2428:      if (opt.spider && !got_head)
2456:      /* Default document type is empty.  However, if spider mode is
2570:           * spider mode.  */
2571:          else if (opt.spider)
2661:              if (opt.spider)

src/res.c
543:  int saved_sp_val = opt.spider;
548:  opt.spider       = false;
551:  opt.spider       = saved_sp_val;  

src/spider.c
1:/* Keep track of visited URLs in spider mode.
37:#include "spider.h"
49:spider_cleanup (void)

src/spider.h
1:/* Declarations for spider.c

src/recur.c
52:#include "spider.h"
279:      if (opt.spider)
366:              || opt.spider /* opt.recursive is implicitely true */
370:             (otherwise unneeded because of --spider or rejected by -R) 
375:                   (opt.spider ? "--spider" : 
378:                     (opt.delete_after || opt.spider
440:      if (opt.spider) 

src/options.h
62:  bool spider;           /* Is Wget in spider mode? */

src/init.c
238:  { "spider",           &opt.spider,            cmd_boolean },

src/main.c
56:#include "spider.h"
238:    { "spider", 0, OPT_BOOLEAN, "spider", -1 },
435:       --spider                  don't download anything.\n"),
1045:  if (opt.recursive && opt.spider)

我想看看代码的差异,而不是抽象的。我喜欢代码示例。

网络蜘蛛在代码中与 Wget 的蜘蛛有何不同?

4

4 回答 4

33

真正的蜘蛛需要大量的工作

为整个 WWW 编写蜘蛛是一项艰巨的任务 --- 你必须注意许多“小细节”,例如:

  • 每台蜘蛛计算机应该从几千台服务器并行接收数据,以有效利用连接带宽。(异步套接字 i/o)。
  • 您需要多台并行蜘蛛的计算机,以覆盖 WWW 上的大量信息(集群;划分工作)
  • 您需要对蜘蛛网站有礼貌:
    • 尊重 robots.txt 文件。
    • 不要太快地获取大量信息:这会使服务器过载。
    • 不要获取您真正不需要的文件(例如 iso 磁盘映像;用于软件下载的 tgz 包...)。
  • 您必须处理 cookie/会话 ID:许多站点将唯一的会话 ID 附加到 URL 以识别客户端会话。每次您到达该站点时,您都​​会获得一个新的会话 ID 和一个新的页面虚拟世界(具有相同的内容)。由于这些问题,早期的搜索引擎忽略了动态内容。现代搜索引擎已经了解了问题所在以及如何处理这些问题。
  • 您必须检测并忽略麻烦的数据:提供看似无限量数据的连接或太慢而无法完成的连接。
  • 除了以下链接之外,您可能还需要解析站点地图以获取页面的 URL。
  • 您可能想评估哪些信息对您很重要,哪些信息会经常更改以比其他页面更频繁地刷新。注意:整个 WWW 的蜘蛛会接收大量数据——您需要为带宽付费。您可能想使用 HTTP HEAD 请求来猜测页面是否已更改。
  • 除了接收之外,您还想处理信息并存储它。Google 建立索引,为每个单词列出包含它的页面。您可能需要单独的存储计算机和连接它们的基础设施。传统的关系数据库无法满足存储/索引整个 WWW 的数据量和性能要求。

这是很多工作。但是如果你的目标比阅读整个 WWW 更谦虚,你可能会跳过一些部分。如果您只是想下载 wiki 等的副本,请参阅 wget 的规范。

注意:如果您不相信它的工作量很大,您可能想了解 Google 如何重新发明大多数计算轮(在基本 Linux 内核之上)以构建好的蜘蛛。即使你偷工减料,也是很多工作。

让我在三点上添加一些技术性评论

并行连接/异步套接字通信

您可以在并行进程或线程中运行多个蜘蛛程序。但是您需要大约 5000-10000 个并行连接才能充分利用您的网络连接。而且这个数量的并行进程/线程会产生太多的开销。

更好的解决方案是异步输入/输出:在一个线程中处理大约 1000 个并行连接,方法是在非阻塞模式下打开套接字,并使用 epoll 或 select 来处理那些已经接收到数据的连接。自 Linux 内核 2.4 以来,Linux 对可扩展性的出色支持(我也建议您研究内存映射文件)在以后的版本中不断改进。

注意:使用异步 i/o 比使用“快速语言”更有帮助:最好为 1000 个用 Perl 编写的连接编写一个 epoll 驱动的进程,而不是运行用 C 编写的 1000 个进程。如果你做得对,你可以用 perl 编写的进程使 100Mb 连接饱和。

从最初的答案来看: 这种方法的缺点是您必须自己以异步形式实现 HTTP 规范(我不知道有一个可重用的库可以做到这一点)。使用更简单的 HTTP/1.0 协议比现代 HTTP/1.1 协议更容易做到这一点。无论如何,您可能不会从普通浏览器的 HTTP/1.1 的优势中受益,因此这可能是节省一些开发成本的好地方。

五年后编辑: 今天,有很多免费/开源技术可以帮助您完成这项工作。我个人喜欢node.js的异步http 实现--- 它为您节省了上面原始段落中提到的所有工作。当然,今天还有很多模块可供您在蜘蛛中需要的其他组件使用。但是请注意,第三方模块的质量可能会有很大差异。你必须检查你使用的任何东西。[老化信息:]最近,我使用 node.js 编写了一个爬虫,我发现用于链接和数据提取的 HTML 处理的 npm 模块的可靠性不足。对于这项工作,我将此处理“外包”给用另一种编程语言编写的流程。但是事情正在迅速变化,当您阅读此评论时,这个问题可能已经成为过去......

将工作分配到多台服务器上

一台计算机无法跟上整个 WWW 的蜘蛛网。您需要将您的工作分布在多个服务器上并在它们之间交换信息。我建议为每台服务器分配特定的“域名范围”:保留一个域名的中央数据库,并参考蜘蛛计算机。

从接收到的网页中批量提取URL:按照域名排序;删除重复项并将它们发送到负责的蜘蛛计算机。在该计算机上,保留已获取的 URL 的索引并获取剩余的 URL。

如果您在每台蜘蛛计算机上保留等待获取的 URL 队列,您将不会遇到性能瓶颈。但是要实现这一点需要大量的编程。

阅读标准

我提到了几个标准(HTTP/1.x、Robots.txt、Cookies)。花点时间阅读并实施它们。如果您只遵循您知道的网站示例,您将犯错误(忘记与您的示例无关的部分标准)并给使用这些附加功能的网站带来麻烦。

阅读 HTTP/1.1 标准文档很痛苦。但是所有的小细节都被添加到其中,因为有人真的需要这些小细节并且现在使用它。

于 2009-05-12T12:47:11.703 回答
4

我不确定评论的原作者到底指的是什么,但我可以猜到 wget 像蜘蛛一样慢,因为它似乎只使用一个执行线程(至少根据你所显示的)。

heritrix这样的“真实”蜘蛛使用大量并行性和技巧来优化它们的爬行速度,同时对它们正在爬行的网站也很友好。这通常意味着以每秒 1 次(左右)的速度限制对一个网站的点击,并同时抓取多个网站。

同样,这只是基于我对蜘蛛的一般了解以及您在此处发布的内容的猜测。

于 2009-04-17T21:34:40.207 回答
2

不幸的是,许多更知名的“真实”网络蜘蛛都是封闭源代码的,实际上是封闭的二进制文件。但是,wget 缺少许多基本技术:

  • 并行性;如果不一次检索多个页面,您将永远无法跟上整个网络的步伐
  • 优先级;某些页面对蜘蛛来说比其他页面更重要
  • 速率限制;如果您继续尽可能快地拉下页面,您将很快被禁止
  • 保存到本地文件系统以外的其他地方;网络足够大,它不适合单个目录树
  • 定期重新检查页面而不重新启动整个过程;在实践中,使用真正的蜘蛛,您会想要频繁地重新检查“重要”页面的更新,而不太有趣的页面可能会持续数月。

还可以使用各种其他输入,例如站点地图等。重点是,wget 的设计初衷不是为了爬取整个网络,而且它也不是一个可以在小代码示例中捕获的东西,因为它是使用整个技术的问题,而不是任何单个小子程序出错为任务。

于 2009-05-10T17:06:40.867 回答
1

我不会详细介绍如何爬取互联网,我认为 wget 评论是关于爬取一个网站,这仍然是一个严峻的挑战。

  • 作为蜘蛛,您需要弄清楚何时停止,而不是仅仅因为 URL 更改为 date=1/1/1900 到 1/2/1900 等而进行递归爬网
  • 解决 URL 重写的更大挑战(我不知道谷歌或任何其他人如何处理这个问题)。爬行足够但不是太多是相当大的挑战。以及如何通过一些随机参数和内容的随机变化自动识别 URL Rewrite?
  • 您至少需要在一定程度上解析 Flash / Javascript
  • 您需要考虑一些疯狂的 HTTP 问题,例如基本标记。考虑到大多数网站都不是 XHTML 并且浏览器的语法非常灵活,即使解析 HTML 也不容易。

我不知道在 wget 中实现或考虑了多少,但您可能想看看 httrack 以了解此任务的挑战。

我很乐意给你一些代码示例,但这是一项艰巨的任务,如果没有 3rd 方库,一个体面的蜘蛛将大约 5000 loc 。

+ 其中一些已经由@yaakov-belch 解释过,所以我不会再输入它们了

于 2009-05-13T20:09:51.310 回答