A API do Notion permite ler e gravar em bancos de dados de forma programática, tornando-o uma camada flexível de gerenciamento de tarefas para fluxos de trabalho de automação. Quando esses fluxos de trabalho encontram formulários protegidos por CAPTCHA,CaptchaAIcuida da resolução. Este guia mostra como usar um banco de dados Notion como uma fila de tarefas CAPTCHA – armazenando URLs e chaves de site, acionando soluções e gravando resultados.
Cenário do mundo real
Sua equipe mantém um banco de dados Notion de URLs de sites que precisam de extração periódica de dados. Algumas dessas URLs são protegidas por CAPTCHA. Um roteiro:
- Lê tarefas pendentes do Notion
- Resolve CAPTCHAs via CaptchaAI
- Atualiza cada registro do Notion com o token e o status
Pré-requisitos
- Integração de noção (integração interna viadesenvolvedores.notion.com)
- Um banco de dados Notion compartilhado com a integração
- Chave de API CaptchaAI
- Python 3.8+ ou Node.js 18+
Configuração do banco de dados do Notion
Crie um banco de dados Notion com estas propriedades:
| Propriedade | Tipo | Objetivo |
|---|---|---|
| Nome | Título | Identificador de tarefa |
| URL | URL | Página de destino com CAPTCHA |
| Chave do site | Texto rico | chave do site reCAPTCHA |
| Estado | Selecione | Pendente, Resolvendo, Resolvido, Falha |
| Símbolo | Texto rico | Token CAPTCHA resolvido |
| Resolvido em | Data | Resolver carimbo de data/hora |
| Erro | Texto rico | Mensagem de erro se falhar |
Compartilhe o banco de dados com sua integração do Notion.
Implementação Python
# notion_captcha_worker.py
import os
import time
import requests
NOTION_TOKEN = os.environ.get("NOTION_TOKEN")
NOTION_DB_ID = os.environ.get("NOTION_DB_ID")
CAPTCHAAI_KEY = os.environ.get("CAPTCHAAI_KEY", "YOUR_API_KEY")
NOTION_HEADERS = {
"Authorization": f"Bearer {NOTION_TOKEN}",
"Content-Type": "application/json",
"Notion-Version": "2022-06-28",
}
def get_pending_tasks():
"""Fetch tasks with Status = Pending from Notion."""
url = f"https://api.notion.com/v1/databases/{NOTION_DB_ID}/query"
payload = {
"filter": {
"property": "Status",
"select": {"equals": "Pending"},
}
}
resp = requests.post(url, headers=NOTION_HEADERS, json=payload)
resp.raise_for_status()
return resp.json()["results"]
def update_task(page_id, properties):
"""Update a Notion page with new property values."""
url = f"https://api.notion.com/v1/pages/{page_id}"
payload = {"properties": properties}
resp = requests.patch(url, headers=NOTION_HEADERS, json=payload)
resp.raise_for_status()
def set_status(page_id, status, token=None, error=None):
"""Update task status in Notion."""
props = {"Status": {"select": {"name": status}}}
if token:
props["Token"] = {"rich_text": [{"text": {"content": token[:2000]}}]}
props["Solved At"] = {"date": {"start": time.strftime("%Y-%m-%dT%H:%M:%S")}}
if error:
props["Error"] = {"rich_text": [{"text": {"content": error[:200]}}]}
update_task(page_id, props)
def solve_captcha(sitekey, pageurl):
"""Submit to CaptchaAI and poll for result."""
# Submit
resp = requests.get("https://ocr.captchaai.com/in.php", params={
"key": CAPTCHAAI_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": pageurl,
"json": "1",
})
result = resp.json()
if result.get("status") != 1:
raise Exception(f"Submit failed: {result.get('request')}")
task_id = result["request"]
# Poll
time.sleep(15)
for _ in range(25):
poll = requests.get("https://ocr.captchaai.com/res.php", params={
"key": CAPTCHAAI_KEY,
"action": "get",
"id": task_id,
"json": "1",
})
poll_result = poll.json()
if poll_result.get("status") == 1:
return poll_result["request"]
if poll_result.get("request") != "CAPCHA_NOT_READY":
raise Exception(f"Solve failed: {poll_result.get('request')}")
time.sleep(5)
raise Exception("Polling timeout")
def extract_property(page, prop_name, prop_type="rich_text"):
"""Extract a property value from a Notion page."""
prop = page["properties"].get(prop_name, {})
if prop_type == "rich_text":
texts = prop.get("rich_text", [])
return texts[0]["plain_text"] if texts else ""
elif prop_type == "url":
return prop.get("url", "")
return ""
def main():
tasks = get_pending_tasks()
print(f"Found {len(tasks)} pending tasks")
for task in tasks:
page_id = task["id"]
sitekey = extract_property(task, "Sitekey")
pageurl = extract_property(task, "URL", "url")
if not sitekey or not pageurl:
set_status(page_id, "Failed", error="Missing sitekey or URL")
continue
print(f"Solving: {pageurl}")
set_status(page_id, "Solving")
try:
token = solve_captcha(sitekey, pageurl)
set_status(page_id, "Solved", token=token)
print(f" Solved successfully")
except Exception as e:
set_status(page_id, "Failed", error=str(e))
print(f" Failed: {e}")
time.sleep(1) # Rate limit for Notion API
print("All tasks processed")
if __name__ == "__main__":
main()
Implementação de JavaScript
// notion_captcha_worker.js
const { Client } = require('@notionhq/client');
const axios = require('axios');
const notion = new Client({ auth: process.env.NOTION_TOKEN });
const DB_ID = process.env.NOTION_DB_ID;
const API_KEY = process.env.CAPTCHAAI_KEY || 'YOUR_API_KEY';
async function getPendingTasks() {
const response = await notion.databases.query({
database_id: DB_ID,
filter: { property: 'Status', select: { equals: 'Pending' } },
});
return response.results;
}
async function updateTask(pageId, status, token, error) {
const properties = {
Status: { select: { name: status } },
};
if (token) {
properties.Token = { rich_text: [{ text: { content: token.slice(0, 2000) } }] };
properties['Solved At'] = { date: { start: new Date().toISOString() } };
}
if (error) {
properties.Error = { rich_text: [{ text: { content: error.slice(0, 200) } }] };
}
await notion.pages.update({ page_id: pageId, properties });
}
async function solveCaptcha(sitekey, pageurl) {
const submit = await axios.get('https://ocr.captchaai.com/in.php', {
params: {
key: API_KEY, method: 'userrecaptcha',
googlekey: sitekey, pageurl, json: '1',
},
});
if (submit.data.status !== 1) throw new Error(submit.data.request);
await new Promise(r => setTimeout(r, 15000));
for (let i = 0; i < 25; i++) {
const poll = await axios.get('https://ocr.captchaai.com/res.php', {
params: { key: API_KEY, action: 'get', id: submit.data.request, json: '1' },
});
if (poll.data.status === 1) return poll.data.request;
if (poll.data.request !== 'CAPCHA_NOT_READY') throw new Error(poll.data.request);
await new Promise(r => setTimeout(r, 5000));
}
throw new Error('Timeout');
}
async function main() {
const tasks = await getPendingTasks();
console.log(`Found ${tasks.length} pending tasks`);
for (const task of tasks) {
const sitekey = task.properties.Sitekey?.rich_text?.[0]?.plain_text;
const pageurl = task.properties.URL?.url;
if (!sitekey || !pageurl) {
await updateTask(task.id, 'Failed', null, 'Missing sitekey or URL');
continue;
}
console.log(`Solving: ${pageurl}`);
await updateTask(task.id, 'Solving');
try {
const token = await solveCaptcha(sitekey, pageurl);
await updateTask(task.id, 'Solved', token);
console.log(' Solved');
} catch (e) {
await updateTask(task.id, 'Failed', null, e.message);
console.log(` Failed: ${e.message}`);
}
await new Promise(r => setTimeout(r, 1000));
}
}
main().catch(console.error);
Solução de problemas
| Problema | Causa | Correção |
|---|---|---|
401 Unauthorized da noção |
Integração não conectada ao banco de dados | Compartilhe o banco de dados com sua integração no Notion |
| Os nomes das propriedades não correspondem | Sensibilidade a maiúsculas e minúsculas | Os nomes das propriedades do Notion diferenciam maiúsculas de minúsculas - correspondem exatamente |
| Token truncado | Noção de limite rich_text de 2.000 caracteres | Os tokens CAPTCHA normalmente têm <1000 caracteres; isso não deveria ser um problema |
| Limite de taxa de noção (429) | Muitas chamadas de API | Adicione atrasos de 1 segundo entre as atualizações do Notion |
Perguntas frequentes
Posso executar isso como um trabalho agendado?
Sim. Use cron (Linux), Agendador de tarefas (Windows) ou um agendador de nuvem (AWS EventBridge, Google Cloud Scheduler) para executar o script de acordo com uma programação.
Como configuro a integração do Notion?
Vá paranoção.so/my-integrations, crie uma nova integração interna, copie o token secreto e compartilhe seu banco de dados com a integração.
Posso processar outros tipos de CAPTCHA?
Sim. Adicione uma propriedade "Tipo CAPTCHA" ao banco de dados Notion e modifique a função de resolução para usar o método CaptchaAI apropriado (turnstile, geetest, base64, etc.).
Artigos relacionados
- Como resolver o retorno de chamada do Recaptcha V2 usando API
- Torniquete Recaptcha V2 no mesmo local
- Mecanismo de retorno de chamada Recaptcha V2
Próximas etapas
Transforme seus bancos de dados Notion em filas automatizadas de resolução de CAPTCHA -obtenha sua chave API CaptchaAI.
Guias relacionados: