jak filtrować zduplikowane żądania na podstawie adresu url w Scrappy

Piszę crawler dla strony internetowej za pomocą Scrappy z CrawlSpider.

Scrapy dostarcza wbudowany filtr duplikatów żądań, który filtruje duplikaty żądań na podstawie adresów URL. Ponadto, mogę filtrować żądania za pomocą rules członek CrawlSpider.

To, co chcę zrobić, to filtrować żądania w stylu:

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

Jeśli już odwiedziłem

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

Uwaga: Referer jest parametrem, który nie wpływa na otrzymaną odpowiedź, więc nie obchodzi mnie, czy wartość zmian tego parametru.

Teraz, jeśli mam zestaw, który gromadzi wszystkie ID mogę zignorować go w mojej funkcji zwrotnej parse_item (to moja funkcja zwrotna), aby osiągnąć tę funkcjonalność.

Ale to by oznaczało, że wciąż przynajmniej pobieram tę stronę, kiedy nie muszę.

Więc w jaki sposób mogę powiedzieć scrapy ' emu, że nie powinien wysyłać konkretnego żądania na podstawie adresu url?

Author: eLRuLL, 2012-09-23

4 answers

Możesz napisać własne oprogramowanie pośrednie do usuwania duplikatów i dodać je w Ustawieniach

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)

Następnie musisz ustawić poprawny DUPFILTER_CLASS w settings.py

DUPEFILTER_CLASS = 'scraper.duplicate_filter.CustomFilter'

Powinno działać po tym

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-11 17:31:17

Idąc za tropem ytomara, napisałem ten filtr, który filtruje wyłącznie na podstawie adresów URL, które były już widoczne, sprawdzając zestaw w pamięci. Jestem noobem Pythona, więc daj znać, jeśli coś spieprzyłem, ale wygląda na to, że działa dobrze: {]}

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)

Jak wspomniał ytomar, należy dodać DUPEFILTER_CLASS stałą do 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/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-15 04:56:43

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

Ten plik może Ci pomóc. Ten plik tworzy bazę danych unikalnego delta fetch key z adresu url, użytkownik przechodzi w scrapie.Reqeust (meta={'deltafetch_key': uniqe_url_key}). To pozwoli Ci uniknąć duplikatów wniosków, które już odwiedziłeś w przeszłości.

Przykładowa implementacja mongodb przy użyciu 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

Np. 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/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-19 14:12:59

Oto moja własna baza filtrów na scrapy 0.24.6.

W tym filtrze dba tylko o id w adresie url. na przykład

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

Są traktowane jako ten sam adres url. Ale

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

Nie będzie.
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/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-31 02:40:15