scraping example español crawler python web-crawler scrapy

python - example - cómo filtrar solicitudes duplicadas basadas en url en scrapy



web crawler linux (4)

Estoy escribiendo un rastreador para un sitio web usando scrapy con CrawlSpider.

Scrapy proporciona un filtro incorporado de solicitud de duplicados que filtra solicitudes duplicadas basadas en urls. Además, puedo filtrar las solicitudes usando las reglas miembro de CrawlSpider.

Lo que quiero hacer es filtrar solicitudes como:

http:://www.abc.com/p/xyz.html?id=1234&refer=5678

Si ya he visitado

http:://www.abc.com/p/xyz.html?id=1234&refer=4567

NOTA: referir es un parámetro que no afecta la respuesta que recibo, por lo que no me importa si el valor de ese parámetro cambia.

Ahora, si tengo un conjunto que acumula todos los identificadores , podría ignorarlo en mi función de devolución de llamada parse_item (esa es mi función de devolución de llamada) para lograr esta funcionalidad.

Pero eso significa que todavía estoy por lo menos buscando esa página, cuando no es necesario.

Entonces, ¿cuál es la forma en que puedo decirle a scrapy que no debe enviar una solicitud particular basada en la url?


Aquí está mi base de filtro personalizada en scrapy 0.24.6.

En este filtro, solo le importa el ID en la url. por ejemplo

http://www.example.com/products/cat1/1000.html?p=1 http://www.example.com/products/cat2/1000.html?p=2

se tratan como la misma url. Pero

http://www.example.com/products/cat2/all.html

no lo hará

import re import os from scrapy.dupefilter import RFPDupeFilter class MyCustomURLFilter(RFPDupeFilter): def _get_id(self, url): m = re.search(r''(/d+)/.html'', url) return None if m is None else m.group(1) def request_fingerprint(self, request): style_id = self._get_id(request.url) return style_id


Puede escribir middleware personalizado para la eliminación duplicada y agregarlo en la configuración

import os from scrapy.dupefilter import RFPDupeFilter from scrapy.utils.request import request_fingerprint class CustomFilter(RFPDupeFilter): """A dupe filter that considers specific ids in the url""" def __getid(self, url): mm = url.split("&refer")[0] #or something like that return mm def request_seen(self, request): fp = self.__getid(request.url) if fp in self.fingerprints: return True self.fingerprints.add(fp) if self.file: self.file.write(fp + os.linesep)

Luego debe configurar el DUPFILTER_CLASS correcto en settings.py

DUPEFILTER_CLASS = ''scraper.duplicate_filter.CustomFilter''

Después de eso debería de funcionar


Siguiendo el ejemplo de ytomar, escribí este filtro que filtra basado puramente en URL que ya se han visto al verificar un conjunto en memoria. Soy un novato de Python, así que avíseme si arruiné algo, pero parece funcionar bien:

from scrapy.dupefilter import RFPDupeFilter class SeenURLFilter(RFPDupeFilter): """A dupe filter that considers the URL""" def __init__(self, path=None): self.urls_seen = set() RFPDupeFilter.__init__(self, path) def request_seen(self, request): if request.url in self.urls_seen: return True else: self.urls_seen.add(request.url)

Como ya mencionó, asegúrese de agregar la constante DUPEFILTER_CLASS a settings.py :

DUPEFILTER_CLASS = ''scraper.custom_filters.SeenURLFilter''


https://github.com/scrapinghub/scrapylib/blob/master/scrapylib/deltafetch.py

Este archivo puede ayudarte. Este archivo crea una base de datos de la clave única delta fetch desde la url, un pase de usuario en un scrapy.Reqeust (meta = {''deltafetch_key'': uniqe_url_key}). Esto le permite evitar solicitudes duplicadas que ya ha visitado en el pasado.

Una implementación de ejemplo de mongodb utilizando deltafetch.py

if isinstance(r, Request): key = self._get_key(r) key = key+spider.name if self.db[''your_collection_to_store_deltafetch_key''].find_one({"_id":key}): spider.log("Ignoring already visited: %s" % r, level=log.INFO) continue elif isinstance(r, BaseItem): key = self._get_key(response.request) key = key+spider.name try: self.db[''your_collection_to_store_deltafetch_key''].insert({"_id":key,"time":datetime.now()}) except: spider.log("Ignoring already visited: %s" % key, level=log.ERROR) yield r

p.ej. id = 345 scrapy.Request (url, meta = {deltafetch_key: 345}, callback = análisis sintáctico)