Python 网络爬虫的速度不能超过大约1MB/秒

Python 网络爬虫的速度不能超过大约1MB/秒,python,web-scraping,twisted,scrapy,urllib3,Python,Web Scraping,Twisted,Scrapy,Urllib3,我正在构建一个webcrawler,它可以从数百万个域的列表中获取1-3页,我正在使用多线程的Python,我已经尝试了使用httplib、httplib2、urllib、urllib2、urllib3、requests和curl(最快的)以及twisted进行多线程处理,虽然很糟糕,但它们都不允许我使用超过10Mbit的带宽(我有60Mbit的速度),通常在100-300个线程时达到最大值,之后会导致请求失败。我在php/curl中也遇到了这个问题。我有一个scraper,它使用urllib3

我正在构建一个webcrawler,它可以从数百万个域的列表中获取1-3页,我正在使用多线程的Python,我已经尝试了使用httplib、httplib2、urllib、urllib2、urllib3、requests和curl(最快的)以及twisted进行多线程处理,虽然很糟糕,但它们都不允许我使用超过10Mbit的带宽(我有60Mbit的速度),通常在100-300个线程时达到最大值,之后会导致请求失败。我在php/curl中也遇到了这个问题。我有一个scraper,它使用urllib3和Threads模块(Python)从google plus页面上刮取数据,并将我的100mbit连接最大化(我相信这可能是因为它在同一主机上重新使用开放式套接字,而google具有快速的网络响应)

下面是一个使用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,因为我的处理器/内存几乎没有被使用。有没有人成功地编写了一个能够使用100位或更多连接的类似刮板


我非常感谢您对如何提高我的抓取代码的速度的任何意见

我认为您在进行web抓取时都无法接近internet连接的最大吞吐量


抓取(以及一般的网络浏览)涉及到大量的小请求。大部分时间都花在连接的建立和断开上,并等待远程端开始交付您的内容。我猜积极下载内容的时间大概在50%左右。如果你下载了一大堆大文件,那么我认为你会看到更好的平均吞吐量。

我不认为你在进行web抓取时可以达到internet连接的最大吞吐量


抓取(以及一般的网络浏览)涉及到大量的小请求。大部分时间都花在连接的建立和断开上,并等待远程端开始交付您的内容。我猜积极下载内容的时间大概在50%左右。如果您正在下载大量大文件,那么我认为您会看到更好的平均吞吐量。

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

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

在主机之间分散负载 并非所有主机都有胖管道,因此您可能希望同时攻击多个主机。这也有助于避免对单个主机进行过多的垃圾邮件。这里的一个好策略是使用多个worker,其中每个worker一次只关注一个主机。通过这种方式,您可以在每个工作进程的上下文中控制每个主机的下载速率,并且每个工作进程将维护自己的连接池以重用来自该主机的连接

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


记住这些,你应该能够从你的关系中挤出更多。一些不相关的建议:考虑使用<代码> WGET < /代码>,你会惊讶于在简单的爬行中它是多么有效(它甚至可以从一个巨大的清单文件中读取)。 连接位置 为了有效地重复使用连接,您需要确保重复使用同一网站的连接。如果您等待太久而无法再次访问较早的主机,则连接可能会超时,这是不好的。打开新插座是一项相对昂贵的操作,因此您希望不惜一切代价避免它。实现这一点的一个简单的启发式方法是按主机对下载目标进行排序,然后一次下载一台主机,但随后会遇到下一个问题

在主机之间分散负载 并非所有主机都有胖管道,因此您可能希望同时攻击多个主机。这也有助于避免对单个主机进行过多的垃圾邮件。这里的一个好策略是使用多个worker,其中每个worker一次只关注一个主机。通过这种方式,您可以在每个工作进程的上下文中控制每个主机的下载速率,并且每个工作进程将维护自己的连接池以重用来自该主机的连接

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

记住这些,你应该能够从你的关系中挤出更多。一些不相关的建议:考虑使用<代码> WGET ,你会惊讶于简单的爬行是多么有效(甚至可以从一个巨大的清单文件中读取)。 您必须调整:
CONCURRENT\u REQUESTS
CONCURRENT\u REQUESTS\u PER\u DOMAIN
CONCURRENT\u REQUESTS\u PER\u IP
。另外,请确保已启用
下载延迟=0
自动锁定=False

尝试使用scrapy

你必须