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?

Author: eLRuLL, 2012-09-23

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

 36
Author: ytomar,
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'
 9
Author: Abe Voelker,
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)

 2
Author: Manoj Sahu,
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
 1
Author: chengbo,
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