监控与调试¶
运行摘要(机器可读)¶
每次爬虫结束,除了给人看的那行「爬虫结束 | 请求成功 63 …」,还会往 stdout 再打一行给机器看的:
NETSPY_RUN_SUMMARY {"schema":1,"request_ok":63,"items":60,"run_id":"...","spider":"BookSpider",...}
为什么单列一行:编排层(如 NetspyHub)读容器日志判成败,此前只能看 exit code——
一个空转的实例(种子锁还在、队列空、request_ok=0)照样 exit 0,被记成成功。
生产上一个定时任务两天里 1158/1160 个实例就是这么静默空转的(见
运行作用域)。这行摘要让「跑了」和「抓了」
从日志里一眼可分。
- 走 stdout,不走日志:不受
LOG_LEVEL影响(有人把 worker 压到WARNING), 也不带 loguru 的时间戳 / 颜色——解析方按前缀NETSPY_RUN_SUMMARY找到该行、 取其后的一段当 JSON 即可。 - 字段是对外契约:前缀、
schema、各计数键名都保持稳定;字段增删时schema+1。 - 关掉:
RUN_SUMMARY_ENABLE = False。在进程内嵌入爬虫、自己解析 stdout 的工具 (基准脚本、测试 harness)应关掉——那一行会混进你自己的输出里。
判「空转」:request_ok == 0 and items == 0(而进程 exit 0)。
run_id / namespace 只在设了运行作用域时非空,
用来把这行关联到具体实例 / 运行。
指标¶
METRICS_ENABLE = True
METRICS_LOG_INTERVAL = 10 # 每 10 秒打一行进度
METRICS_PROMETHEUS_PORT = 9100 # >0 且装了 netspy[metrics] 时起 exporter
进度行:
metrics - 进度 | 成功 1240 失败 12 重试 30 | 队列 88 在途 4 | 入库 1180 | 21.3 请求/s
Prometheus(http://localhost:9100/metrics):
netspy_request_ok 1240.0
netspy_request_failed 12.0
netspy_item 1180.0
netspy_queue_depth 88.0
netspy_in_flight 4.0
告警¶
WARNING_ENABLE = True
# 群机器人(配几个就发几个)
WARNING_FEISHU_WEBHOOK = "https://open.feishu.cn/open-apis/bot/v2/hook/xxx"
WARNING_DINGTALK_WEBHOOK = "https://oapi.dingtalk.com/robot/send?access_token=xxx"
WARNING_DINGTALK_SECRET = "SECxxx" # 「加签」模式的密钥;用「自定义关键词」则留空
WARNING_WECHAT_WEBHOOK = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx"
WARNING_EMAIL = dict(host="smtp.qq.com", port=465, ssl=True,
user="bot@qq.com", password="***", to=["me@corp.com"])
WARNING_FAILED_RATE = 0.5 # 失败率超 50% 告警
WARNING_MIN_REQUESTS = 50 # 少于 50 个请求不算失败率
WARNING_FAILED_COUNT = 1000 # 失败数超 1000 告警
WARNING_STALL_SECONDS = 600 # 10 分钟没有新的成功请求 = 卡死
WARNING_INTERVAL = 300 # 同类告警最小间隔,防刷屏
调度器在结束检测循环里顺带跑告警检查。默认还有一个 LogNotifier(写 WARNING 日志)。
钉钉的两种安全模式¶
钉钉群机器人必须配安全设置,两选一:
- 加签 —— 填
WARNING_DINGTALK_SECRET,框架自动带上timestamp和签名 - 自定义关键词 —— 不填 secret;消息标题固定带
【Netspy】, 把关键词设成Netspy即可
企业微信没有签名机制,webhook 里的 key 就是凭据。
发送失败会被记下来¶
三家群机器人在 webhook 失效、关键词不匹配、需要加签这些情况下都返回 HTTP 200, 真正的结果在响应体的错误码里。所以框架会检查状态码和响应体,被拒绝时记 ERROR 日志:
钉钉告警被拒绝:errcode=310000 keywords not in content
为什么要专门检查这个
告警系统静默失效是最坏的一种失效 —— 出事那天你才发现它自己早就哑了。
配好之后建议先手动触发一次(比如把 WARNING_STALL_SECONDS 调到 1 秒跑一遍),
确认群里真的收得到。
调试¶
NewsSpider(debug=True).start()
debug=True → 日志转 DEBUG、强制单线程,方便逐条跟踪。等价于
NETSPY_DEBUG=true NETSPY_LOG_LEVEL=DEBUG python main.py。
崩溃恢复¶
failed_requests.jsonl—— 中断退出时未完成的请求、以及重试耗尽的请求。netspy retry --requests是探活(重新下载看状态码,不跑回调、不入库,记录一条不删); 要把数据抓回来,开RETRY_FAILED_ON_START重跑一次爬虫 —— 那会把这些请求灌回队列, 走完整的下载 → 回调 → 落库failed_items.jsonl—— 写库失败的数据;netspy retry --items重放到管道