正则匹配匹配行下一行内容返回空,Scrapy爬取问题求助
解决Mercado Livre商品页window.__PRELOADED_STATE__数据提取问题
核心问题分析
你之前的正则存在两个关键缺陷:
- 第一个正则
r'(?s)window.__PRELOADED_STATE__ = (.+?\});'的非贪婪匹配会在遇到JSON嵌套的}时提前终止,导致提取内容不完整;同时对赋值符号与JSON之间的空格/换行兼容性不足。 - 第二个正则
r'(?s)window.__PRELOADED_STATE__ = +([^\r\n]+)'中[^\r\n]+明确排除了换行符,直接导致目标内容在下一行时匹配失败,即使启用了(?s)也无效。
实用解决方案
方案1:用字符串分割提取(新手友好,容错性高)
先定位包含目标内容的script标签,再通过字符串分割精准截取JSON部分,避免正则的贪婪/非贪婪陷阱:
import json from scrapy import Spider class MercadoLivreSpider(Spider): name = 'mercadolivre' start_urls = ['你的目标URL'] def parse(self, response): # 定位包含window.__PRELOADED_STATE__的script标签 script_text = response.xpath('//script[contains(text(), "window.__PRELOADED_STATE__")]/text()').get() if not script_text: self.logger.warning(f"No target script found for {response.url}") return try: # 分割出JSON字符串并补全闭合大括号 preloaded_str = script_text.split('window.__PRELOADED_STATE__ = ')[1].split('};')[0] + '}' # 解析为JSON对象 preloaded_data = json.loads(preloaded_str) # 示例:提取商品标题 product_title = preloaded_data.get('product', {}).get('name') yield {'title': product_title} except (IndexError, json.JSONDecodeError) as e: self.logger.warning(f"Failed to extract data: {str(e)} for {response.url}")
方案2:改进后的正则表达式(适合格式规范的页面)
如果页面格式相对统一,可使用兼容多行、匹配完整JSON的正则:
import re import json # 在parse方法中替换分割逻辑为: pattern = r'window\.__PRELOADED_STATE__\s*=\s*({.*?});' match = re.search(pattern, script_text, re.DOTALL) if match: try: preloaded_data = json.loads(match.group(1)) # 处理数据... except json.JSONDecodeError: self.logger.warning("JSON decode failed for PRELOADED_STATE")
\s*匹配任意数量的空格/换行,兼容赋值符号与JSON之间的各种格式re.DOTALL让.匹配换行符,支持跨多行的JSON内容- 注意:若JSON存在多层嵌套,非贪婪匹配
.*?可能仍会提前终止,此时优先用方案1。
额外建议
- 优先使用字符串分割方案,逻辑简单直观,新手更容易调试和维护。
- 若遇到极端复杂的JavaScript代码(比如JSON被压缩或混淆),可尝试用
execjs库直接执行脚本获取数据,但需要提前安装Node.js环境。 - 测试时可先把
script_text打印出来,复制到本地编辑器或JSON校验工具中,确认分割/正则的截取范围是否正确。
内容的提问来源于stack exchange,提问作者Vitor Pinheiro
相关产品推荐
相关产品推荐

