Scrapy读取CSV中URL与域名遍历异常问题求助
嘿,我来帮你搞定这个Scrapy的问题!你遇到的两个坑——缩进错误和只识别最后一个域名,其实都是爬虫开发里的常见问题,咱们一步步拆解解决:
解决Scrapy遍历多域名/URL并导出全站URL的问题
一、先搞懂问题根源
- 缩进错误:这是Python语法的硬要求,Scrapy的爬虫类、方法(比如
start_requests、parse)必须严格遵循缩进层级——类内的方法要缩进4个空格,方法内的代码再缩进一层,稍微错一点就会报错,得仔细核对代码结构。 - 仅识别最后一个域名:大概率是你循环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
相关产品推荐
相关产品推荐

