2013-06-10 7 views
12

Я очищаю 23770 веб-страниц с довольно простым скребком с помощью scrapy. Я совершенно новичок в 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

+0

@doukremt: Спасибо! Я просмотрел документацию, и это кажется довольно простым для того, для чего мне это нужно. Правильно ли понятно, что для каждого соединения я должен называть 'thread.start_new_thread (parse)'? Или я просто получаю два соединения, каждый из которых очищает все страницы 23770? – Mace

+0

scrapy - фактически асинхронный, поэтому он фактически загружает параллельно (вы можете установить, сколько одновременных запросов оно делает). –

ответ

20

Вот коллекция вещей, чтобы попробовать:

  • использование последней Scrapy версии (если уже не используется)
  • проверки, если нестандартные промежуточное программное используются
  • попробовать увеличить CONCURRENT_REQUESTS_PER_DOMAIN, CONCURRENT_REQUESTS настройки (docs)
  • выключают вход LOG_ENABLED = False (docs)
  • попробовать yield ИНГИ элемента в цикле вместо сбора предметов в items список и возвращают их
  • использования локального кэш DNS (см this thread)
  • чека, если этот сайт с помощью загрузки порога и ограничивает скорость загрузки (см this thread)
  • журнала процессор и память во время паутинного бега - посмотреть, если есть какие-то проблемы есть
  • попробуйте запустить тот же паук под scrapyd службы
  • ли grequests + lxml будет работать лучше (спросите, если вам нужна помощь в реализации этот золь социологическое загрязнение)
  • попробуйте запустить Scrapy на pypy см Running Scrapy on PyPy

Надежда, что помогает.

+0

Спасибо! Являются ли упорядоченные точки релевантными/улучшенными? – Mace

+0

Ну, никакого специального заказа здесь, но я бы проверял, не связанные с проблемами с scrapy, например, ограничение загрузки сайта. – alecxe

+0

Как это проверить? Я посмотрел на поток, но я не вижу, где он упоминает, как проверить, если это так? – Mace

5

Глядя на ваш код, я бы сказал, что большая часть этого времени тратится на сетевые запросы, а не на обработку ответов. Все советы, которые @alecxe предоставляет в своем ответе, применяются, но я бы предложил настройку HTTPCACHE_ENABLED, так как он кэширует запросы и избегает делать это во второй раз. Это помогло бы при следующих обходах и даже в автономном режиме. Смотрите подробнее в документации: http://doc.scrapy.org/en/latest/topics/downloader-middleware.html#module-scrapy.contrib.downloadermiddleware.httpcache

+0

Хорошо, спасибо! – alecxe

+0

Спасибо, я попробую это. Я попробовал несколько пунктов @alecxe. В начале скребка очень быстрая, но потом она становится довольно медленной, и я получаю неудачные царапины, потому что царапины занимают более 180 секунд. Не зная наверняка, похоже, что я слишком сильно нажимаю на страницу, или они уменьшают скорость ответа, поскольку все запросы поступают из одного и того же IP-адреса. Любые мысли по этому поводу? – Mace

+0

@barraponto: настройка 'HTTPCACHE_ENABLED', равная' True', действительно помогла! Теперь моя проблема в том, что я часто получаю «500 Internal Server Error». Я попытался установить время задержки на 5 секунд и 'CONCURRENT_REQUESTS_PER_DOMAIN = 2', но это не поможет. – Mace

0

Я работаю также на веб-слом, используя оптимизированный C#, и он заканчивает ЦП, поэтому я переключение на C.

Синтаксический HTML выдувает кэш данных процессора, и довольно уверен, что ваш процессор вообще не использует SSE 4.2, так как вы можете получить доступ только к этой функции с помощью C/C++.

Если вы выполняете математику, вы быстро вычисляете границы, но не привязываетесь к памяти.

Смежные вопросы