Airtable 表里的记录一多,总有几条要先过验证码才能继续处理——不如直接接上 CaptchaAI:Automation 触发器和 Scripting 扩展都能调用它的识别接口,记录一变状态就自动提交、轮询、把 token 写回表里。本文演示两种接法:Automation 在 Status 变为 pending(待处理)时触发单条识别,Scripting 扩展批量处理积压记录。
建表:CAPTCHA Tasks 需要哪些字段
新建一个名为 CAPTCHA Tasks 的表,字段名要和脚本里用到的完全一致(脚本按字段名精确取值):
| 字段名 | 类型 | 用途 |
|---|---|---|
| URL | URL | 目标页面地址 |
| Sitekey | 单行文本 | reCAPTCHA 的 sitekey |
| Status | 单选 | 可选值:pending / solving / solved / failed |
| Token | 长文本 | 已识别的验证码 token |
| Solved At | 日期/时间 | 识别完成的时间戳 |
| Error | 单行文本 | 识别失败时的错误信息 |
提示: Status 的选项要用英文小写
pending、solving、solved、failed,写成中文选项会导致触发器和脚本都失效。
典型场景:跨境团队追踪海外供应商页面的验证码
跨境电商或供应链团队常用 Airtable 跟踪几十个海外供应商门户,这些页面大多挂着 reCAPTCHA v2(国内站点更常见的是 GeeTest(极验),面向海外的页面则几乎都是 reCAPTCHA/Turnstile)。每加入一条新 URL,都要先过验证码才能抓取或提交数据:
- Automation 检测到新记录
- 脚本把验证码参数提交给 CaptchaAI
- CaptchaAI 返回已识别的 token
- token 写回对应记录
第一步:创建 Automation 触发器
在 Airtable 里:
- 打开 Automations 标签
- 点击 Create automation
- 命名为:"Solve CAPTCHA on New Record"
触发条件
选择 When record matches conditions:
| 项目 | 值 |
|---|---|
| 表 | CAPTCHA Tasks |
| 条件 | Status 等于 pending |
记录的 Status 变为 pending,无论是新记录还是重新提交的失败记录,都会激活触发器。
第二步:编写脚本动作
在触发器后添加一个动作 → Run a script:
// Airtable Automation Script — Solve CAPTCHA via CaptchaAI
// Input configuration (set in the left panel):
// - recordId: Record ID from trigger
// - sitekey: Sitekey field from trigger
// - pageurl: URL field from trigger
const config = input.config();
const recordId = config.recordId;
const sitekey = config.sitekey;
const pageurl = config.pageurl;
const API_KEY = 'YOUR_API_KEY'; // Use input.config() for security
// Update status to "solving"
const table = base.getTable('CAPTCHA Tasks');
await table.updateRecordAsync(recordId, {
'Status': { name: 'solving' },
});
try {
// Step 1: Submit task to CaptchaAI
const submitUrl = `https://ocr.captchaai.com/in.php?key=${API_KEY}&method=userrecaptcha&googlekey=${encodeURIComponent(sitekey)}&pageurl=${encodeURIComponent(pageurl)}&json=1`;
const submitResponse = await fetch(submitUrl);
const submitResult = await submitResponse.json();
if (submitResult.status !== 1) {
throw new Error(`Submit failed: ${submitResult.request}`);
}
const taskId = submitResult.request;
console.log(`Task submitted: ${taskId}`);
// Step 2: Poll for result (wait 15 seconds first)
await new Promise(resolve => setTimeout(resolve, 15000));
let token = null;
for (let i = 0; i < 20; i++) {
const pollUrl = `https://ocr.captchaai.com/res.php?key=${API_KEY}&action=get&id=${taskId}&json=1`;
const pollResponse = await fetch(pollUrl);
const pollResult = await pollResponse.json();
if (pollResult.status === 1) {
token = pollResult.request;
break;
}
if (pollResult.request !== 'CAPCHA_NOT_READY') {
throw new Error(`Solve failed: ${pollResult.request}`);
}
await new Promise(resolve => setTimeout(resolve, 5000));
}
if (!token) {
throw new Error('Polling timeout — CAPTCHA not solved in time');
}
// Step 3: Update record with solved token
await table.updateRecordAsync(recordId, {
'Status': { name: 'solved' },
'Token': token,
'Solved At': new Date().toISOString(),
'Error': '',
});
console.log(`CAPTCHA solved for record ${recordId}`);
} catch (error) {
// Update record with error
await table.updateRecordAsync(recordId, {
'Status': { name: 'failed' },
'Error': error.message,
});
console.error(`Failed: ${error.message}`);
}
配置脚本输入变量
在左侧输入面板里映射好这几个变量:
| 变量 | 来源 |
|---|---|
recordId |
触发记录的 Record ID |
sitekey |
触发记录的 Sitekey 字段 |
pageurl |
触发记录的 URL 字段 |
逻辑分三步:提交到 in.php、轮询 res.php(先等 15 秒),成功后写回 token 并置 Status 为 solved;失败则标记 failed 并写入 Error,方便按状态筛选重跑。
第三步:批量处理用 Scripting 扩展
如果表里已经积压了一批 pending 记录,没必要一条条触发 Automation——用 Scripting 扩展(在 Apps 面板里)一次跑完:
// Batch CAPTCHA Solver — Airtable Scripting Extension
const API_KEY = 'YOUR_API_KEY';
const table = base.getTable('CAPTCHA Tasks');
// Get all pending records
const query = await table.selectRecordsAsync({
fields: ['URL', 'Sitekey', 'Status'],
});
const pendingRecords = query.records.filter(
r => r.getCellValueAsString('Status') === 'pending'
);
output.text(`Found ${pendingRecords.length} pending CAPTCHAs`);
for (const record of pendingRecords) {
const sitekey = record.getCellValueAsString('Sitekey');
const pageurl = record.getCellValueAsString('URL');
if (!sitekey || !pageurl) {
output.text(`Skipping ${record.id} — missing sitekey or URL`);
continue;
}
output.text(`Solving for: ${pageurl}`);
await table.updateRecordAsync(record.id, {
'Status': { name: 'solving' },
});
try {
// Submit
const submitResp = await fetch(
`https://ocr.captchaai.com/in.php?key=${API_KEY}&method=userrecaptcha&googlekey=${encodeURIComponent(sitekey)}&pageurl=${encodeURIComponent(pageurl)}&json=1`
);
const submitData = await submitResp.json();
if (submitData.status !== 1) throw new Error(submitData.request);
// Poll
await new Promise(r => setTimeout(r, 15000));
let token = null;
for (let i = 0; i < 20; i++) {
const pollResp = await fetch(
`https://ocr.captchaai.com/res.php?key=${API_KEY}&action=get&id=${submitData.request}&json=1`
);
const pollData = await pollResp.json();
if (pollData.status === 1) { token = pollData.request; break; }
if (pollData.request !== 'CAPCHA_NOT_READY') throw new Error(pollData.request);
await new Promise(r => setTimeout(r, 5000));
}
if (!token) throw new Error('Timeout');
await table.updateRecordAsync(record.id, {
'Status': { name: 'solved' },
'Token': token,
'Solved At': new Date().toISOString(),
});
output.text(`✓ Solved: ${pageurl}`);
} catch (e) {
await table.updateRecordAsync(record.id, {
'Status': { name: 'failed' },
'Error': e.message,
});
output.text(`✗ Failed: ${e.message}`);
}
}
output.text('Batch processing complete');
这段脚本会先把所有 Status 为 pending 的记录取出来,逐条提交、轮询,成功就把 token 和完成时间写回去,失败就记录错误原因,跑完后在控制台打印一行汇总。
常见问题
Airtable 自动化脚本的执行时长上限是多少?
都是 30 秒上限(部分付费计划可延长)。接近超时时,缩短轮询次数、加长首次等待更管用。
免费版 Airtable 能跑通这一整套流程吗?
可以,主要受限于每月运行次数和记录数上限,用量大了再升级,不影响搭建方式。
图片验证码(Image CAPTCHA)能用同一套逻辑处理吗?
可以,把 method 改成 base64 并提交图片数据即可,Base64 图片可存进 Airtable 附件字段,脚本里再读出来提交。
sitekey 应该从哪里提取,容易踩什么坑?
常见来源和坑点:
- 目标页面的
data-sitekey属性,或对应的 JS 初始化代码 - 开发者工具里搜索
sitekey通常能直接定位 - 最容易踩的坑:把测试环境和线上环境的 sitekey 搞混,导致轮询一直拿不到有效 token
多个 Base 或多人共用同一个 API Key 会有问题吗?
不会,Key 和 Base 无关,可以复用。真正要注意的是别把 Key 明文写进脚本——用输入变量传入。
排查清单
- Automation 没有触发:Status 不等于
pending→ 核对单选字段的值是否完全一致 fetch is not defined:部分脚本环境要用remoteFetchAsync→ 把fetch换成remoteFetchAsync- 脚本超时:脚本动作有 30 秒执行上限 → 减少轮询次数,加长首次等待
- 记录更新失败:字段名和表里的对不上 → 核对
updateRecordAsync里的字段名 - API Key 出现在脚本里:Key 被硬编码在代码中 → 改用
input.config()输入变量
相关文章
- reCAPTCHA v2 回调模式下如何用 API 识别
- reCAPTCHA v2 和 Turnstile 同站点的处理方式
- reCAPTCHA v2 回调机制详解
下一步
把验证码识别交给自动化,团队就能专心做数据本身——获取 CaptchaAI 的 API Key,按上面的步骤接好 Automation 或 Scripting 扩展。