我正在用C#编写一个Web爬虫,供我个人使用。它的主要目的是从它抓取的网页下载图像。除了下载的图像,它不会保存网页上的任何数据。
我有一些逻辑可以在列表中存储抓取工具访问过的所有网址的文字字符串。这对于短爬行会话就足够了,但我想当爬虫在列有数万个URL的列表中进行查找时,这会在较长的会话中成为瓶颈。我也在我的URL队列中进行查找,以便在等待抓取的URL队列中没有重复的URL。
我的问题分为两部分:
1)目前我没有在抓取会话之间存储任何数据,现在这很好。当爬虫正在运行时,是否有更好的方法来存储已访问过的URL而不是简单的字符串列表?
2)如果我要开始在磁盘上永久存储数据以进行多个会话,那么在这种情况下你会建议如何存储访问过的URL?
答案 0 :(得分:3)
这在很大程度上取决于您的抓取工具的抓取速度。如果你有一个单线程爬虫,那么你平均不会比每秒一页更好。因此,您可以使用HashSet来存储您访问过的网址。或者,如果您要保存有关您访问过的网址的信息,可以使用Dictionary<string, UrlInfo>
,其中UrlInfo
是您定义的类,其中包含您要保留的有关每个访问过的网址的信息。
每天86,400秒,HashSet
或Dictionary
会存储相当多的数据。
但你可能不想多次下载同一张图片。所以你可能会更好地使用我称之为“离线”或“抓取 - 进程 - 爬行”的模型。这是它的工作原理。
当您开始抓取时,您会访问您已识别的几千页。您下载页面,提取链接,并将这些链接写入日志文件。如果找到图像,则下载并保存图像。您访问的每个页面也会写入文件。
完成访问这些页面后,您将停止抓取工具。您现在有两个保存在文件中的列表:您访问过的页面和您找到的链接。
对访问过的链接进行排序,并将它们与之前访问过的网页列表合并。随着时间的推移,该文件会变得相当大。
对提取的链接列表进行排序,然后删除重复项。然后根据您已访问过的页面列表检查这些链接。合并时这是最简单的。如果已访问该链接,请将其丢弃。否则,将其写入将在下一个抓取会话中使用的文件。
使用简单的数据库会更容易,但要注意数据库会变得非常大。使用数据库,您不必进行爬网进程爬网。相反,您可以检查针对数据库提取的每个链接,并立即保存或丢弃它。
但是要明白,你会很难打到数据库。我对抓取的经验是,平均而言,一个网页包含100多个链接(即<a href="...">
。这不包括图像。你将每秒至少100次点击该数据库单线程爬虫。
您将遇到的另一个问题是您无法访问找到的每个网址。随着时间的推移,我发现在我从平均网页中提取的100个链接中,有10个链接是我以前从未见过的新链接。因此,对于我阅读的每一页,我发现还有10页我还没读过。最终,您需要一些方法来过滤掉不太可能引导您进入图片的网址。
跟踪您访问过的网址的另一种可能性是使用Bloom Filter。我在网络爬虫中使用了这些效果。