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

无法在CrawlSpider内修改allowed_domains的并行爬虫问题求助

解决Scrapy并行爬虫中OffsiteMiddleware不识别动态设置allowed_domains的问题

问题核心在于默认OffsiteMiddleware会在爬虫初始化阶段就缓存allowed_domains,而你在start_requests中设置该属性的时机太晚,中间件已经完成初始化,无法读取到新值。以下是三种可行的解决方案:

方案1:在爬虫初始化时直接设置allowed_domains

重写爬虫的__init__方法,在初始化阶段就从settings中读取并赋值allowed_domains,确保OffsiteMiddleware初始化时能获取到正确的域名列表:

from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor

class DomainSpecificSpider(CrawlSpider):
    name = "domain_spider"
    rules = (
        Rule(LinkExtractor(), callback='parse_item', follow=True),
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 初始化阶段就从settings中读取allowed_domains和start_url
        self.allowed_domains = self.settings['crawl_start'][1]
        self.start_urls = [self.settings['crawl_start'][0]]

    def parse_item(self, response):
        # 你的解析逻辑
        pass

这种方法无需修改中间件,实现简单,适合大多数场景。

方案2:自定义OffsiteMiddleware支持动态读取allowed_domains

默认OffsiteMiddleware会在open_spider时缓存allowed_domains,自定义中间件可以跳过缓存,每次检查请求时直接读取当前爬虫的allowed_domains:

  1. 首先在项目的settings.py中禁用默认中间件,启用自定义版本:
SPIDER_MIDDLEWARES = {
    'your_project.middlewares.CustomOffsiteMiddleware': 500,
    'scrapy.spidermiddlewares.offsite.OffsiteMiddleware': None,
}
  1. 在middlewares.py中编写自定义中间件:
from scrapy.spidermiddlewares.offsite import OffsiteMiddleware

class CustomOffsiteMiddleware(OffsiteMiddleware):
    def should_follow(self, request, spider):
        # 每次检查请求时,实时读取爬虫当前的allowed_domains
        if not spider.allowed_domains:
            return True
        
        # 提取请求的域名并检查是否在允许列表内
        request_domain = request.url.split('/')[2]
        return any(request_domain.endswith(domain) for domain in spider.allowed_domains)

这种方法适合需要在爬取过程中动态调整allowed_domains的场景。

方案3:启动爬虫时直接传入参数(推荐多进程场景)

在多进程启动爬虫时,直接将allowed_domains和start_url作为参数传入爬虫,避免依赖settings传递,彻底消除竞争条件:

  1. 多进程启动代码示例:
from multiprocessing import Process
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
from your_project.spiders import DomainSpecificSpider

def run_single_spider(start_url, allowed_domains):
    settings = get_project_settings()
    process = CrawlerProcess(settings)
    # 直接将参数传入爬虫
    process.crawl(DomainSpecificSpider, allowed_domains=allowed_domains, start_urls=[start_url])
    process.start()

# 定义需要爬取的域名列表
crawl_tasks = [
    ("https://example.com", ["example.com"]),
    ("https://test.org", ["test.org"]),
]

# 启动多进程
processes = []
for url, domains in crawl_tasks:
    p = Process(target=run_single_spider, args=(url, domains))
    p.start()
    processes.append(p)

for p in processes:
    p.join()
  1. 爬虫代码调整:
class DomainSpecificSpider(CrawlSpider):
    name = "domain_spider"
    rules = (
        Rule(LinkExtractor(), callback='parse_item', follow=True),
    )

    def __init__(self, allowed_domains=None, start_urls=None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if allowed_domains:
            self.allowed_domains = allowed_domains
        if start_urls:
            self.start_urls = start_urls

    def parse_item(self, response):
        # 你的解析逻辑
        pass

这种方法参数传递更清晰,每个进程的爬虫配置独立,完全避免了settings共享导致的竞争问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 18:13:11