如何将Scrapy抓取的单个元素拆分至CSV多行?
解决Scrapy导出CSV时每个Genre单独一行的问题
嘿,我太懂这种明明XPath已经精准拿到了genre列表,却卡在CSV输出格式上的挫败感了——试了一堆方案还是没搞定基础功能,确实闹心!下面给你两种靠谱的解决思路,都是我实际项目里用过的:
方法一:在Spider里直接拆分生成单个Item(推荐)
这是最直接的方式,在解析页面的时候,就把每个genre对应成一个独立的Item,这样后续导出CSV自然就是每行一个类型。
假设你的Item定义是这样的:
import scrapy class MovieItem(scrapy.Item): title = scrapy.Field() release_year = scrapy.Field() genre = scrapy.Field() # 注意这里是单个类型,不是列表
那在Spider的parse函数里,遍历拿到的genre列表,逐个生成Item:
def parse(self, response): # 先抓取其他固定字段 movie_title = response.xpath('//h1[@class="movie-title"]/text()').get().strip() release_year = response.xpath('//span[@class="release-year"]/text()').get().strip() # 通过XPath获取完整的genre列表 genre_list = response.xpath('//div[@class="genre-container"]/a/text()').getall() # 遍历每个genre,生成单独的Item for genre in genre_list: item = MovieItem() item['title'] = movie_title item['release_year'] = release_year item['genre'] = genre.strip() # 单个类型值 yield item
这样Scrapy默认的CSV导出器就能直接输出每行一个genre的结果,不需要额外修改Pipeline。
方法二:在Pipeline中拆分Item(适合已有的Spider不想大改的情况)
如果你的Spider已经输出了带genre列表的Item,不想改动Spider代码,可以在Pipeline里做拆分处理:
首先,自定义一个Pipeline类,负责拆分带列表的Item并导出:
from scrapy.exporters import CsvItemExporter class GenreSplitPipeline: def open_spider(self, spider): # 打开CSV文件并初始化导出器 self.csv_file = open('movies_with_genres.csv', 'wb') self.exporter = CsvItemExporter(self.csv_file) self.exporter.start_exporting() def close_spider(self, spider): self.exporter.finish_exporting() self.csv_file.close() def process_item(self, item, spider): # 检查Item里是否有genre列表字段 if 'genres' in item and isinstance(item['genres'], list): # 遍历每个genre,生成新的Item并导出 for genre in item['genres']: split_item = item.copy() split_item['genre'] = genre.strip() del split_item['genres'] # 删除原列表字段 self.exporter.export_item(split_item) else: # 如果没有列表,直接导出原Item self.exporter.export_item(item) return item
然后在settings.py里启用这个Pipeline,记得注释掉默认的CSV导出器:
ITEM_PIPELINES = { # 'your_project_name.pipelines.YourDefaultPipeline': 300, 'your_project_name.pipelines.GenreSplitPipeline': 300, }
关键注意事项
- 确保Item里的字段是单个值类型,不要用列表字段导出,否则默认CSV会把列表转成逗号分隔的字符串(比如
Mystery,Comedy),不是你想要的每行一个。 - 如果用方法一,记得把Item里的genre字段定义为单个值,而不是列表。
我之前处理电影类型导出时也踩过同样的坑,一开始总想在Pipeline里绕弯路,后来发现直接在Spider里拆分Item最省心,你可以试试这两种方法,应该能解决你的问题!
内容的提问来源于stack exchange,提问作者Charles Davidson
相关产品推荐
相关产品推荐

