常见原因有三:js动态渲染导致requests无法获取真实价格;缺少user-agent等请求头被拦截;字体映射使数字显示为乱码。应优先抓api、加完整headers、解析woff字体文件。

用 requests + BeautifulSoup 抓取商品价格时,为什么总返回空或乱码?
常见现象是 response.text 里找不到价格数字,或者抓到的是“¥”后面跟一串乱码(如 ),甚至直接返回 403。这不是代码写错了,而是网站做了基础反爬:
- 多数电商页价格由 JavaScript 动态渲染,
requests拿不到真实 DOM - 缺少
User-Agent或Accept-Encoding头,被服务器直接拦截 - 页面用了字体映射(如阿里系常用 custom font 将数字替换成符号),需额外解析字体文件或匹配 CSS 类
实操建议:
- 先用浏览器开发者工具(Network → XHR/Fetch)找价格接口,优先调用 API 而非解析 HTML
- 若必须解析 HTML,加完整 headers:
{"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", "Accept": "text/html"} - 遇到字体混淆,查
@font-face的 URL,下载 .woff 文件并用fontTools解析字形映射表(小众但有效)
定时任务选 APScheduler 还是系统 cron?
APScheduler 在 Python 进程内跑,适合单机轻量监控;cron 更稳定、不依赖 Python 环境,但调试成本高。关键区别不在“能不能用”,而在“挂了怎么办”:
-
APScheduler的BackgroundScheduler一旦主进程退出就停,没持久化、无失败重试 - cron 不会自己记录日志,出错只能靠重定向 stderr,排查慢
实操建议:
- 小范围测试用
APScheduler,加try/except包住整个抓取逻辑,并写入本地 CSV 日志 - 上生产环境一律用 cron,配合
python -m venv隔离环境,命令形如:0 <em>/2 </em> <em> </em> cd /opt/price-mon && ./venv/bin/python monitor.py >> /var/log/price.log 2>&1 - 必须加超时控制:
requests.get(url, timeout=(3, 7)),避免单次卡死拖垮整个调度
怎么判断价格真变了,而不是页面抖动或缓存差异?
直接比对字符串“¥299”和“¥299.00”会误报;更糟的是,有些站用 CDN 缓存,同一 URL 两次请求返回不同价格(A/B 测试或地域分发)。不能只看值,要看上下文稳定性:
- 同一商品 ID(如
data-sku-id或 URL 中的pid=)下,连续 2 次间隔 5 分钟的抓取结果一致,才记为有效快照 - 价格字段应提取原始数值(去符号、转
float),而非保留格式字符串 - 记录响应 HTTP 状态码和
response.headers.get("Date"),时间戳偏差 >30 秒即丢弃该次数据
实操建议:
- 本地存 SQLite,表结构至少含:
sku_id TEXT, price REAL, fetched_at TIMESTAMP, status_code INTEGER, url TEXT - 每次写入前查最近 2 条同
sku_id记录,用abs(price - prev_price) > 0.01判断变动(别用!=) - 对 JS 渲染页,用
selenium或playwright截图+OCR 是下策,仅当 API 完全不可用时启用
通知渠道选微信还是邮件?怎么避免被当垃圾信息?
微信模板消息接口已收紧,个人号用 itchat 或 wechaty 容易被封;企业微信 Webhook 最稳,但需提前配好机器人。邮件看似古老,其实打开率高、过滤少,关键是头信息要合规:
- 邮件主题带变动幅度(如
[↓12%] iPhone 15 Pro 价格降至 7299),正文必须含时间、来源 URL、前后价格、变动百分比 - 微信推送每条得带跳转链接,且链接域名必须在机器人后台白名单里,否则点不开
实操建议:
- 用微信时,用
requests.post(webhook_url, json={"msgtype": "text", "text": {"content": "..."} }),内容里 URL 用短链(如tinyurl.com)绕过风控 - 发邮件用
smtplib+email.mime,别用第三方 SDK,避免多一层依赖;From 地址必须是发信域名的邮箱(如monitor@yourdomain.com),否则进垃圾箱 - 所有通知加开关:配置文件里设
NOTIFY_ON_CHANGE_ONLY = True,首次抓取不发,只变价才触发
价格监控真正难的不是“怎么拿到”,而是“怎么信它”。页面改版、CDN 切流、反爬策略升级,都会让昨天好用的 selector 今天返回 None。留一手:每次抓取都存原始 response.content 到磁盘(按日期+SKU 命名),出问题时能立刻回溯是前端改了,还是 selector 写窄了。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











