2013-06-10 10 views
12

Ich kratze 23770 Webseiten mit einem ziemlich einfachen Web Schaber mit scrapy. Ich bin ziemlich neu bei Scrapy und sogar Python, habe es aber geschafft, eine Spinne zu schreiben, die diese Aufgabe erfüllt. Es ist jedoch sehr langsam (es dauert ca. 28 Stunden, um die 23770 Seiten zu crawlen).Beschleunigen Sie Web Schaber

Ich habe auf die scrapy Webseite und die Mailinglisten und stackoverflow geschaut, aber ich kann nicht scheinen, allgemeine Empfehlungen zum Schreiben von schnellen Crawlern zu finden, die für Anfänger verständlich sind. Vielleicht ist mein Problem nicht die Spinne selbst, sondern die Art, wie ich sie betreibe. Alle Vorschläge willkommen!

Ich habe meinen Code unten aufgeführt, wenn es benötigt wird.

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 

Vielen Dank!

+1

Das erste, was Sie tun können, ist die Verwendung von Threads (siehe die entsprechenden Informationen im Dokument der Standardbibliothek), um beispielsweise 5/10 Downloads gleichzeitig auszuführen, was offensichtlich zu einer großen Ausführungszeit führen kann Verbesserung. Abgesehen davon sehe ich keine einfache Möglichkeit, die Dinge zu beschleunigen, da Ihr Code einfach zu sein scheint. – michaelmeyer

+0

@doukremt: Danke! Ich habe mir die Dokumentation angeschaut und es scheint ziemlich einfach zu sein, wofür ich sie brauche. Ist es richtig verstanden, dass ich für jede Verbindung 'thread.start_new_thread (parse)' aufrufen soll? Oder bekomme ich nur zwei Verbindungen, die alle 23770 Seiten scrapen? – Mace

+0

scrapy ist eigentlich asynchron, also wird es tatsächlich parallel heruntergeladen (Sie können einstellen, wie viele gleichzeitige Anfragen es machen). –

Antwort

20

Hier ist eine Sammlung von Dingen, um zu versuchen:

  • neueste scrapy Version verwenden (wenn nicht bereits verwendet wird)
  • überprüfen, ob Nicht-Standard-Middle
  • Versuch verwendet werden CONCURRENT_REQUESTS_PER_DOMAIN, CONCURRENT_REQUESTS Einstellungen zu erhöhen (docs)
  • Abschaltzeit Anmeldung LOG_ENABLED = False (docs)
  • versuchen 10 ing ein Element in einer Schleife statt Elemente in die items Liste zu sammeln und
  • Verwendung lokalen Cache DNS (siehe this thread)
  • Check Rückkehr, wenn diese Website herunterladen Schwelle ist mit und begrenzt Ihre Download-Geschwindigkeit (siehe this thread)
  • log CPU- und Speichernutzung während der Spinne Lauf - nachsehen, ob es irgendwelche Probleme gibt es
  • versuchen, die gleiche Spinne unter scrapyd Dienst laufen
  • sehen, ob grequests + lxml besser durchführen wird (fragen Sie, wenn Sie Hilfe brauchen bei der Umsetzung dieses Sol ution)
  • versuchen Scrapy auf pypy ausgeführt wird, finden Running Scrapy on PyPy

Hoffnung, das hilft.

+0

Danke! Sind die Punkte nach Relevanz/Leistungsverbesserung geordnet? – Mace

+0

Nun, keine spezielle Bestellung hier, aber ich würde nach nicht verwandten zu scrapy Probleme, wie Website Download Limit zuerst prüfen. – alecxe

+0

Wie überprüfe ich das? Ich habe den Thread angeschaut, aber ich kann nicht sehen, wo es erwähnt, wie man prüft, ob das der Fall ist? – Mace

5

Mit Blick auf Ihren Code würde ich sagen, dass die meiste Zeit in Netzwerkanforderungen verbracht wird, anstatt die Antworten zu verarbeiten. Alle Tipps, die @alecxe in seiner Antwort zur Verfügung stellt, gelten, aber ich würde die Einstellung HTTPCACHE_ENABLED vorschlagen, da sie die Anforderungen zwischenspeichert und es ein zweites Mal vermeidet. Es würde bei folgenden Crawls und sogar bei der Offline-Entwicklung helfen. Sehen Sie weitere Informationen in der Dokumentation: http://doc.scrapy.org/en/latest/topics/downloader-middleware.html#module-scrapy.contrib.downloadermiddleware.httpcache

+0

Guter Punkt, danke! – alecxe

+0

Danke, ich werde das versuchen. Ich habe mehrere der genannten Punkte @alecxe ausprobiert. Am Anfang ist das Kratzen sehr schnell, aber dann wird es ziemlich langsam, und ich bekomme geschundene Kratzer, weil die Kratzer mehr als 180 Sekunden dauern. Ohne sicher zu sein, scheint es, als ob ich entweder zu hart auf die Seite treffe, oder sie reduzieren ihre Antwortzeit, da alle Anfragen von derselben IP stammen. Irgendwelche Gedanken dazu? – Mace

+0

@barraponto: Die Einstellung 'HTTPCACHE_ENABLED' gleich 'True' hat wirklich geholfen !! Jetzt ist mein Problem, dass ich den "500 internen Server-Fehler" viel bekomme. Ich habe versucht, die Verzögerungszeit auf 5 Sekunden und 'CONCURRENT_REQUESTS_PER_DOMAIN = 2' zu setzen, aber es hilft nicht. – Mace

0

Ich arbeite auch auf Web-Verschrottung, optimiert mit C#, und es endet die CPU gebunden, so dass ich die Umstellung auf C.

Parsing HTML bläst die CPU-Daten-Cache, und ziemlich sicher, dass Ihre CPU SSE 4.2 überhaupt nicht verwendet, da Sie nur mit C/C++ auf diese Funktion zugreifen können.

Wenn Sie die Mathematik ausführen, werden Sie schnell compute gebunden aber nicht speichergebunden.