2016-06-10 2 views
4

Я пишу паук Scrapy, который сканирует набор URL-адресов один раз в день. Однако некоторые из этих веб-сайтов очень большие, поэтому я не могу ежедневно сканировать полный сайт и не хочу генерировать массовый трафик, необходимый для этого.Scrapy spider, который только сканирует URL-адреса один раз

Старый вопрос (here) спросил что-то подобное. Однако вышеприведенный ответ просто указывает на фрагмент кода (here), который, как представляется, требует что-то из экземпляра запроса, хотя это не объясняется в ответе или на странице, содержащей фрагмент кода.

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

Я отправил код ниже, чтобы получить мяч, но мне не обязательно использовать это промежуточное программное обеспечение. Любой scrapy-паук, который может ежедневно сканировать и извлекать новые URL-адреса, будет делать. Очевидно, одно из решений заключается в том, чтобы просто написать словарь скребковых URL-адресов, а затем проверить, чтобы каждый новый URL-адрес был/нет в словаре, но это кажется очень медленным/неэффективным.

Паук

from scrapy.contrib.spiders import CrawlSpider, Rule 
from scrapy.contrib.linkextractors import LinkExtractor 
from cnn_scrapy.items import NewspaperItem 



class NewspaperSpider(CrawlSpider): 
    name = "newspaper" 
    allowed_domains = ["cnn.com"] 
    start_urls = [ 
     "http://www.cnn.com/" 
    ] 

    rules = (
     Rule(LinkExtractor(), callback="parse_item", follow=True), 
    ) 

    def parse_item(self, response): 
     self.log("Scraping: " + response.url) 
     item = NewspaperItem() 
     item["url"] = response.url 
     yield item 

Элементы

import scrapy 


class NewspaperItem(scrapy.Item): 
    url = scrapy.Field() 
    visit_id = scrapy.Field() 
    visit_status = scrapy.Field() 

промежуточное программное (ignore.py)

from scrapy import log 
from scrapy.http import Request 
from scrapy.item import BaseItem 
from scrapy.utils.request import request_fingerprint 

from cnn_scrapy.items import NewspaperItem 

class IgnoreVisitedItems(object): 
    """Middleware to ignore re-visiting item pages if they were already visited 
    before. The requests to be filtered by have a meta['filter_visited'] flag 
    enabled and optionally define an id to use for identifying them, which 
    defaults the request fingerprint, although you'd want to use the item id, 
    if you already have it beforehand to make it more robust. 
    """ 

    FILTER_VISITED = 'filter_visited' 
    VISITED_ID = 'visited_id' 
    CONTEXT_KEY = 'visited_ids' 

    def process_spider_output(self, response, result, spider): 
     context = getattr(spider, 'context', {}) 
     visited_ids = context.setdefault(self.CONTEXT_KEY, {}) 
     ret = [] 
     for x in result: 
      visited = False 
      if isinstance(x, Request): 
       if self.FILTER_VISITED in x.meta: 
        visit_id = self._visited_id(x) 
        if visit_id in visited_ids: 
         log.msg("Ignoring already visited: %s" % x.url, 
           level=log.INFO, spider=spider) 
         visited = True 
      elif isinstance(x, BaseItem): 
       visit_id = self._visited_id(response.request) 
       if visit_id: 
        visited_ids[visit_id] = True 
        x['visit_id'] = visit_id 
        x['visit_status'] = 'new' 
      if visited: 
       ret.append(NewspaperItem(visit_id=visit_id, visit_status='old')) 
      else: 
       ret.append(x) 
     return ret 

    def _visited_id(self, request): 
     return request.meta.get(self.VISITED_ID) or request_fingerprint(request) 
+0

и как насчет URL-адресов, которые нужно найти в других ответах? – eLRuLL

+0

Я предполагаю, что после того, как я попал в URL-адрес, на этой странице не будут найдены новые URL-адреса (за исключением start_urls). Или я неправильно понял ваш вопрос? –

+1

Нет, это нормально, тогда я думаю, что ваш подход (или аналогичный) в порядке, идея состоит в том, чтобы сохранить те, которые уже были выполнены, если они много, я бы рекомендовал использовать отдельную базу данных, также Scrapy сохраняет запросы, такие как отпечаток пальца, который помогает на собственном компоненте дедупликации. – eLRuLL

ответ

0

Вот вещь, то, что у ou хочет сделать, чтобы иметь возможность иметь одну базу данных, по которой запланирован/croned ваш обход. dupflier.middleware или нет, вам все равно придется царапать весь сайт независимо от ... и я чувствую, несмотря на очевидность того, что код не может быть весь проект, что этот WAYY слишком много кода.

Я не совсем уверен, что это такое, что вы выскакивали, но я собираюсь предположить, что теперь у вас есть CNN в качестве URL-адреса проекта, который вы очищаете от статей?

что бы я делал бы использовать CNNs RSS-каналы или даже карта сайта, учитывая, что обеспечивает должную дату со статьей мета- и с помощью модуля OS ...

определить дату каждого экземпляра ползания Использование регулярных выражений ограничить детализация с сканерами определенных даты против даты статей размещена разворачивать и график ползти к/в scrapinghub использовать scrapinghubs клиента Python API для перебора элементов

Еще бы ползать целые сайты содержания, но с xmlspider или rssspider классом идеально подходит для более быстрого анализа всех этих данных ... И теперь, когда db доступный в «облаке» ... Я чувствую, что можно быть более модульным с масштабируемостью проекта, а также гораздо более удобной переносимостью/кросс-совместимостью

Я уверен, что описание потока будет предметом некоторого вмешательства, но идея прямолинейна.