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

Scrapy爬虫无法爬满单起始URL100页,请求排查与修正方案

问题分析与修复方案

核心问题

你的爬虫提前停止的根本原因有两个:

  1. 计数被重复初始化:每次调用parse方法时,都会重新执行self.counts = {url: 1 for url in self.start_urls},导致之前累计的爬取页数全部丢失,永远无法累计到100页。
  2. 分页URL逻辑错误:生成下一页URL时使用的是当前页的计数,而非下一页的页码,会导致重复爬取同一页,被Scrapy的去重机制拦截后提前停止。

修复方案(推荐使用meta传递页码)

这种方式不需要依赖实例变量,每个请求携带自身的页码,避免多线程并发下的计数混乱,逻辑更清晰:

import scrapy
from urllib.parse import urlparse, urlunparse

class YourSpider(scrapy.Spider):
    name = "your_spider"
    start_urls = ["url1", "url2", ...]  # 替换为你的起始URL列表

    def start_requests(self):
        # 为每个起始URL发起初始请求,携带初始页码1
        for url in self.start_urls:
            yield scrapy.Request(url, callback=self.parse, meta={"page": 1})

    def parse(self, response):
        current_page = response.meta["page"]
        
        # 达到100页则停止爬取当前URL的后续页面
        if current_page > 100:
            return

        # 解析当前页的内容,生成item请求
        for result in response.xpath(".//h2/a"):
            item_url = result.xpath("@href").extract_first()
            if item_url:
                yield scrapy.Request(url=item_url, callback=self.parse_item)

        # 生成下一页请求
        next_page = current_page + 1
        # 提取基础URL(去掉分页参数),避免重复拼接page参数
        parsed_url = urlparse(response.url)
        base_url = urlunparse(parsed_url._replace(query=""))
        next_page_url = f"{base_url}?page={next_page}"
        
        yield scrapy.Request(next_page_url, callback=self.parse, meta={"page": next_page})

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

备选方案(修正实例变量计数逻辑)

如果你坚持使用实例变量记录计数,需要将计数初始化移到爬虫的构造方法中,同时处理带分页参数的URL映射:

import scrapy
from urllib.parse import urlparse, urlunparse

class YourSpider(scrapy.Spider):
    name = "your_spider"
    start_urls = ["url1", "url2", ...]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 仅初始化一次每个起始URL的计数
        self.counts = {url: 1 for url in self.start_urls}

    def parse(self, response):
        # 提取不带分页参数的基础URL,作为计数的key
        parsed_url = urlparse(response.url)
        base_url = urlunparse(parsed_url._replace(query=""))
        
        count = self.counts.get(base_url, 1)
        if count > 100:
            return

        # 解析当前页内容
        for result in response.xpath(".//h2/a"):
            item_url = result.xpath("@href").extract_first()
            if item_url:
                yield scrapy.Request(url=item_url, callback=self.parse_item)

        # 更新计数并生成下一页请求
        next_count = count + 1
        self.counts[base_url] = next_count
        next_page_url = f"{base_url}?page={next_count}"
        
        yield scrapy.Request(next_page_url, callback=self.parse)

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

关键说明

  • 基础URL提取:必须将带分页参数的URL转换为基础URL(去掉?page=xxx部分),否则每个分页URL都会被当成新的key,计数永远停留在1。
  • meta传递页码的优势:Scrapy是异步多线程爬虫,实例变量可能被多个请求同时修改导致计数错误,而每个请求携带的meta参数是独立的,完全避免了并发问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 11:07:16