一个 Python 采集程序昨天还能提取商品名称,今天却只得到“请完成验证”。问题通常不在 BeautifulSoup 的选择器:程序可能根本没有拿到商品页面。此时最值得做的改动,是让获取函数能够明确返回“有效内容”或“访问诊断”,而不是把所有响应都交给解析器。
如果目标确实返回受支持的 DataDome 挑战,可以评估穿云API的 DataDome 验证处理。先测试目标兼容性,再接入现有 requests 工作流;不要把某个页面测试通过理解为全站、所有请求类型都支持。

先找出失效的那一层
保存一次失败请求的状态码、最终 URL、Content-Type 和脱敏后的正文摘要。对照程序预期:商品页应该包含商品标识或标题,而不是拼图、验证提示或拒绝访问说明。空的解析结果只能说明业务字段没有提取成功,不能证明页面没有商品。
同样要分清读取方式。HTML 页面、页面内嵌 JSON 和单独的 JSON 接口是三个不同的输入。列表页面可访问,不代表详情接口也具备相同权限或验证流程。先选一个获准的、能稳定复现问题的 URL 做测试,避免一开始就把批量任务全部切换。
最小改动:给采集程序增加一个访问适配器
把原来散落在业务代码中的 requests.get 收拢到获取函数。这个函数负责调用已确认的 API 连接方式、设置时间限制并返回规范化响应。下游仍使用原来的商品解析器。这样可以单独替换访问方式,而不影响去重、字段清洗和数据库写入。
下面只是应用内部的接口示意,不是穿云API的 SDK,也不包含可直接调用的 DataDome 端点。真正的认证、目标传递和响应解包方式,按当前 API 文档及目标测试结果填写。
def collect_product(url, access_adapter, parser):
result = access_adapter.fetch(url)
if result.kind != "expected_content":
return {"status": "not_collected", "reason": result.kind}
product = parser(result.body)
if not product.get("product_id"):
return {"status": "schema_mismatch"}
return {"status": "collected", "product": product}
不要在适配器里把验证失败转换为空字符串。那会让业务层误判为“商品下架”。失败类型应保留,至少区分连接超时、认证配置错误、验证未完成和内容结构变化。日志记录请求编号和耗时,不记录完整密钥、代理凭证或 Cookie。
requests.Session 有用,但不是验证码处理器
Requests 的 Session可保留 Cookie 等状态。对于一个需要延续上下文的访问序列,反复创建全新 Session 可能丢失你刚建立的状态。不过,保留本地 Session 与 API 服务端会话并不天然等价,仍要核对该接入模式要求如何传递和保存状态。
连接超时与读取超时也应明确设置。连接失败、响应迟迟没有结束和得到验证页,是不同故障。重试只针对允许恢复的情况,设上限并遵守访问频率限制;明确的访问拒绝应暂停任务,不进行无休止的“再试一次”。
用一个小样本证明改动有效
建议先验证三件事:正文包含预期商品标识;同一获准任务的下一次请求没有意外丢失上下文;模拟失败时数据没有被错误写入。验证通过后逐步扩大批量范围,同时观察有效记录数、失败分类和单条有效记录的成本。
准备接入穿云API时,提供目标 URL、页面或接口类型、脱敏响应以及 Python 程序的获取方式。目标明确,才能判断接入应该发生在哪一层。你的目标不是让 requests “看起来成功”,而是让后面的解析器重新收到可以信任的数据。
