EveryInfra

音频验证码识别(语音 → 文字)

音频验证码识别(语音 → 文字)非单一厂商(跨产品的无障碍备选通道)文字问答图像挑战框里有一个耳机图标按钮。点下去后九宫格图片换成一个音频播放器:播放一段被加噪、混响、变速处理过的英文朗读(通常是几个数字或单词),下方一个文本输入框让你把听到的内容打进去。reCAPTCHA 还提供「Alternatively, download audio as MP3」下载链接、按 R 键从头重播、以及换一道新题的按钮。自建表单的音频验证码则更简单:一个小喇叭图标,点了播放一段读字母数字的录音,答案直接填在表单的普通输入框里。

正在查询可用性…$0.83 / 1K 次按成功计费,失败退款

接口规格

项目
typeaudio
必填参数body
可选参数language
返回一段文字solution.text
怎么用这个解听写出的文字
价格$0.83 / 1K 次 —— 按成功计费,没解出来退款
厂商文档非单一厂商(跨产品的无障碍备选通道) 官方文档

参数去页面哪里取

下面全部是可以直接照做的定位方法 —— DOM 属性名、JS 全局变量名、script 上的 query 参数。

先分清两类,取法完全不同。

① reCAPTCHA v2 的音频挑战 —— 活在 bframe iframe 里,不在 anchor iframe 里。
先在顶层页面拿 sitekey 并确认 bframe 存在:

[...document.querySelectorAll('iframe[src*="recaptcha/api2/bframe"]')]
  .map(f => new URL(f.src).searchParams.get('k'))

k= 的值就是 sitekey,和页面上 data-sitekey 属性、grecaptcha.rendersitekey 参数是同一个值。

然后在 DevTools 的执行上下文下拉里切到 bframe 那个 iframe,跑这一行拿音频地址:

document.getElementById('audio-source')?.src ||
document.querySelector('.rc-audiochallenge-download-link')?.href

关键标识符一览:
- #recaptcha-anchor — 顶层那个复选框,先点它

- #recaptcha-audio-button — 切换到音频模式的耳机按钮

- #audio-source<source> 元素,src 指向 https://www.google.com/recaptcha/api2/payload?…(.mp3)

- .rc-audiochallenge-download-link — 「下载 MP3」那个链接的 href,与上面同源

- #audio-response — 填答案的输入框

- #recaptcha-verify-button — 提交

- .rc-audiochallenge-error-message — 判断这次答错没答错,看它的 display 是不是 none

② 自建表单的音频验证码 —— 没有 sitekey,直接读 audio 标签。

document.querySelector('audio[src], audio source[src]')?.src ||
[...document.querySelectorAll('a[href*=".mp3"],a[href*="audio"]')].map(a=>a.href)

答案输入框的 name 常见取值:captchacodeaudio_codecaptcha_response —— 手动提交一次表单,在 Network 里看那条 POST 的 Form Data 就能确定字段名和端点。

通用兜底(不知道是哪种时): 打开 DevTools → Network → 按 Media 过滤或直接输 mp3,点一下播放键,列表里冒出来的那条请求的 Request URL 就是音频地址。

调用示例

一个端点解全部验证码类型 —— 换一种验证码只改 type 这一个字段。

请求
curl -X POST https://api.everyinfra.com/api/v1/captcha \  -H "Authorization: Bearer omg_你的KEY" \  -H "Content-Type: application/json" \  -d '{"type":"audio","body":"<body>"}'
响应
{  "solution": {    "text": "…"  },  "billing": { "charged": true, "credits": 60 }}

怎么确认目标站用的就是它

服务端把一串随机答案用 TTS 合成或拼接真人录音,再叠加背景噪声、多人同时说话、回声与变速,让声学特征远离标准语料。识别侧的流程是纯 ASR:取到音频文件 → 转成识别模型要的采样率与编码 → 输出文字 → 填回输入框提交。之所以这条通道在工程上更容易处理,是因为答案空间小且结构固定(几个数字或常见单词,一次只有一个短字符串),而图像类挑战要做的是开放域视觉推理。它存在的原因是无障碍合规 —— WCAG 要求验证码提供非视觉的等价替代形式。

容易搞混的

最容易和「语音验证码 / 电话 OTP」搞混 —— 后者是系统打电话或发语音条给你念一串一次性验证码,属于身份验证(OTP)而不是人机验证挑战,两者的技术栈和用途毫无关系。另外要和「站点自建的音频验证码」(如 BotDetect 这类组件生成的 wav/mp3)区分开:那类没有 sitekey、没有 token,答案直接填进表单字段随表单一起提交,判定完全在站点自己的服务端;而 reCAPTCHA 的音频挑战最终产出的仍是一个标准的 g-recaptcha-response token,要走 Google 的 siteverify。

去看 Google 那一条 →

常见部署场景

已知的坑

音频通道不是更宽松的后门,恰恰相反 —— 它是被反向加严的那一条。reCAPTCHA 在 IP / 网段信誉可疑时会整体禁用音频挑战,直接显示「Your computer or network may be sending automated queries」,耳机按钮点了没反应甚至根本不出现。所以这条路径在干净住宅 IP 上可用,在机房 IP 上往往一开始就不存在。别把「答案空间小、好识别」当成「判定更松」。

hCaptcha 已经取消了音频挑战。它改成需要用邮箱申请一个 accessibility cookie,因此 hCaptcha 场景下根本没有音频路径可走 —— 这一条经常被过时的资料写错。

音频文件 URL 是一次性且带时效的。复制出来隔一会儿再取就是 404 / 403,而且它与当前会话绑定,换个浏览器打不开。

音频挑战有独立的失败计数。同一个 widget 连错几次会被锁死,必须整个刷新重来,不是无限重试。

reCAPTCHA 的响应 token 一次性且两分钟过期(官方 verify 文档写明),音频识别再快也要在这个窗口内提交完。

语言跟着 hl= 参数走。非英语的音频用的是完全不同的口音与词表,按英语数字表去处理会全错。

格式上几乎都是 MP3,但自建验证码有用 WAV / OGG 的(老实现还会为不支持 HTML5 audio 的浏览器回落到 embed/object 标签),拿到手要先确认容器格式。

#audio-source 只在切到音频模式之后才存在,直接在图像挑战状态下查会返回 null —— 必须先点过 #recaptcha-audio-button。

很多带图验证码都提供「听语音」的无障碍通道 —— 图识别不出来时,换这条走音频往往是更稳的一条路

常见问题

音频验证码识别(语音 → 文字) 要传哪些参数?

必填 body;可选 language。请求里 type 传 audio。

解出来的东西怎么用?

返回一段文字,取 solution.text。听写出的文字

grecaptcha.render 要去页面的哪里找?

重点找 grecaptcha.render、audio_code、display。本页「参数去页面哪里取」一节写了全部位置与取法,含可直接粘进控制台的一行命令。

怎么确认目标站用的就是 音频验证码识别(语音 → 文字)?

最容易和「语音验证码 / 电话 OTP」搞混 —— 后者是系统打电话或发语音条给你念一串一次性验证码,属于身份验证(OTP)而不是人机验证挑战,两者的技术栈和用途毫无关系。另外要和「站点自建的音频验证码」(如 BotDetect 这类组件生成的 wav/mp3)区分开:那类没有 sitekey、没有 token,答案直接填进表单字段随表单一起提交,判定完全在站点自己的服务端;而 reCAPTCHA 的音频挑战最终产出的仍是一个标准的 g-recaptcha-response token,要走 Google 的 siteverify。

有什么容易踩的坑?

音频通道不是更宽松的后门,恰恰相反 —— 它是被反向加严的那一条。reCAPTCHA 在 IP / 网段信誉可疑时会整体禁用音频挑战,直接显示「Your computer or network may be sending automated queries」,耳机按钮点了没反应甚至根本不出现。所以这条路径在干净住宅 IP 上可用,在机房 IP 上往往一开始就不存在。别把「答案空间小、好识别」当成「判定更松」。

多少钱一次,失败扣不扣?

$0.83 / 1K 次。按成功计费 —— 没解出来一律退款,所以失败不花钱。账单按次记,标价按每千次是为了让量级读得出来。

开始接入

一个端点覆盖全部验证码类型,按成功计费,失败与空结果一律退款。