web-dev-qa-db-fra.com

comment filtrer les demandes en double en fonction de l'URL en tremblant

J'écris un robot pour un site Web utilisant scrapy avec CrawlSpider.

Scrapy fournit un filtre de demande de doublon intégré qui filtre les demandes en double en fonction des URL. En outre, je peux filtrer les demandes en utilisant les règles membre de CrawlSpider.

Ce que je veux faire, c'est filtrer les demandes comme:

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

Si j'ai déjà visité

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

REMARQUE: refer est un paramètre qui n'affecte pas la réponse que j'obtiens, donc je me fiche que la valeur de ce paramètre change.

Maintenant, si j'ai un ensemble qui accumule tous ids je pourrais l'ignorer dans ma fonction de rappel parse_item (c'est ma fonction de rappel) pour obtenir cette fonctionnalité.

Mais cela signifierait que je suis encore au moins en train de récupérer cette page, quand je n'en ai pas besoin.

Alors, quelle est la façon dont je peux dire à scrapy qu'il ne doit pas envoyer une demande particulière basée sur l'URL?

41
nik-v

Vous pouvez écrire un middleware personnalisé pour la suppression des doublons et l'ajouter dans les paramètres

import os

from scrapy.dupefilter import RFPDupeFilter

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)

Ensuite, vous devez définir la DUPFILTER_CLASS correcte dans settings.py

DUPEFILTER_CLASS = 'scraper.duplicate_filter.CustomFilter'

Il devrait marcher après ça

40
ytomar

En suivant l'exemple d'ytomar, j'ai écrit ce filtre qui filtre uniquement en fonction des URL qui ont déjà été vues en vérifiant un ensemble en mémoire. Je suis un Python noob alors faites-moi savoir si j'ai foiré quelque chose, mais cela semble fonctionner correctement:

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)

Comme ytomar l'a mentionné, assurez-vous d'ajouter le DUPEFILTER_CLASS constant à settings.py:

DUPEFILTER_CLASS = 'scraper.custom_filters.SeenURLFilter'
10
Abe Voelker

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

Ce fichier pourrait vous aider. Ce fichier crée une base de données de clé d'extraction delta unique à partir de l'URL, un utilisateur passe dans un scrapy.Reqeust (meta = {'deltafetch_key': uniqe_url_key}). Cela vous permet d'éviter les demandes en double que vous avez déjà visitées dans le passé.

Un exemple d'implémentation de mongodb utilisant 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

par exemple. id = 345 scrapy.Request (url, meta = {deltafetch_key: 345}, callback = parse)

3
Manoj Sahu

Voici ma base de filtre personnalisée sur scrapy 0.24.6.

Dans ce filtre, il ne se soucie que de l'identifiant dans l'url. par exemple

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

sont traités comme la même URL. Mais

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

ne fera pas.

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
chengbo

Dans la dernière version, nous pouvons utiliser le filtre de duplication par défaut ou l'étendre et en avoir un personnalisé.

définir la configuration ci-dessous dans les paramètres d'araignée

DUPEFILTER_CLASS = 'scrapy.dupefilters.BaseDupeFilter'

0
Nagendran