加速网络爬虫

20
我正在使用简单的网络爬虫scrapy获取23,770个网页。虽然我对scrapy和Python都比较陌生,但还是写了一个可以完成工作的爬虫。不过,速度非常慢(需要大约28小时才能爬取这23770个页面)。
我查看了scrapy网站、邮件列表和stackoverflow,但似乎找不到适合初学者的编写快速爬虫的通用建议。也许我的问题并不在爬虫本身,而是在运行方式上。欢迎提出各种建议!
如果需要,我已列出了我的代码。
from scrapy.spider import BaseSpider
from scrapy.selector import HtmlXPathSelector
from scrapy.item import Item, Field
import re

class Sale(Item):
    Adresse = Field()
    Pris = Field()
    Salgsdato = Field()
    SalgsType = Field()
    KvmPris = Field()
    Rum = Field()
    Postnummer = Field()
    Boligtype = Field()
    Kvm = Field()
    Bygget = Field()

class HouseSpider(BaseSpider):
    name = 'House'
    allowed_domains = ["http://boliga.dk/"]
    start_urls = ['http://www.boliga.dk/salg/resultater?so=1&type=Villa&type=Ejerlejlighed&type=R%%C3%%A6kkehus&kom=&amt=&fraPostnr=&tilPostnr=&iPostnr=&gade=&min=&max=&byggetMin=&byggetMax=&minRooms=&maxRooms=&minSize=&maxSize=&minsaledate=1992&maxsaledate=today&kode=&p=%d' %n for n in xrange(1, 23770, 1)]

    def parse(self, response):
        hxs = HtmlXPathSelector(response)
        sites = hxs.select("id('searchresult')/tr")
        items = []      
        for site in sites:
            item = Sale()
            item['Adresse'] = site.select("td[1]/a[1]/text()").extract()
            item['Pris'] = site.select("td[2]/text()").extract()
            item['Salgsdato'] = site.select("td[3]/text()").extract()
            Temp = site.select("td[4]/text()").extract()
            Temp = Temp[0]
            m = re.search('\r\n\t\t\t\t\t(.+?)\r\n\t\t\t\t', Temp)
            if m:
                found = m.group(1)
                item['SalgsType'] = found
            else:
                item['SalgsType'] = Temp
            item['KvmPris'] = site.select("td[5]/text()").extract()
            item['Rum'] = site.select("td[6]/text()").extract()
            item['Postnummer'] = site.select("td[7]/text()").extract()
            item['Boligtype'] = site.select("td[8]/text()").extract()
            item['Kvm'] = site.select("td[9]/text()").extract()
            item['Bygget'] = site.select("td[10]/text()").extract()
            items.append(item)
        return items

感谢!

1
你可以做的第一件事就是使用线程(请在标准库文档中查看相关信息),同时运行5/10个下载,这显然会导致很大的执行时间改善。除此之外,我没有看到任何简单的方法来加快速度,因为你的代码似乎很直接。 - michaelmeyer
@doukremt:谢谢!我已经查看了文档,对于我需要的功能来说似乎非常简单。我正确理解了吗?对于每个连接,我应该调用thread.start_new_thread(parse)吗?还是我会得到两个连接,每个连接都会爬取所有的23770个页面? - Mace
Scrapy实际上是异步的,因此它可以并行下载(您可以设置它发出多少并发请求)。 - Capi Etheriel
@barraponto:用我这个白痴都能理解的话来说,同时发起两个请求会一起获取23770页,而不是每个请求都下载所有页面,对吧? :) - Mace
@Mace scrapy是单线程的,但它可以并行下载并在等待答案时处理响应...这就是非阻塞或异步的含义。当然,它也可以是多线程的,但这会增加代码的复杂性,而没有真正的优势,因为您的限制是网络调用,而不是解析代码。 - Capi Etheriel
4个回答

40

以下是可尝试的方法:

  • 使用最新版本的Scrapy(如果尚未使用)
  • 检查是否使用了非标准中间件
  • 尝试增加CONCURRENT_REQUESTS_PER_DOMAINCONCURRENT_REQUESTS设置 (文档)
  • 关闭日志记录LOG_ENABLED = False (文档)
  • 尝试在循环中使用yield一个项,而不是将项收集到items列表中并返回它们
  • 使用本地缓存DNS(参见此线程)
  • 检查此站点是否使用下载阈值,并限制您的下载速度(参见此线程)
  • 记录CPU和内存使用情况 - 看看是否有任何问题
  • 尝试在scrapyd服务下运行相同的爬虫
  • 看看grequests+lxml是否表现更好(如果需要实施此解决方案,请咨询帮助)
  • 尝试在pypy上运行Scrapy,请参见在PyPy上运行Scrapy

希望这有所帮助。


谢谢!这些点是否按照相关性/性能改进的顺序排列? - Mace
嗯,没有特定的顺序,但我会先检查与scrapy无关的问题,比如网站下载限制。 - alecxe
我该怎么检查?我已经查看了线程,但是我没有看到它提到如何测试是否符合条件? - Mace
其实不太确定如何准确地知道,除非运行性能测试并测量下载速度。看起来做起来并不那么简单。 - alecxe

5

谢谢,我会尝试的。我已经尝试了@alecxe提到的几个点。一开始爬取非常快,但后来变得相当慢,并且我会出现一些失败的情况,因为爬取需要超过180秒。没有确定的消息,看起来好像要么是请求太频繁,要么是由于所有请求都来自同一个IP,导致网站减缓响应速度。你有什么想法吗? - Mace
@barraponto:将HTTPCACHE_ENABLED设置为True确实有所帮助!现在我的问题是我经常遇到“500内部服务器错误”。我尝试将延迟时间设置为5秒和CONCURRENT_REQUESTS_PER_DOMAIN = 2,但这并没有帮助。 - Mace
@Mace 500错误可能会在服务器崩溃时发生,这可能会被维护人员注意到,并可能导致他们阻止您的API或采取措施防止自动访问。我建议使用一些代理,也许可以尝试使用Crawlera:http://crawlera.com/ - Capi Etheriel
免责声明:我在ScrapingHub工作,这是一家开发Scrapy和Crawlera的公司。 - Capi Etheriel
@barraponto 我想我确实造成了崩溃,但现在它已经重新启动了,而且我没有被阻止。我只会更少地爬行,我想我会没事的 - 今天没有出现任何问题。 - Mace

0

加速Scrapy的一个解决方法是适当配置start_urls

例如,如果我们的目标数据在http://apps.webofknowledge.com/doc=1,文档编号范围从11000,则可以按照以下方式配置start_urls

 start_urls = [
    "http://apps.webofknowledge.com/doc=250",
    "http://apps.webofknowledge.com/doc=750",
]

通过这种方式,请求将从250251,249以及从750751,749同时启动,因此与start_urls = ["http://apps.webofknowledge.com/doc=1"]相比,您的速度将提高4倍。


0

我也从事网络爬虫工作,使用优化的C#语言,但最终CPU负载过高,因此我正在转向C语言。

解析HTML会导致CPU数据缓存失效,而且很可能你的CPU根本没有使用SSE 4.2,因为只有使用C/C++才能访问这个功能。

如果你做一下计算,你很快就会受到计算限制,但不会受到内存限制。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接