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

Scrapy的start_requests含多个start_url时仅爬取第一页如何解决

问题根因分析
  • Scrapy默认采用异步并发调度模式,所有请求默认优先级相同,多个初始start_url提交后,不同auction_id的列表页、详情页、翻页请求会混合进入调度队列并行执行
  • 该目标站点对单客户端会话存在访问限制:同一时间仅支持处理一个拍卖分类(auction_id)的请求,多分类并行请求时会被站点拦截,导致翻页请求无法正常返回有效内容,因此每个初始url仅能爬取第一页
  • 爬虫逻辑本身无语法错误,其他站点运行正常是因为对应站点没有类似的会话/分类并行访问限制
解决方案

方案1:单分类串行爬取(完全满足处理完第一个start_url全量再处理下一个的需求)

核心逻辑是通过Spider实例变量存储待处理任务队列,仅在当前分类所有页面爬取完成后再提交下一个分类的初始请求,修改后的完整代码如下:

import scrapy
import re
import hashlib
from lotbot.items import LotbotItem
from scrapy import Request

class VendunotarisSpider(scrapy.Spider):
    name = "vendurotterdam"
    allowed_domains = ['vendurotterdam.nl']

    def __init__(self, *args, **kwargs):
        super(VendunotarisSpider, self).__init__(*args, **kwargs)
        # 存储所有待处理的拍卖任务
        self.task_queue = [[1777, 'https://vendurotterdam.nl/catalogus/?auction_id=1229'], [1761, 'https://vendurotterdam.nl/catalogus/?auction_id=1224'], [1731, 'https://vendurotterdam.nl/catalogus/?auction_id=1225']]

    def start_requests(self):
        # 启动时仅提交第一个任务
        if self.task_queue:
            first_task = self.task_queue.pop(0)
            yield Request(url=first_task[1], callback=self.parse_list, cb_kwargs=dict(sale=first_task[0]))


    def parse_list(self, response, sale):
        lot_page_links = response.css('div.items div#objectinfo div.col-lg-12.col-xs-12 a')
        yield from response.follow_all(lot_page_links, self.parse_lot, cb_kwargs=dict(sale=sale))

        pagination_links = response.xpath("//div/a[contains(text(), 'Volgende')]")
        if pagination_links:
            # 有下一页,继续提交当前分类的翻页请求
            yield from response.follow_all(pagination_links, self.parse_list, cb_kwargs=dict(sale=sale))
        else:
            # 当前分类爬取完成,提交下一个待处理任务
            if self.task_queue:
                next_task = self.task_queue.pop(0)
                yield Request(url=next_task[1], callback=self.parse_list, cb_kwargs=dict(sale=next_task[0]))


    def parse_lot(self, response, sale):
        def extract_with_css(query):
            return response.css(query).get()

        item = LotbotItem()
        item['source_url'] = response.request.url
        item['catalog_url'] = response.request.url
        item['productId'] = response.xpath('//table/tr[1]/td[3]/b/text()').get()
        item['name'] = extract_with_css('h1.item-detail-title::text')
        if extract_with_css('div.modal-body') is None:
            item['description'] = extract_with_css('span.title::text') + ' ' + response.xpath('/html/body/div/div/div[2]/section/div[1]/div/div/div[2]/div/div[2]/div[2]/text()').getall()[2]
        else:
            item['description'] = extract_with_css('div.modal-body::text') + ' ' + response.css('div.col-lg-6.col-md-6.col-sm-6.detail-right div ::text').getall()[8]
        relative_img_urls = response.css('div.slider_image div a::attr(href)').get()
        item['image_urls'] = [relative_img_urls]
        item['estimates'] = response.css('div.box-black.pull-right::text').get()
        item['price_result'] = response.xpath('//td[contains(@id,"highest_bid_td")]/text()').get()
        checksum_string = str(sale) + response.request.url
        item['checksum'] = hashlib.md5(checksum_string.encode('utf-8')).hexdigest()
        item['sale_id'] = sale

        yield item

    def url_join(self, urls, response):
        joined_urls = []
        for url in urls:
            joined_urls.append(response.urljoin(url))

        return joined_urls

方案2:并发适配方案(无需修改爬虫逻辑,仅调整配置)

如果不想用串行模式牺牲爬取效率,可以在settings.py中添加以下配置适配站点限制:

# 限制同一域名下并发请求数为1,所有请求按顺序执行
CONCURRENT_REQUESTS_PER_DOMAIN = 1
# 设置请求间隔,避免触发站点频率限制
DOWNLOAD_DELAY = 1
# 启用cookie保持同一会话
COOKIES_ENABLED = True
额外排查建议

可开启Scrapy的Debug日志模式,查看多start_url场景下翻页请求的响应状态码和返回内容,确认是否存在站点拦截类的响应。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 22:06:00