2

我正在构建一个网络爬虫,它可以从数百万个域的列表中获取 1-3 页,我正在使用多线程的 Python,我尝试过使用 httplib、httplib2、urllib、urllib2、urllib3、请求和 curl 的多线程(最快的一堆)以及扭曲和scrapy,但它们都不允许我使用超过约10 mbits的带宽(我有60 mbit的速度),通常在大约100-300个线程时达到最大值,之后它会导致失败的请求. 我也遇到了 php/curl 的这个问题。我有一个刮板,它从谷歌加上带有 urllib3 和 Threads 模块(Python)的页面,并且最大限度地利用了我的 100mbit 连接(我相信这可能是因为它正在重新使用具有相同主机的开放套接字,而谷歌有一个快速网络响应)

这是我使用 pycurl 的脚本之一的示例,我正在从包含 url 的 csv 文件中读取 url。

import pycurl
from threading import Thread
from Queue import Queue
import cStringIO


def get(readq,writeq):
    buf = cStringIO.StringIO()
    while True:
        url=readq.get()

        c = pycurl.Curl()
        c.setopt(pycurl.TIMEOUT, 15)
        c.setopt(pycurl.FOLLOWLOCATION, 1)
        c.setopt(pycurl.USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Firefox/24.0')
        c.setopt(c.WRITEFUNCTION, buf.write)
        c.setopt(c.URL, url)
        try:
            c.perform()
            writeq.put(url+'  '+str(c.getinfo(pycurl.HTTP_CODE)))
        except:
            writeq.put('error  '+url)
print('hi')
readq=Queue()
writeq=Queue()

import csv
reader=csv.reader(open('alldataunq2.csv'))
sites = []
ct=0
for l in reader:
    if l[3] != '':
        readq.put('http://'+l[3])
        ct+=1
        if ct > 100000:
            break

t=[]
for i in range(100):
    Thread(target=get,args=(readq,writeq)).start()

while True:
    print(writeq.get())

瓶颈肯定是网络 IO,因为我的处理器/内存几乎没有被使用。有没有人成功编写过能够使用完整 100mbit 或更多连接的类似刮板?

非常感谢有关如何提高抓取代码速度的任何输入

4

3 回答 3

3

在优化爬行速度时,您需要牢记几个因素。

连接位置

为了有效地重用连接,您需要确保为同一个网站重用连接。如果您等待太久才能再次访问较早的主机,则连接可能会超时,这是不好的。打开新套接字是一项相对昂贵的操作,因此您希望不惜一切代价避免它。实现此目的的一个简单的启发式方法是按主机对下载目标进行排序并一次下载一个主机,但随后您会遇到下一个问题......

在主机之间分散负载

并非所有主机都有胖管道,因此您需要同时访问多个主机——这也有助于避免过多地向单个主机发送垃圾邮件。这里一个好的策略是拥有多个工作人员,每个工作人员一次专注于一个主机。通过这种方式,您可以在每个工作人员的上下文中控制每个主机的下载速率,并且每个工作人员将维护自己的连接池以重用连接。

工人专业化

破坏吞吐量的一种方法是将数据处理例程(解析 HTML、提取链接等)与获取例程混合。一个好的策略是在获取工作人员中做最少的处理工作,并简单地将数据保存为一组单独的工作人员稍后获取和处理(甚至可能在另一台机器上)。

牢记这些事情,你应该能够从你的连接中挤出更多的东西。一些不相​​关的建议:考虑使用wget,您会惊讶于它在进行简单爬网时的有效性(它甚至可以从巨大的清单文件中读取)。

于 2013-11-03T23:23:45.137 回答
1

我认为在进行网络抓取时,您无法期望获得接近 Internet 连接的最大吞吐量的任何地方。

抓取(以及一般的网页浏览)涉及发出许多小请求。大部分时间都花在了连接的建立和拆除上,以及在远程端等待开始交付您的内容。我猜想主动下载内容所花费的时间大概在 50% 左右。如果您正在下载一堆大文件,那么我认为您会看到更好的平均吞吐量。

于 2013-11-03T20:33:21.690 回答
0

尝试使用scrapy-redis进行抓取。

您必须调整设置CONCURRENT_REQUESTS和。还要确保你有和。CONCURRENT_REQUESTS_PER_DOMAINCONCURRENT_REQUESTS_PER_IPDOWNLOAD_DELAY = 0AUTOTHROTTLE_ENABLED = False

于 2013-11-04T13:13:31.953 回答