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

Scrapy爬虫仅爬取最后一个链接下一页的问题求助

解决Scrapy循环爬取仅处理最后一个链接下一页的问题

嘿,这个坑我踩过好多次!你遇到的是Scrapy异步请求里典型的变量作用域延迟绑定陷阱——简单说就是循环生成请求时,所有请求共享了同一个循环变量的引用,等异步请求真正执行时,循环已经跑完,变量指向了最后一个元素,所以所有请求都用了最后那个链接的参数。

问题根源

Python里的循环变量是引用传递,而Scrapy的请求是异步的,循环会在所有请求发送前就执行完毕。比如你写了这样的代码:

def parse(self, response):
    links = ['link1', 'link2', ..., 'link10']
    for link in links:
        yield scrapy.Request(link, callback=self.parse_detail, meta={'current_link': link})

这里每个Request的meta['current_link']并没有保存循环时的link值,而是保存了对link变量的引用。等parse_detail回调执行时,循环已经结束,link已经变成了最后一个值(比如'link10'),所以所有请求的回调都拿到了最后一个链接。

两种快速解决办法

1. 用functools.partial绑定当前变量

这是最稳妥的方式,通过partial把循环时的当前链接绑定到回调函数的参数里,确保每个请求都持有独立的变量副本:

from functools import partial
import scrapy

class MySpider(scrapy.Spider):
    name = 'my_spider'
    start_urls = ['your_start_page_url']

    def parse(self, response):
        # 提取你要处理的10个链接
        links = response.xpath('//path/to/your/links/@href').getall()
        for link in links:
            # 用partial绑定当前的link到回调参数
            yield scrapy.Request(
                link,
                callback=partial(self.parse_detail, current_link=link),
                dont_filter=True  # 避免重复链接被过滤(如果需要的话)
            )

    def parse_detail(self, response, current_link):
        # 处理当前页面内容
        item = {
            'original_link': current_link,
            'content': response.xpath('//path/to/content/text()').get()
        }
        # 提取下一页链接
        next_page = response.xpath('//a[@rel="next"]/@href').get()
        if next_page:
            # 传递item和原始链接,继续爬下一页
            yield scrapy.Request(
                next_page,
                callback=self.parse_next_page,
                meta={'item': item},
                dont_filter=True
            )

    def parse_next_page(self, response):
        item = response.meta['item']
        item['next_page_content'] = response.xpath('//path/to/next/content/text()').get()
        # 导出item到JSON
        yield item

2. 用Lambda默认参数捕获当前值

如果不想导入partial,可以用Lambda的默认参数技巧,强制保存当前循环的变量值:

def parse(self, response):
    links = response.xpath('//path/to/your/links/@href').getall()
    for link in links:
        # 关键是这里的link=link,把当前值作为默认参数传入lambda
        yield scrapy.Request(
            link,
            callback=lambda response, link=link: self.parse_detail(response, link),
            dont_filter=True
        )

这里的link=link会把循环时的当前link值赋值给Lambda的默认参数,每个Lambda都会持有自己的独立副本,不会被后续循环覆盖。

验证方法

你可以在parse_detail里加一行打印:

def parse_detail(self, response, current_link):
    print(f"Processing link: {current_link}")
    # 其他逻辑...

运行爬虫后,如果控制台输出的是1到10的所有链接,说明问题解决了。

最后记得在settings.py里配置JSON导出:

FEEDS = {
    'output.json': {
        'format': 'json',
        'encoding': 'utf-8',
        'overwrite': True
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 03:36:14