You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Scrapy遇错误仍持续遍历网站并完成爬虫任务?

解决Scrapy爬虫中断及无法返回黄页遍历循环的问题

看起来你的核心问题是:当爬虫尝试访问商家网站时,一旦遇到错误就停止,而且成功抓取后也没法回到黄页的主循环继续处理下一个商家或下一页。这主要是因为请求的meta配置和错误处理逻辑影响了Scrapy的调度流程,下面是具体的修复方案:

1. 优化错误处理函数,避免中断爬虫流程

你的handle_error目前只是简单打印请求,但可以更完善地记录错误,同时确保爬虫不会因为单个请求失败而终止。修改后的函数会详细记录错误URL和原因,且不需要返回任何内容——Scrapy会自动继续处理队列里的其他请求:

import logging

def handle_error(self, failure):
    # 记录详细的错误信息,方便后续排查
    error_url = failure.request.url
    error_msg = str(failure.value)
    self.log(f"Request failed for URL: {error_url} | Error: {error_msg}", level=logging.WARNING)

2. 调整请求的Meta参数,允许正常的重定向和重试

你之前给商家网站请求加了dont_redirect: True和dont_retry: True,这会导致很多正常的网站跳转(比如302重定向)被当成错误处理,甚至直接阻止爬虫重试。建议去掉这些限制,只针对明确的错误状态码处理:

# 替换原有的请求生成代码
if website:  # 直接判断website是否存在,而非和字符串"None"比较
    request = Request(
        url=website,
        callback=self.parse_email,
        errback=self.handle_error,
        meta={
            # 去掉不必要的限制,允许Scrapy处理正常重定向
            # 'dont_retry': True,
            # 'dont_redirect': True,
            'handle_httpstatus_list': [404, 500, 503],  # 只处理明确的服务器错误
            'data': {'Website': website}
        }
    )
    yield request

3. 修正parse_email的逻辑,确保流程正常结束

你的parse_email函数目前如果没找到邮箱,不会返回任何内容,但应该明确处理这种情况,同时给邮箱去重避免重复输出:

import re

def parse_email(self, response):
    data = response.meta.get('data', {})
    # 使用更通用的邮箱正则,适配非.com域名
    email_pattern = r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}'
    # 提取所有邮箱并去重
    emails = set(re.findall(email_pattern, response.text, re.IGNORECASE))
    
    if emails:
        for email in emails:
            item = data.copy()  # 复制字典避免修改原数据
            item['email_address'] = email.strip()
            yield item
    else:
        # 没有找到邮箱也返回记录,方便后续统计哪些网站无邮箱
        item = data.copy()
        item['email_address'] = None
        yield item

4. 修复下一页请求的配置

你给下一页请求也加了dont_retry和dont_redirect,这可能导致黄页的下一页无法正常加载。去掉这些限制,确保下一页请求能正常被处理:

next_page_url = response.xpath('//*[@class="next ajax-page"]/@href').extract_first()
if next_page_url:  # 先判断下一页链接是否存在,避免None值
    absolute_next_page_url = response.urljoin(next_page_url)
    yield Request(
        absolute_next_page_url,
        callback=self.parse,
        errback=self.handle_error
        # 去掉不必要的meta限制
        # meta={'dont_retry': True, 'dont_redirect':True}
    )

关键原理说明

Scrapy的请求是基于队列调度的:当你在parse里yield商家网站的请求时,这些请求会被加入调度队列,爬虫会在处理完当前黄页页面的所有商家请求后,自动回到parse的流程继续处理下一页。只要每个请求的错误都被errback正确捕获且不抛出致命异常,爬虫就会持续遍历所有黄页页面,同时处理每个商家网站的邮箱抓取。

内容的提问来源于stack exchange,提问作者gizaom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 13:42:46