Scrapy导出UTF-16编码CSV列合并问题(Python3.7+Scrapy1.6)
Scrapy阿拉伯语网站CSV导出:编码与分栏的矛盾解决
我来帮你搞定这个爬取阿拉伯语网站时遇到的CSV导出问题!你现在的困境是utf-16导出时列全混在一起,换其他编码又内容异常,这其实是Excel对不同编码的CSV解析逻辑导致的,下面给你几个实用的解决方案:
问题回顾
你用Python 3.7.1 + Scrapy 1.6.0爬取阿拉伯语网站时:
- 设置
FEED_EXPORT_ENCODING = 'utf-16'导出CSV,所有字段(Company_Name、Phone、Activity、Website、Company_Type)挤在同一列; - 用其他编码时,CSV能正常分栏,但阿拉伯语内容格式异常。
你的相关代码如下:
spider.py
# -*- coding: utf-8 -*- import scrapy from scrapy import Request from scrapy.loader import ItemLoader from Arabic_Companies.items import ArabicCompaniesItem class ArabicSpider(scrapy.Spider): name = 'arabic' handle_httpstatus_all = True def start_requests(self): url = "https://www.egycompanies.com/searchAr?name=&activity=&industry_id=0" yield Request(url, callback=self.parse) def parse(self, response): links = response.xpath("//div[@class='f-listings-item']") for link in links: Company_Name = link.xpath(".//div/div/div/h2[@class='f-listings-item__title']/a/text()").extract_first() Phone = link.xpath(".//*[contains(text(),' هاتف الشركة: ')]/following-sibling::text()[1]").extract_first() Activity = link.xpath(".//*[contains(text(),' النشاط: ')]/following-sibling::text()[1]").extract_first() Website = link.xpath(".//*[contains(text(),' الموقع الإلكترونى: ')]/following-sibling::a[1]/@href").extract_first() Company_Type = link.xpath(".//*[contains(text(),' التصنيفات : ')]/span/text()").extract_first() loader = ItemLoader(item=ArabicCompaniesItem(), response=response) loader.add_value('Company_Name', Company_Name) loader.add_value('Phone', Phone) loader.add_value('Activity', Activity) loader.add_value('Website', Website) yield loader.load_item()
items.py
import scrapy from w3lib.html import replace_escape_chars from scrapy.loader.processors import MapCompose, TakeFirst class ArabicCompaniesItem(scrapy.Item): Company_Name = scrapy.Field(input_processor= MapCompose(replace_escape_chars)) Phone = scrapy.Field(input_processor= MapCompose(replace_escape_chars)) Activity = scrapy.Field(input_processor= MapCompose(replace_escape_chars)) Website = scrapy.Field(input_processor= MapCompose(replace_escape_chars)) Company_Type = scrapy.Field(input_processor= MapCompose(replace_escape_chars))
settings.py
FEED_EXPORT_ENCODING = 'utf-16' FEED_EXPORT_FIELDS = ["Company_Name", "Phone", "Activity", "Website", "Company_Type"]
示例异常数据:
Company_Name,Phone,Activity,Website,Company_Type
أورينتال لمكسبات الطعم والرائحة, 0482590882, صناعات غذائية , http://www.oriental-off.com , شركات المواد الغذائية
解决方案
方案1:用utf-8-sig编码(最便捷)
这是解决问题的最优解!utf-8-sig会自动添加UTF-8的字节顺序标记(BOM),Excel能正确识别逗号分隔符,同时阿拉伯语内容也能正常显示,完美兼顾分栏和编码正确性。
修改settings.py的编码配置:
FEED_EXPORT_ENCODING = 'utf-8-sig' FEED_EXPORT_FIELDS = ["Company_Name", "Phone", "Activity", "Website", "Company_Type"]
导出后直接用Excel打开,就能看到正常分栏的阿拉伯语数据了。
方案2:坚持用utf-16?手动指定分隔符并正确解析
如果必须使用utf-16编码,需要调整CSV分隔符并手动告诉Excel解析规则:
- 修改
settings.py,把分隔符换成制表符:
FEED_EXPORT_ENCODING = 'utf-16' FEED_EXPORT_FIELDS = ["Company_Name", "Phone", "Activity", "Website", "Company_Type"] FEED_EXPORT_CSV_DELIMITER = '\t' # 用制表符替代逗号作为分隔符
- 用Excel打开文件时,不要直接双击,而是选择「数据」→「自文本/CSV」,然后手动设置:
- 文件编码选择
UTF-16 - 分隔符选择「制表符」
这样就能正确分栏显示数据了。
- 文件编码选择
额外优化:清理数据中的干扰字符
数据里的英文逗号可能会干扰CSV的分栏逻辑,建议在items.py里添加一个清理函数,把数据中的英文逗号替换成中文逗号(或者直接删除):
import scrapy from w3lib.html import replace_escape_chars from scrapy.loader.processors import MapCompose, TakeFirst def clean_commas(text): if text: return text.replace(',', ',') # 替换英文逗号为中文逗号,避免干扰CSV分隔 return text class ArabicCompaniesItem(scrapy.Item): Company_Name = scrapy.Field(input_processor= MapCompose(replace_escape_chars, clean_commas)) Phone = scrapy.Field(input_processor= MapCompose(replace_escape_chars, clean_commas)) Activity = scrapy.Field(input_processor= MapCompose(replace_escape_chars, clean_commas)) Website = scrapy.Field(input_processor= MapCompose(replace_escape_chars)) # 网址里的逗号保留 Company_Type = scrapy.Field(input_processor= MapCompose(replace_escape_chars, clean_commas))
这个小优化能避免因为数据本身带逗号导致的列混乱问题。
内容的提问来源于stack exchange,提问作者Ahmed Khaled
相关产品推荐
相关产品推荐

