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

Scrapy读取CSV中URL与域名遍历异常问题求助

嘿,我来帮你搞定这个Scrapy的问题!你遇到的两个坑——缩进错误和只识别最后一个域名,其实都是爬虫开发里的常见问题,咱们一步步拆解解决:

解决Scrapy遍历多域名/URL并导出全站URL的问题

一、先搞懂问题根源

  1. 缩进错误:这是Python语法的硬要求,Scrapy的爬虫类、方法(比如start_requests、parse)必须严格遵循缩进层级——类内的方法要缩进4个空格,方法内的代码再缩进一层,稍微错一点就会报错,得仔细核对代码结构。
  2. 仅识别最后一个域名:大概率是你循环CSV数据时,直接给start_urls赋值,每次循环都会覆盖之前的列表,最后只留下最后一条数据;或者没给每个域名生成独立的请求/爬虫实例,导致前面的请求被覆盖了。

二、完整可落地的实现方案

下面给你一套从读取CSV、生成多域名请求到Pipeline导出的完整代码:

1. 先明确CSV格式

假设你的CSV文件(命名为targets.csv)是这样的结构:

domain,start_url
example.com,https://example.com
test.org,https://test.org/home

2. 编写爬虫文件(spiders/domain_spider.py)

核心是不要直接给start_urls赋值,而是用start_requests遍历CSV生成请求,同时把域名通过meta传递给解析函数,这样后续爬取时能判断URL是否属于当前域名:

import scrapy
import csv
from urllib.parse import urlparse

class DomainSpider(scrapy.Spider):
    name = 'domain_spider'

    def start_requests(self):
        # 读取CSV文件,注意路径如果不是项目根目录要写绝对路径
        with open('targets.csv', 'r', encoding='utf-8') as f:
            reader = csv.DictReader(f)
            for row in reader:
                target_domain = row['domain']
                start_url = row['start_url']
                # 把目标域名塞进meta,传给后续解析函数
                yield scrapy.Request(
                    url=start_url,
                    callback=self.parse,
                    meta={'target_domain': target_domain}
                )

    def parse(self, response):
        target_domain = response.meta['target_domain']
        # 提取当前页面所有链接
        all_links = response.css('a::attr(href)').getall()

        for link in all_links:
            # 把相对URL转为绝对URL
            absolute_url = response.urljoin(link)
            # 解析URL的域名,判断是否属于目标域名
            parsed_url = urlparse(absolute_url)
            # 这里可以根据需求调整,比如兼容带www的域名:parsed_url.netloc.replace('www.', '') == target_domain
            if parsed_url.netloc == target_domain:
                # 把域名和URL封装成Item,交给Pipeline处理
                yield {'domain': target_domain, 'url': absolute_url}
                # 递归爬取该域名下的其他页面,继续传递meta
                yield scrapy.Request(
                    url=absolute_url,
                    callback=self.parse,
                    meta={'target_domain': target_domain}
                )

3. 编写Pipeline导出到CSV(pipelines.py)

这里实现把所有域名的URL导出到一个CSV,用domain字段区分:

import csv

class DomainUrlExportPipeline:
    def open_spider(self, spider):
        # 打开CSV文件,写入表头
        self.file = open('domain_urls.csv', 'w', encoding='utf-8', newline='')
        self.writer = csv.writer(self.file)
        self.writer.writerow(['domain', 'url'])

    def close_spider(self, spider):
        self.file.close()

    def process_item(self, item, spider):
        # 写入每行数据
        self.writer.writerow([item['domain'], item['url']])
        return item

4. 配置settings.py

记得启用Pipeline,同时设置基础爬取规则避免重复请求:

# 启用自定义Pipeline,优先级300
ITEM_PIPELINES = {
    'your_project_name.pipelines.DomainUrlExportPipeline': 300,
}

# 启用URL去重过滤器,避免重复爬取同一页面
DUPEFILTER_CLASS = 'scrapy.dupefilters.RFPDupeFilter'
DUPEFILTER_DEBUG = True

# 设置下载延迟,降低被反爬的概率
DOWNLOAD_DELAY = 1

三、额外注意事项

  • 缩进检查:写完代码后,确认所有方法(比如start_requests、parse)都在DomainSpider类的缩进层级下,方法内的代码缩进一致,Python对缩进零容忍。
  • 域名兼容:如果你的CSV里域名不带www,但目标网站的链接带www,可以修改域名判断逻辑,比如parsed_url.netloc.replace('www.', '') == target_domain。
  • CSV路径:如果targets.csv不在项目根目录,一定要写绝对路径,或者放在爬虫文件同目录下。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:41:29