爬虫工作量由小到大的思维转变---<第二十九章 Scrapy的重试机制(避混淆)>

2023-12-28 17:46:44

前言:

单纯讲重试的问题---因为今天有人私了我 `他的代码`,我忽然觉得这里有一个误区;顺便给哥们你混淆的理论里,再搅和搅和....哈哈哈

正文:

拨乱反正:

在Scrapy中,默认情况下,当一个请求失败时,会进行自动重试。重试次数的计算是基于原始请求的 meta 属性中的 retry_times 字段。


例如,若全局重试次数设置为3,当第一次请求失败时,retry_times 字段的初始值为3。随后,经过每次重试,retry_times 的值会依次减少,直到为0。

案例说明:
class MySpider(scrapy.Spider):
    name = 'example'

    def start_requests(self):
        url = 'http://www.example.com'
        yield scrapy.Request(url, self.parse, meta={'retry_times': self.settings.get('RETRY_TIMES', 3)})

    def parse(self, response):
        if response.status == 200:
            # 成功处理响应的逻辑
            pass
        else:
            retry_times = response.meta.get('retry_times', self.settings.get('RETRY_TIMES', 3))
            if retry_times > 0:
                next_request = response.request.copy()
                next_request.meta['retry_times'] = retry_times - 1
                yield next_request
            else:
                # 超过重试次数,放弃重试
                pass

----我为什么要说这个呢? 因为我看到他的代码,在增加"retry_times"的次数,导致这个request如果失效,他能一直错下去;? (正确的代码如下,哥们儿你自己提哈):

def process_response(self, request, response, spider):
    if response.status >= 400:  # 请求超时,可能是IP的问题
        # 获取当前使用的代理IP
        proxy = request.meta.get('proxy', None)
        if proxy:
            self.remove_proxy(proxy)  # 从代理池中删除该IP

        if request.meta['retry_times'] > 0:
            # 重新获取一个随机的代理IP,并重试请求
            new_proxy = self.get_proxy()  # 获取一个新的代理IP
            if new_proxy:
                new_request = request.copy()
                new_request.meta['proxy'] = new_proxy
                new_request.meta['retry_times'] -= 1
                return new_request
    return response

我稍微改进了一下,如果重试都失败了,那抛异常没毛病了吧:

   def process_response(self, request, response, spider):
        if response.status >= 400:  # 请求超时,可能是IP的问题
            # 获取当前使用的代理IP
            proxy = request.meta.get('proxy', None)
            if proxy:
                self.remove_proxy(proxy)  # 从代理池中删除该IP

            if request.meta['retry_times'] > 0:
                new_proxy = self.get_proxy()  # 获取一个新的代理IP
                if new_proxy:
                    new_request = request.copy()
                    new_request.meta['proxy'] = new_proxy
                    new_request.meta['retry_times'] -= 1

                    if new_request.meta['retry_times'] == 0:
                    # 重试次数超过全局重试次数时,抛出异常
                        raise Exception('URL重试次数超过限制')

                    return new_request
        return response

备注:(记得从你的全局settings中,获取重试次数哈),如果你不获取的话,虽然scrapy默认会重试,但你获取不到重试的值!!! 因为他不是显式的!

global_retry_times = get_project_settings().get('RETRY_TIMES', 3) ?# 获取全局设置的重试次数
request_retry_times = request.meta.get('retry_times', global_retry_times) ?# 获取请求的重试次数

或者,你在spiders的时候,meta函数里面添加个'RETRY_TIMES';例如:

  custom_settings = {
        'RETRY_TIMES': 3,  # 设置重试次数为 3 次
    }

    def start_requests(self):
        
            
            yield scrapy.Request(f'https://www.example.com/zq/1?date={self.timeday}', callback=self.parse,meta={'retry_times': self.settings.getint('RETRY_TIMES')})

最后,我再补个知识点(看了你的代码):

关于中间件的:
DOWNLOADER_MIDDLEWARES = {
   "你的爬虫名.middlewares.A!!!!Middleware": 543,
   "你的爬虫名.middlewares.B!!!!Middleware": 600,
   "你的爬虫名.middlewares.C!!!!Middleware": 900,
}

正常来说:

请求(request)的时候他的执行顺序,如你听到的--->从A到B到C;

但是:

响应(response)的时候,他的执行顺序,不如你所写--->从C到B到A!!!

对咯--->他是倒着来的! 不是按你理解的那个顺序跑的...

所以,别在不是处理异常的中间件类里边写异常~容易给你自己玩跑偏了,导致该接收异常的收不到!!!?

你去看看我

爬虫工作量由小到大的思维转变---<第二十八章 Scrapy中间件说明书>-CSDN博客

.... 在A类里边干B类的事,就是耍流氓....哪怕你发现了,什么都别做,他会根据流程滚到属于管他的那个类里边被处理掉的;放心...

总结:

1.重试是在做减法! 不要去给他+了;

2.不要一出异常就抛,给每个url请求一个机会,也有可能是咱网络或者IP其他别的问题呢?

3.彻底抛出url请求异常,最好写在重试次数结束之后;

文章来源:https://blog.csdn.net/m0_56758840/article/details/135232903
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。