使用Scrapy爬取Petlebi网站时JSON非法换行符的解决方案
解决Scrapy解析petlebi.com产品JSON时的换行符解析错误问题
问题根源
目标网站返回的application/ld+json脚本中,description字段包含未转义的字面换行符(\n/\r),违反了JSON语法规范——JSON字符串内部的换行必须转义为\\n。html.unescape无效是因为这不是HTML实体转义问题,而是JSON本身的格式错误。
通用解决方案:预处理JSON字符串修复非法字符
通过正则匹配JSON中的字符串部分,仅替换字符串内部的非法换行符(不破坏JSON的结构换行),再用标准json.loads解析。
1. 编写修复函数
import re import json def fix_malformed_json(json_str): """修复JSON字符串中未转义的换行符及控制字符""" def sanitize_string(match): # 提取匹配到的带双引号的字符串 raw_str = match.group(0) # 替换字符串内部的换行、回车、制表符为转义形式 cleaned_str = raw_str.replace('\n', '\\n').replace('\r', '\\r').replace('\t', '\\t') return cleaned_str # 正则匹配所有双引号包裹的字符串(兼容转义的双引号\") fixed_json = re.sub(r'"(?:\\.|[^"\\])*"', sanitize_string, json_str) return fixed_json
2. 在Scrapy爬虫中集成
import scrapy class PetlebiSpider(scrapy.Spider): name = 'petlebi' start_urls = ['https://www.petlebi.com/'] # 替换为目标产品页或列表页 def parse(self, response): # 提取application/ld+json脚本内容 json_content = response.xpath('//script[@type="application/ld+json"]/text()').get() if not json_content: self.logger.warning("未找到目标JSON脚本") return try: # 修复JSON格式 fixed_content = fix_malformed_json(json_content) # 解析修复后的JSON product_data = json.loads(fixed_content) # 提取所需字段(根据实际JSON结构调整) yield { 'product_name': product_data.get('name'), 'description': product_data.get('description'), 'price': product_data.get('offers', {}).get('price'), 'product_url': product_data.get('url') } except json.JSONDecodeError as e: self.logger.error(f"解析失败(URL: {response.url}): {str(e)}") # 可选:保存错误的JSON内容用于调试 with open(f"error_{response.url.split('/')[-1]}.json", 'w', encoding='utf-8') as f: f.write(json_content)
额外优化建议
- 扩展字符处理:如果遇到其他非法控制字符(如垂直制表符),可以在
sanitize_string函数中添加对应替换规则。 - 调试错误案例:对解析失败的页面,保存原始JSON内容,分析是否有其他格式问题(如未闭合的引号、多余的逗号)。
- 性能考量:正则匹配对大规模爬取影响不大,若需极致性能,可考虑使用状态机逐字符处理JSON字符串。
内容的提问来源于stack exchange,提问作者esyilmaz
相关产品推荐
相关产品推荐

