Neste artigo procurámos responder a todas as questões importantes. Para começar a resolver o problema, o primeiro passo é identificar que sistema de proteção está a ser utilizado. Para isso, pode consultar a lista de captchas e sistemas de proteção antibot mais populares, onde encontrará exemplos visuais e sinais principais que ajudam a perceber rapidamente com o que está a lidar.
Se verificar que o seu site utiliza TenDI (Tencent), o passo seguinte é analisar mais detalhadamente as suas características e o seu funcionamento. Neste mesmo artigo também pode consultar o guia de integração de TenDI (Tencent), para compreender totalmente como o sistema funciona no seu site. Isto permitirá não só entender a proteção atual, como também planear corretamente a sua manutenção.
Trabalhar com o CapMonster Cloud através da API normalmente envolve os passos seguintes:
type - CustomTask
class - TenDI
websiteURL - Endereço da página onde o captcha é resolvido.
websiteKey - captchaAppId. Por exemplo "websiteKey": "189123456" — parâmetro único para o seu site
captchaUrl (dentro do metadata) - Link para o script do captcha. Normalmente termina em TCaptcha.js ou TCaptcha-global.js;
websiteURL - Endereço da página onde o captcha é resolvido;
userAgent (opcional) - User-Agent do navegador. Envie apenas UA atual do Windows.
https://api.capmonster.cloud/createTask
{
"clientKey": "API_KEY",
"task": {
"type": "CustomTask",
"class": "TenDI",
"websiteURL": "https://example.com",
"websiteKey": "189123456",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36",
"metadata": {
"captchaUrl": "https://global.captcha.example.com/TCaptcha-global.js"
}
}
}
{
"errorId":0,
"taskId":407533072
}https://api.capmonster.cloud/getTaskResult{
"clientKey":"API_KEY",
"taskId": 407533072
}
{
"errorId":0,
"status":"ready",
"solution": {
"data": {
"randstr": "@EcL",
"ticket": "tr03lHUhdnuW3neJZu.....7LrIbs*"
},
"headers": {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36"
}
}
}
// npx playwright install chromium
import { chromium } from 'playwright';
import { CapMonsterCloudClientFactory, ClientOptions, TenDIRequest } from '@zennolab_com/capmonstercloud-client';
// Substitua pelos seus valores
const API_KEY = "YOUR_API_KEY";
const WEBSITE_URL = "https://example.com";
async function solveTenDIOnPage() {
const browser = await chromium.launch({ headless: false });
const context = await browser.newContext();
const page = await context.newPage();
// 1. Abrimos a página
await page.goto(WEBSITE_URL, { waitUntil: 'networkidle' });
// 2. Esperamos que o captcha apareça (ex.: input ou iframe)
await page.waitForSelector('#tendi_response, iframe[src*="tendi"], input[name="tendi_response"]', { timeout: 15000 });
// Se necessário, pode extrair websiteKey da página
const WEBSITE_KEY = await page.evaluate(() => {
// Exemplo: sitekey pode estar num atributo data ou numa variável global
const el = document.querySelector('#tendi_response') || document.querySelector('div[data-sitekey]');
return el?.getAttribute('data-sitekey') || window.TenDI_siteKey || "183268248";
});
console.log("Website key detected:", WEBSITE_KEY);
const client = CapMonsterCloudClientFactory.Create(
new ClientOptions({ clientKey: API_KEY })
);
// 3. Criamos a tarefa TenDI
const tenDIRequest = new TenDIRequest({
websiteURL: page.url(),
websiteKey: WEBSITE_KEY,
});
const balance = await client.getBalance();
console.log("Balance:", balance);
// 4. Resolvemos o captcha
const solution = await client.Solve(tenDIRequest);
console.log("Solution:", solution);
const { ticket, randstr } = solution.solution.data;
// 5. Formas de inserir o resultado
await page.evaluate(({ ticket, randstr }) => {
// Inserção no input
const inputSelectors = ['#tendi_response', 'input[name="tendi_response"]', 'input[type="hidden"]'];
let inserted = false;
for (const sel of inputSelectors) {
const input = document.querySelector(sel);
if (input) {
input.value = ticket;
input.dispatchEvent(new Event('input', { bubbles: true }));
const form = input.closest('form');
if (form) form.submit();
inserted = true;
break;
}
}
// Função callback JS
if (typeof window.onCaptchaSolved === 'function') {
window.onCaptchaSolved(ticket, randstr);
inserted = true;
}
// Se não houver input nem callback
if (!inserted) {
window._tenDITicket = ticket;
window._tenDIRandStr = randstr;
console.log("Ticket and randstr saved to window._tenDITicket and window._tenDIRandStr");
}
}, { ticket, randstr });
await page.waitForTimeout(5000);
await browser.close();
}
solveTenDIOnPage().catch(console.error);
Receberá dois parâmetros: CaptchaAppId e AppSecretKey. Serão usados no frontend e no servidor.
Ao clicar, aparece o captcha e, após resolução, o resultado é mostrado na consola.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Captcha Example</title>
// Carregamento obrigatório do JS da captcha
<script src="https://ca.turing.captcha.qcloud.com/TJNCaptcha-global.js"></script>
</head>
<body>
<div id="cap_iframe"></div>
<button id="CaptchaId">Verification</button>
<script>
// Processamento do resultado
function callback(res) {
console.log("callback:", res);
if (res.ret === 0) {
// Verificação bem-sucedida
const text = `[randstr] ${res.randstr} | [ticket] ${res.ticket}`;
const input = document.createElement("input");
input.value = text;
document.body.appendChild(input);
input.select();
document.execCommand("Copy");
document.body.removeChild(input);
alert("Ticket e randstr copiados para a área de transferência.");
}
}
// Gestão de erros ao carregar o script da captcha
function loadErrorCallback() {
const appid = "CaptchaAppId";
const ticket = `trerror_1001_${appid}_1769260288`;
callback({
ret: 0,
randstr: "@" + Math.random().toString(36).slice(2),
ticket,
errorCode: 1001,
errorMessage: "jsload_error",
});
}
window.onload = function () {
document.getElementById("CaptchaId").onclick = function () {
try {
const captcha = new TencentCaptcha(
document.getElementById("cap_iframe"),
"Your CaptchaAppId",
callback,
{}
);
captcha.show();
} catch (e) {
loadErrorCallback();
}
};
};
</script>
</body>
</html>
Como funciona a integração
Passo 1: Carregar o JS da captcha
O script deve ser carregado dinamicamente:
<script src="https://ca.turing.captcha.qcloud.com/TJNCaptcha-global.js"></script>Carregamentos não padrão ou caching podem causar funcionamento incorreto da captcha.
Passo 2: Criar o objeto TencentCaptcha
Após carregar o JS, aparece uma classe global:
<script src="new TencentCaptcha(domElement, CaptchaAppId, callback, options);"></script>Parâmetros:
domElement - Container onde o checkbox/iframe será inserido
CaptchaAppId - O seu ID
callback - O que fazer após a verificação
options - Configurações visuais (opcional)
Passo 3: Chamar o método .show()
captcha.show();Mostra a captcha. Pode ser chamado várias vezes.
Passo 4: Processar o resultado
Callback recebe um objeto:
{
ret: 0, // 0 -- sucesso, 2 -- utilizador fechou a janela
ticket: "...", // necessário pelo servidor
randstr: "...", // também necessário pelo servidor
errorCode: 1001, // se a captcha não carregou
errorMessage: "..." // mensagem de erro
}No servidor, sempre execute a verificação secundária do ticket.
"Modo de emergência"
Se a captcha não carregar (ex.: CDN indisponível), pode automaticamente gerar um 'ticket de emergência' para não interromper o processo de negócio.
Cenário:
trerror_<errorcode>_<appid>_<timestamp>Criptografia do AppId (opcional)
Para proteção máxima, pode enviar para a captcha uma versão encriptada do AppId em vez da versão aberta:
aidEncrypted = Base64(IV + AES256(AppId & timestamp & ttl))Necessário:
Exemplo de encriptação server-side (Python)
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import base64
def encrypt(plaintext, key, iv):
cipher = AES.new(key, AES.MODE_CBC, iv)
ciphertext = cipher.encrypt(pad(plaintext.encode(), AES.block_size))
return base64.b64encode(iv + ciphertext).decode("utf-8")Validação no servidor
Passo 1. Configurar acesso à API
No painel de gestão de chaves (CAM / API Key Management), obtenha SecretId e SecretKey para a API. Necessários para pedidos assinados.
Passo 2. Chamar API DescribeCaptchaResult
Após o cliente devolver ticket e randstr, o servidor envia o pedido:
Parâmetros:
CaptchaType - 9 (valor fixo)
Ticket - string — ticket retornado do cliente
Randstr - string — randstr retornado do cliente
CaptchaAppId - o seu AppId
AppSecretKey - a sua chave secreta
UserIp - IP do utilizador (recomendado)
Passo 3. Processar resposta
A API devolve:
Se CaptchaCode === OK, o utilizador é considerado verificado. Caso contrário — rejeitar.
Exemplo — verificação de ticket em Node.js
import { v20190722 as captcha } from "@tencentcloud/tencentcloud-sdk-nodejs";
const client = new captcha.Client({
credential: {
secretId: "YOUR_SECRET_ID",
secretKey: "YOUR_SECRET_KEY"
},
region: "ap-project", // região, se necessário
});
async function verifyCaptcha(ticket, randstr, userIp) {
const params = {
CaptchaType: 9,
Ticket: ticket,
Randstr: randstr,
CaptchaAppId: YOUR_APP_ID,
AppSecretKey: "YOUR_APP_SECRET_KEY",
UserIp: userIp
};
const resp = await client.DescribeCaptchaResult(params);
const code = resp.Response.CaptchaCode;
return code === 0;
}Mais informações sobre como ligar Tencent CAPTCHA ao seu site podem ser encontradas na documentação oficial.
Se herdou um site que já tem um captcha ou outro sistema de proteção instalado e não tem acesso ao código, não há problema! É bastante fácil identificar qual a tecnologia que está a ser utilizada. Para verificar se tudo está a funcionar corretamente, pode usar o serviço de reconhecimento CapMonster Cloud num ambiente de teste isolado, para garantir que o mecanismo de processamento de tokens e a lógica de verificação estão a funcionar corretamente.
No caso de TenDI (Tencent), basta identificar o sistema, analisar o seu comportamento e confirmar que a proteção está a funcionar corretamente. No artigo, mostramos como identificar TenDI (Tencent) e onde encontrar instruções para a sua integração ou reconfiguração, para que possa manter a proteção com confiança e controlar o seu funcionamento.