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

Scrapy爬虫:如何保存爬取的链接列表到文件并处理后续页面

解决Scrapy爬虫的两个核心问题

一、正确调用自定义页面处理函数

你之前尝试的parse_landing_page没生效,主要是代码里self.current未定义导致过滤逻辑失效,同时回调函数的调用逻辑也需要调整。下面是修正后的完整代码:

import scrapy
from scrapy.linkextractors import LinkExtractor

class MySpider(scrapy.Spider):
    name = "myspider"
    start_urls = ["https://books.toscrape.com/"]
    allowed_domains = ["books.toscrape.com"]  # 限制爬取范围,避免意外爬取外部链接

    def parse(self, response):
        to_avoid = ['tel','facebook','twitter','instagram','privacy','terms','contact','java','cookies','policies','google','mail']
        le = LinkExtractor(deny=to_avoid, allow_domains=self.allowed_domains)
        ex_links = le.extract_links(response)
        
        for href in ex_links:
            url = response.urljoin(href.url)
            # 先调用自定义函数处理当前页面数据
            yield response.follow(url, callback=self.parse_landing_page)
            # 继续跟进该页面下的子链接,维持爬取深度
            yield response.follow(url, callback=self.parse)

    def parse_landing_page(self, response):
        # 这里编写你处理每个页面的业务逻辑,比如提取页面信息
        page_info = {
            'url': response.url,
            'page_title': response.css('h1::text').get(default='无标题'),
            # 可添加更多需要提取的字段,比如价格、分类等
        }
        # 输出数据,供后续导出使用
        yield page_info

关键修正点:

  • 新增allowed_domains替代未定义的self.current,精准控制爬取范围
  • 每个链接同时触发两个回调:parse_landing_page处理页面数据,parse继续递归爬取子链接
  • 去掉类变量self.links,改用yield输出数据,符合Scrapy异步爬虫的设计规范,避免多线程环境下的数据异常

二、将爬取结果保存为CSV或JSON

Scrapy自带成熟的数据导出功能,无需手动编写文件操作代码,直接在命令行运行爬虫时指定输出文件即可:

保存为JSON格式

scrapy crawl myspider -o page_data.json

保存为CSV格式

scrapy crawl myspider -o page_data.csv

原理说明:

当你在parse_landing_page中yield字典(或Scrapy Item对象)时,Scrapy会自动收集所有输出数据,运行命令时通过-o参数指定文件路径和格式,就能直接导出结构化数据,比手动维护列表再写入文件更安全高效。

额外方案:手动保存链接列表(不推荐)

如果一定要用self.links存储链接,可以借助Scrapy的spider_closed信号,在爬虫结束时触发保存操作:

import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy import signals
from scrapy.signalmanager import dispatcher
import json
import csv

class MySpider(scrapy.Spider):
    name = "myspider"
    start_urls = ["https://books.toscrape.com/"]
    allowed_domains = ["books.toscrape.com"]
    links = []

    def __init__(self):
        # 绑定爬虫结束信号
        dispatcher.connect(self.on_spider_closed, signal=signals.spider_closed)

    def parse(self, response):
        to_avoid = ['tel','facebook','twitter','instagram','privacy','terms','contact','java','cookies','policies','google','mail']
        le = LinkExtractor(deny=to_avoid, allow_domains=self.allowed_domains)
        ex_links = le.extract_links(response)
        
        for href in ex_links:
            url = response.urljoin(href.url)
            if url not in self.links:  # 去重
                self.links.append(url)
                yield response.follow(url, callback=self.parse)
                yield response.follow(url, callback=self.parse_landing_page)

    def parse_landing_page(self, response):
        # 页面处理逻辑
        pass

    def on_spider_closed(self, spider):
        # 保存为JSON
        with open('all_links.json', 'w', encoding='utf-8') as f:
            json.dump(self.links, f, indent=2, ensure_ascii=False)
        # 保存为CSV
        with open('all_links.csv', 'w', newline='', encoding='utf-8') as f:
            writer = csv.writer(f)
            writer.writerow(['爬取链接'])
            for link in self.links:
                writer.writerow([link])

注意:这种方式仅适合小规模爬取,类变量self.links在多线程环境下可能出现数据丢失或重复,优先推荐使用Scrapy自带的导出功能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 00:01:31