首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >用纯 API 替代浏览器自动化:从 5 小时卡死到 8 分钟跑通的实战复盘

用纯 API 替代浏览器自动化:从 5 小时卡死到 8 分钟跑通的实战复盘

原创
作者头像
用户12457203
修改2026-07-29 18:20:05
修改2026-07-29 18:20:05
610
举报

用纯 API 替代浏览器自动化:从 5 小时卡死到 8 分钟跑通的实战复盘

Web 数据抓取 · 接口逆向 · Node.js 实战

一次数据导出任务:原本走浏览器模拟点击路线耗了 5 小时,后来通过抓包发现后台接口、改用纯 HTTP 调用,8 分钟搞定 429 条记录。本文记录完整思路转折、接口调用方案和踩坑细节。


一、任务背景

需求:将某语音转文字平台(SaaS 服务)上的数百条录音记录批量导出为「音频 MP3 + 转写 Word」,文件名统一加日期前缀并按录制时间排序。后续还需要清理旧文件释放存储空间,但不能误删未整理的数据。

关键约束:

  • 导出每条记录的音频文件和转写文本
  • 按录制时间由近及远排序,文件名加 YYYY-MM-DD_ 前缀
  • 平铺存到本地磁盘(不分子目录)
  • 清理旧数据时必须有备份校验,不能误删

二、第一条错误路线:浏览器自动化

一开始用的是浏览器模拟操作方案:打开每个记录的详情页、从 DOM 提取数据、触发下载。这条路线遇到了一系列典型问题:

问题

影响

需要逐个打开详情页

429 条记录就要加载 429 个页面

SPA 渲染等待

每页需要等待 JS 渲染完成才能提取数据

弹窗拦截

程序化的 window.open() 经常被浏览器拦截

选择器不稳定

页面改版后选择器失效,脚本中断

登录态维护

Cookie 过期后需要重新登录

结果:跑了 5 小时还没跑完一半,而且中途因为各种异常断了好几次。


三、转折:从"模拟人操作"到"直接调接口"

注意到该平台的网页端本身就有"勾选 50 条批量下载"的功能——这说明后台一定有批量操作的接口。既然网页能调,脚本也能直接调。

思路转变:不该教脚本怎么"假装是人",而是找到网页在用什么接口,然后直接复用那些接口。

3.1 抓包找接口

打开浏览器开发者工具(F12)→ Network 面板 → 在网页上手动触发一次列表加载/下载操作,观察实际发出的请求。

本次抓包发现的三个核心接口:

用途

方法

路径模式

说明

列表分页

POST

/api/v2/records/list

游标分页,支持拉全量

音频下载

GET

/api/v1/audio/{id}/url

返回带签名的临时下载地址

转写文本

GET

/api/v1/transcript/{id}/text

返回 JSON 格式的逐字稿

注:以上路径为示例模式,实际路径因平台而异。关键是先抓包确认真实接口,不要猜测。

3.2 认证方式

大多数 SaaS 平台的网页端认证基于 Cookie。获取方式:

  1. 用户在浏览器中正常登录
  2. 通过 Chrome DevTools Protocol (CDP) 或浏览器扩展提取 Cookie
  3. 后续 API 请求携带相同 Cookie 即可鉴权

安全提醒: Cookie 含敏感登录态,脚本中不应硬编码。建议运行时动态获取,用完即弃。


四、纯 API 方案实现

切换到纯接口调用后,核心流程大幅简化:

获取 Cookie → 循环拉列表分页 → 对每条记录并行请求音频URL和转写文本 → 下载写入本地文件

4.1 列表分页

分页接口采用游标模式(cursor pagination),每次请求返回一页数据和下一页游标,直到游标为空表示结束。

// 伪代码:游标分页拉全量 let cursor = null; const allRecords = []; do { const resp = await httpPost(LIST_API, { cursor, pageSize: 50 }); allRecords.push(...resp.records); cursor = resp.nextCursor; } while (cursor);

注意:必须正确处理末页条件。 有些接口末页返回空数组,有些返回 hasMore: false,有些返回 nextCursor: null。处理不当会导致死循环(本次踩过这个坑,脚本跑到 60 多页才停)。

4.2 并发控制

429 条记录,每条需要 2~3 次 API 请求(音频 URL + 转写文本 + 下载)。全部串行太慢,全部并发又可能触发限流。

折中方案:使用并发池(concurrency pool),控制同时请求数:

// 伪代码:并发池控制 const pool = new ConcurrencyPool({ maxConcurrency: 5 }); for (const record of allRecords) { await pool.add(() => downloadRecord(record)); } await pool.done();

4.3 文件名解析

原始文件名格式五花八门,需要统一解析出录制日期:

原始格式

示例

解析结果

中文日期

2022年9月3日录音

2022-09-03

横杠分隔

20251210_文件名

2025-12-10

点分分隔

2025.6.12

2025-06-12

紧凑数字

20221103

2022-11-03

无日期

会议录音001

使用创建时间补

日期正则要点: 必须加前缀约束(如年份以 19/20 开头)和月日范围校验(月 1-12,日 1-31),否则手机号之类的数字串会被误判为日期。


五、旧数据安全清理

备份完成后清理旧数据释放空间。这里的核心挑战是如何只删该删的、绝不误删

5.1 安全设计

利用业务规则实现天然隔离:该平台的"未整理"数据在 PC 端不可见,也不出现在接口返回的列表中。因此通过接口筛选删除目标时,未整理数据天然不会被选中。

5.2 删除接口

大多数平台提供两步删除机制:

操作

语义

说明

回收(recycle)

移入回收站

可恢复,通常 7 天后自动清除

彻底删除(delete)

从回收站永久删除

不可恢复

建议: 脚本默认只执行回收操作(soft delete),且必须先 dry-run 输出清单让用户确认。

5.3 过滤规则

按文件名中的录制日期过滤(不能用同步时间,那个是操作当天的日期)。只删同时满足以下条件的记录:

  1. 文件名中的录制日期 ≤ 目标截止日期
  2. 本地已有对应的备份文件(mp3 或 docx 至少有一个)
  3. 日期能正确解析(解析不出年份的保守跳过)

六、踩坑汇总

阶段

解法

1

浏览器自动化跑了 5 小时没跑完

方案选择

放弃浏览器自动化,改用纯 API

2

分页死循环跑到 60 页

接口调用

末页必须正确判断退出条件

3

手机号被日期正则误匹配

命名解析

加年份前缀 + 月日范围双重约束

4

旧数据漏删——用了同步时间而非录制日期

过滤逻辑

统一按文件名中的日期过滤

5

有备份的记录被判无备份

命名一致性

多脚本的命名函数必须字符级一致

6

点分日期格式未被识别

正则覆盖

补充 \d{4}.\d{1,2}.\d{1,2} 模式

7

接口超时导致脚本挂死

工程实践

所有 HTTP 请求设置超时(建议 20s)


七、方法论总结

1. 先抓包再动手

任何网页数据操作任务,第一步不是写爬虫代码,而是打开 DevTools 看它实际调了什么接口。有现成的 API 就直连,效率差几个数量级。

2. 破坏性操作必须分层

把流程拆成"只读导出"和"写删除"两步,删除步骤默认 dry-run、强制备份校验。这一条能避免绝大多数灾难性误操作。

3. 跨脚本的一致性靠拷贝不靠记忆

如果多个脚本共享同一套命名/解析逻辑,从一个已验证的脚本原样复制函数代码,不要凭记忆重写。本次多个 bug 的根因都是"记得大概但参数顺序写错了"。

4. 利用业务规则做安全兜底

了解平台的业务规则(如"未整理数据不在列表中"),有时比写更多的校验代码更有效。


八、最终成果

指标

数值

总记录数

429 条

导出文件数

776 个(387 mp3 + 389 docx)

纯 API 耗时

约 8 分钟

清理旧记录

约 307 条

释放空间

约 70GB

误删数量

0 条

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 用纯 API 替代浏览器自动化:从 5 小时卡死到 8 分钟跑通的实战复盘
    • 一、任务背景
    • 二、第一条错误路线:浏览器自动化
    • 三、转折:从"模拟人操作"到"直接调接口"
      • 3.1 抓包找接口
      • 3.2 认证方式
    • 四、纯 API 方案实现
      • 4.1 列表分页
      • 4.2 并发控制
      • 4.3 文件名解析
    • 五、旧数据安全清理
      • 5.1 安全设计
      • 5.2 删除接口
      • 5.3 过滤规则
    • 六、踩坑汇总
    • 七、方法论总结
    • 八、最终成果
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档