SerpBase 采集脚本慢在哪?cProfile + py-spy 性能剖析实录

「脚本太慢了」是采集项目最常见的抱怨,但相当多的「优化」都优化错了方向:有人在优化 JSON 解析,实际瓶颈是每条记录 commit 一次;有人在调正则,实际时间全花在等接口响应上。慢分两种——「在等」和「在算」,先分清,再动手。 这篇用两个剖析工具(cProfile + py-spy)把一次批量采集剖开看。

第 0 步:先看「等」还是「算」

在剖析工具之前,先做最朴素的分段计时:

import time

t = time.perf_counter(); data = fetch(kw);   net  = time.perf_counter() - t
t = time.perf_counter(); rows = parse(data); cpu1 = time.perf_counter() - t
t = time.perf_counter(); store(rows);        db   = time.perf_counter() - t
print(f"net={net:.2f}s parse={cpu1:.2f}s db={db:.2f}s")

跑 20 个关键词汇总。这一步就能定性:net 占大头 = 在等(用并发/缓存/批量);parse/db 占大头 = 在算(上剖析工具找热点)。

第 1 步:cProfile 找 CPU 热点

import cProfile, pstats

def main():
    for kw in keywords:
        rows = parse(fetch(kw))
        store(rows)

cProfile.run("main()", "prof.out")
p = pstats.Stats("prof.out")
p.sort_stats("cumulative").print_stats(20)     # 先看 cumulative
p.sort_stats("tottime").print_stats(20)        # 再看 tottime(自身耗时)

读法两条:

  • cumulative(累计):这个函数连同它调用的子函数花了多少——用来定位「大块头」
  • tottime(自身):只算函数自己——用来揪出「自己就很贵」的热点(正则、序列化、日志格式化常见于此)

关键提醒:cProfile 不统计 I/O 等待。 如果你的时间花在等请求响应上,profile 出来会「一片平坦、没有热点」——这个「没有热点」本身就是最重要的线索:瓶颈在等,不在算。

第 2 步:py-spy 剖运行中的进程

cProfile 要改代码、有开销(跑一遍慢 2-3 倍),适合离线。生产里用 py-spy——不修改代码、不用重启:

pip install py-spy

py-spy top --pid 12345                      # 实时看各函数占用
py-spy record -o profile.svg --pid 12345    # 采一段生成火焰图

火焰图里横轴越宽 = 占用时间越多,一层层往下看就能从「main」追到具体热点。

第 3 步:一次真实案例的数字

批量采集 200 个关键词的一次剖析(数字为这次实测):

阶段 优化前 发现 优化后
总墙钟 6m05s — 3m10s
网络等待 ~4m40s I/O 主导 → 并发 4 + 命中缓存 ~2m10s
CPU 合计 ~40s JSON 解析 + 正则占 60% ~25s(减少正则,直取字段)
入库 ~35s 每条一次 commit → 批提交 ~6s

三个发现按「先等后算」的顺序处理:先解决等待(并发+缓存),再削 CPU 热点(解析),最后砍入库次数(批提交)。

第 4 步:优化的顺序原则

  1. 先看构成:等 vs 算(第 0 步)
  2. 等的部分:并发、缓存、批量化——收益大、风险低
  3. 算的部分:用 cumulative/tottime 找热点,一次改一处
  4. 每次改动后复测:同样的输入跑一遍,看数字变没变——没有测量就没有优化

踩坑记录

坑 1:拿 cProfile 找 I/O 瓶颈。 等待时间在 profile 里不显示,越看越迷惑。先分段计时。

坑 2:用小数据剖析。 10 个词的样本里「热点」是玄学。用真实量级跑。

坑 3:生产环境直接跑 cProfile。 开销 2-3 倍,把线上拖慢。生产用 py-spy。

坑 4:凭直觉优化。 「这行看起来慢」经常错——实测热点常是正则、序列化、循环里的日志格式化。

坑 5:忘了日志开销。 循环里每轮 print/logger 是真实热点(尤其写文件)。批量场景降日志级别或缓冲输出。

坑 6:优化完不复测。 改了三处感觉快了,实际互相抵消。一次一处、每次复测。

小结

性能剖析的路径:分段计时定性(等/算)→ cProfile 找 CPU 热点 → py-spy 看生产 → 按「等→算→入库」顺序优化 → 每次复测。这套下来,你优化的是「真实热点」,而不是「看起来慢的代码」。对采集脚本这类 I/O 混 CPU 的负载,「先分清在等还是在算」这一句话,能省掉一半无效工作。

响应信封里的 elapsed_ms(网关侧耗时)与本地分段计时对照,可以快速判断「慢在接口还是慢在本地」——字段说明见 SerpBase 官方文档。你们的采集脚本剖析过吗?最大的热点是什么?评论区聊聊。

posted @ 2026-10-14 08:55  蜘蛛人  阅读(4)  评论(0)    收藏  举报