Я пишу паук 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)
и как насчет URL-адресов, которые нужно найти в других ответах? – eLRuLL
Я предполагаю, что после того, как я попал в URL-адрес, на этой странице не будут найдены новые URL-адреса (за исключением start_urls). Или я неправильно понял ваш вопрос? –
Нет, это нормально, тогда я думаю, что ваш подход (или аналогичный) в порядке, идея состоит в том, чтобы сохранить те, которые уже были выполнены, если они много, я бы рекомендовал использовать отдельную базу данных, также Scrapy сохраняет запросы, такие как отпечаток пальца, который помогает на собственном компоненте дедупликации. – eLRuLL