cómo filtrar solicitudes duplicadas basadas en url en scrapy
Estoy escribiendo un rastreador para un sitio web usando scrapy con CrawlSpider.
Scrapy proporciona un filtro de solicitud duplicada incorporado que filtra las solicitudes duplicadas en función de las URL. Además, puedo filtrar solicitudes usando rules 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: refer es un parámetro que no afecta la respuesta que obtengo, por lo que no me importa si el valor de ese parámetro cambia.
Ahora, si tengo un conjunto que acumula todos los ids 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 significaría que todavía estoy al menos buscando esa página, cuando no lo necesito.
Entonces, ¿cuál es la forma en que puedo decirle a scrapy que no debe enviar una solicitud en particular basada en la url?
4 answers
Puede escribir middleware personalizado para eliminar duplicados y agregarlo en 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)
Entonces necesitas establecer el DUPFILTER_CLASS correcto en settings.py
DUPEFILTER_CLASS = 'scraper.duplicate_filter.CustomFilter'
Debe funcionar después de eso
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-11 17:31:17
Siguiendo el ejemplo de ytomar, escribí este filtro que filtra basado puramente en URLs que ya se han visto al comprobar un conjunto en memoria. Soy un noob de pitón, así que avísame si metí la pata en algo, pero parece que funciona 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 mencionó ytomar, asegúrese de agregar la constante DUPEFILTER_CLASS
a settings.py
:
DUPEFILTER_CLASS = 'scraper.custom_filters.SeenURLFilter'
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-15 04:56:43
Https://github.com/scrapinghub/scrapylib/blob/master/scrapylib/deltafetch.py
Este archivo puede ayudarte. Este archivo crea una base de datos de 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 usando 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
Eg. id = 345 scrapy.Request (url,meta={deltafetch_key:345},callback=parse)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-19 14:12:59
Aquí está mi base de filtro personalizado 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-31 02:40:15