Scrapy - 不要根据 http status_code 过滤某些 url

问题描述 投票:0回答:1

我有一个自定义的 dupefilter,当我启动/停止它时,我用它来加载/保存我的抓取状态到 s3 中。

我想从重复过滤器中删除具有特定 http status_code 的网址,例如 429。

我最初的想法是收集Spider_Closed方法中的每个失败的URL,并在将其保存到S3之前从看到的所有非200个URL中删除,但我无法让它工作,我不确定这是最好的方法。

这是我的 dupefilter 类:

from scrapy.dupefilters import BaseDupeFilter
import hashlib
import pickle


class S3DupeFilter(BaseDupeFilter):

    @classmethod
    def from_crawler(cls, crawler):
        bucket_name = ...
        key_name = ...
        logger = crawler.spider.logger
        return cls(bucket_name, key_name, logger)


    def __init__(self, bucket, key, logger):
        super(S3DupeFilter, self).__init__()
        self.bucket_name = bucket
        self.key_name = key
        self.logger = logger
        self.seen = set()
        self.load()


    def request_seen(self, request):
        fp = self.request_fingerprint(request)
        if fp in self.seen:
            return True
        self.seen.add(fp)
        return False


    def close(self, reason):
        self.save()

    def load(self):
        try:
            self.seen = aws_s3_read_data(...)
            if not self.seen:
                self.seen = set()
            self.logger.info(f"Loaded {len(self.seen)} fingerprints from S3")
        except Exception as e:
            self.logger.error(f"Error loading dupefilter from S3: {e}")


    def save(self):
        try:
            serialized_seen = pickle.dumps(self.seen)
            aws_s3_insert_data(...)
            self.logger.info(f"Saved {len(self.seen)} fingerprints to S3")
        except Exception as e:
            self.logger.error(f"Error saving dupefilter to S3: {e}")


    def request_fingerprint(self, request):
        return hashlib.sha256(request.url.encode('utf-8')).hexdigest()


    def open(self):
        pass

python scrapy
1个回答
0
投票

回答我自己的问题,这是我找到的解决方案:

我在自定义 dupefilter 类中添加了一个

unsee_request()
方法。它从
seen
集合中删除一个 url

    def unsee_request(self, request):
        fp = self.request_fingerprint(request)
        if fp in self.seen:
            self.seen.remove(fp)

我重写了

_retry
RetryMiddleware
方法。它检查请求是否失败以及是否达到 max_retries。如果是这样,它会调用
unsee_request()
方法。

    def _retry(self, request, reason, spider):
        retry_req = super()._retry(request, reason, spider)
        if not retry_req:
            spider.crawler.engine.slot.scheduler.df.unsee_request(request)
        return retry_req

© www.soinside.com 2019 - 2024. All rights reserved.