C# 网络爬虫优化
本文关键字:优化 爬虫 网络 | 更新日期: 2023-09-27 18:36:18
我用C#编写了Webcrawles,它使用多线程。目前它可以下载和解析大约 1000 个链接/分钟,但是当我同时运行 3 个实例时,每个实例可以达到 1000 个链接/分钟,所以我有 3000 个链接/分钟。一个实例最多使用 2% 的 CPU、100MB 的 RAM 和 1% 的网络速度。现在我想知道当我有可用的资源(cpu、ram、网络)时,一个实例是否可以达到 3000 个链接/分钟或更多?
我的代码结构:
ThreadSafeFileBuffer<string> successWriter = new ThreadSafeFileBuffer<string>("ok.txt");
IEnumerable<string> lines = File.ReadLines("urls.txt");
var options = new ParallelOptions
{
CancellationToken = _cts.Token,
MaxDegreeOfParallelism = 500
};
Parallel.ForEach(lines, options, (line, loopState, idx) =>
{
var crawler = new Crawler(line);
var result = crawler.Go(); //download,parse
successWriter.AddResult(result);
}
我有视窗7,中央处理器i7,16GB内存,SSD磁盘
上使用 Parallel.ForEach
的问题在于,这些列表通常包含来自同一站点的许多 URL,并且您最终会向同一站点发出多个并发请求。一些网站对此不屑一顾,会阻止您或插入人为的延迟。
每分钟 1,000 个请求相当于每秒 16 或 17 个请求,这几乎是您在不采取特殊措施的情况下可以做到的极限。问题的很大一部分是DNS解析,这可能需要很长时间。此外,默认的 .NET ServicePointManager
将任何给定站点上的并发请求限制为 2 个。如果要支持更多内容,则需要更改 ServicePointManager.DefaultConnectionLimit 属性。
您绝对不想添加数百个线程。我做过一次。这很痛苦。您需要的是一些可以非常快速地发出异步请求的线程。我的测试表明,单个线程每秒不能承受超过 15 个请求,因为 HttpRequest.BeginGetResponse 在异步之前会执行大量同步工作。如文档所述:
在此方法变为异步之前,BeginGetResponse 方法需要完成一些同步安装任务(例如,DNS 解析、代理检测和 TCP 套接字连接)。
您可以通过增加 DNS 客户端缓存的大小并在单独的计算机上拥有本地 DNS 缓存来加快速度,但您可以在那里实现的内容是有限的。
我不知道你在做多少爬行。如果你做了很多事情,那么你需要实施一个礼貌政策,考虑到机器人.txt文件,限制它访问特定网站的频率,限制它下载的URL类型(例如,如果你不能对它做任何事情,下载MP3或.doc文件就没有用)等。为了防止您的爬虫被阻止,您的爬虫的核心是礼貌策略执行器,恰好下载网页。
我开始写这个,但后来没有完成(其他项目优先)。请参阅 http://blog.mischel.com/2011/12/13/writing-a-web-crawler-introduction/以获取第一篇文章以及指向该线程中其他帖子的链接。另请参阅 http://blog.mischel.com/2011/12/26/writing-a-web-crawler-queue-management-part-1/。这是我一直想回到的东西,但将近两年后我仍然没有做到。
您还会遇到代理问题、URL 过滤问题(此处和此处)、奇怪的重定向以及不完全异步的异步调用。
您不需要更多线程,因为这些线程都花时间等待。您需要一个异步程序,它不会阻塞等待 Web 回复的线程。
线程的问题在于它们是一种相当昂贵的资源,因为它们的堆栈需要内存,以及它们为操作系统线程调度程序创建的工作。在您的程序中,此调度程序不断切换线程,以便它们都可以轮流等待。但他们没有做任何有用的事情。
在网络爬虫中,您将花费大部分时间等待网络请求。因此,如果您阻塞了 I/O,您的程序将不会全速处理,如果程序处于空闲状态等待回调,异步 IO 也无济于事。听起来您只需要向主应用程序添加更多线程并并行处理即可。
但是很难说,因为你没有发布任何代码。
是的。找出瓶颈所在并提高性能。
编辑:
如果使用 Parallel.ForEach,则可以使用 ParallelOptions 参数尝试重载。设置 MaxDegreeOfParallelism 属性可能会有所帮助。
实际上,链接数/分钟与同时运行的爬网程序线程数成正比。
在第一种情况下;您有 3 个进程,每个进程有 n 个线程(总共 3n 个线程)
尝试在一个进程中运行 3n 个线程。
实际上,这也取决于您的操作系统和CPU。因为旧版本的窗口(如XP)不支持不同CPU内核上的并行多线程。
与 TPL 的并行性对于网络爬虫来说是糟糕的设计。Parallel.ForEach() 循环只启动一堆请求 (5-50),因为它被设计为并行执行耗时的计算,而不是并行执行数千个几乎什么都不做的请求。要获取您想要的数据,您必须能够并行执行大量 (10000+) 的请求。异步操作是关键。
我开发了 Crawler-Lib 框架的爬虫引擎。它是一个支持工作流的爬虫,可以轻松扩展以执行任何类型的请求甚至处理您想要的。它旨在为您提供开箱即用的高吞吐量。
这是引擎:http://www.crawler-lib.net/crawler-lib-engine
以下是一些Youtube视频,展示了Crawler-Lib引擎的工作原理: http://www.youtube.com/user/CrawlerLib
我知道这个项目不是开源的,但有一个免费版本。