pq ele não consegue obter: [Playwright] Iniciando ...
創建於:2025年8月21日
創建於:2025年8月21日
pq ele não consegue obter: [Playwright] Iniciando navegador para obter token reCAPTCHA...
[Playwright] ERRO: Ocorreu uma exceção inesperada: Page.wait_for_selector: Timeout 20000ms exceeded.
Call log:
[Playwright] Navegador finalizado.
[ERRO] Não foi possível obter o token reCAPTCHA. Tente novamente.
[DICA] Verifique se os cookies estão corretos e válidos. consegue resolver isso? think harder: # -- coding: utf-8 --
import asyncio
import json
import sys
import uuid
from typing import Dict, Any, List, Optional
import requests
from playwright.async_api import async_playwright, Route
COOKIES: Dict[str, str] = {
"i18n_set": "pt-BR",
"_gcl_au": "1.1.62685151.1755263695",
"_ga": "GA1.1.203885191.1755263695",
"_fbp": "fb.1.1755263695001.392179771727185719",
"ai_user": "jmhDbMDM2CtNJcLJVKd5+P|2025-08-15T13:14:55.764Z",
"session_id": "7710c7ce-93c5-46a6-87b9-f357244261e8:67e4794fc2090448254ddd5f9403b4f3a715c1305ada00b8bf8648b4789a9abb",
"agree_terms": "1",
"c1": "23prrvC53bbtTkczLz7xiY8WmSUbjijYnJiMxDM9aQJotIta0Ha%2B8nECeL8T%2BQ%2FCdfePgvv6SBff7FRTQKYDirxgsPa15%2BK2uCsqzuEM%2BaQ1iE8Z",
"c2": "2T8q%2BGSrJGwzDzot",
"gslogin": "1",
"ai_session": "wWAFgxi+KmF3F9fWVo2sN2|1755772657326|1755772849339",
# "_ga_VL3SBJ0Y0F": "", # Opcional, pode ser omitido
}
DEFAULT_MODEL = "gpt-5-high"
GENSPARK_CHAT_URL = "https://www.genspark.ai/copilot"
GENSPARK_API_URL = "https://www.genspark.ai/api/copilot/ask"
BASE_HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0",
"Accept": "/",
"Accept-Language": "pt-BR,pt;q=0.9,en;q=0.8",
"Origin": "https://www.genspark.ai",
"Referer": GENSPARK_CHAT_URL,
"Sec-Ch-Ua": '"Not;A=Brand";v="99", "Microsoft Edge";v="139", "Chromium";v="139"',
"Sec-Ch-Ua-Mobile": "?0",
"Sec-Ch-Ua-Platform": '"Windows"',
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"Content-Type": "application/json",
}
async def get_recaptcha_token(cookies: Dict[str, str], headless: bool = True) -> Optional[str]:
"""
Usa Playwright para abrir o site da GenSpark, interceptar a requisição de chat
e extrair o g_recaptcha_token gerado.
"""
print("[Playwright] Iniciando navegador para obter token reCAPTCHA...")
token_captured = asyncio.Event()
captured_token = None
textasync def route_handler(route: Route): nonlocal captured_token request = route.request if request.url == GENSPARK_API_URL and request.method == "POST": try: post_data = await request.post_data_json() token = post_data.get("g_recaptcha_token") if token: print("[Playwright] Token reCAPTCHA capturado com sucesso.") captured_token = token token_captured.set() # Abortamos a requisição para que o navegador não a complete await route.abort() return except Exception as e: print(f"[Playwright] Erro ao processar requisição: {e}") await route.continue_() p = None browser = None try: p = await async_playwright().start() browser = await p.chromium.launch(headless=headless) context = await browser.new_context(user_agent=BASE_HEADERS["User-Agent"]) # Aplicar cookies cookie_list = [ {"name": k, "value": v, "domain": ".genspark.ai", "path": "/"} for k, v in cookies.items() if v ] await context.add_cookies(cookie_list) page = await context.new_page() await page.route("**/*", route_handler) # Navegar e simular o envio de uma mensagem para acionar o reCAPTCHA await page.goto(GENSPARK_CHAT_URL, wait_until="networkidle") # Espera um pouco para a página carregar completamente o JS await page.wait_for_timeout(3000) # Localiza o campo de texto e o botão de envio textarea_selector = 'textarea[placeholder*="Ask me anything"]' await page.wait_for_selector(textarea_selector, timeout=20000) await page.fill(textarea_selector, "Olá") # Clica no botão de envio button_selector = 'button[type="submit"]' await page.wait_for_selector(button_selector, timeout=5000) await page.click(button_selector) # Aguarda a captura do token pela nossa rota await asyncio.wait_for(token_captured.wait(), timeout=30) return captured_token except asyncio.TimeoutError: print("[Playwright] ERRO: Timeout ao esperar pelo token. A página pode ter mudado, ou a conta requer verificação.") return None except Exception as e: print(f"[Playwright] ERRO: Ocorreu uma exceção inesperada: {e}") return None finally: if browser: await browser.close() if p: await p.stop() print("[Playwright] Navegador finalizado.")
def build_api_payload(prompt: str, model: str, g_recaptcha_token: str) -> Dict[str, Any]:
"""Constrói o corpo (payload) da requisição para a API de chat."""
return {
"type": "COPILOT_MOA_CHAT",
"current_query_string": "type=COPILOT_MOA_CHAT",
"project_id": None,
"messages": [{"role": "user", "content": prompt}],
"user_s_input": prompt,
"action_params": {},
"extra_data": {
"models": [model],
"run_with_another_model": False,
"request_web_knowledge": True,
"speed_mode": False,
"writingContent": None,
},
"g_recaptcha_token": g_recaptcha_token,
}
def process_sse_stream(response: requests.Response) -> str:
"""
Processa a resposta SSE (Server-Sent Events), imprime os pedaços de texto
em tempo real e retorna a resposta completa.
"""
full_text = ""
try:
for line in response.iter_lines(decode_unicode=True):
if line.startswith("data:"):
data_str = line[len("data:"):].strip()
if not data_str or data_str == "[DONE]":
continue
try:
data_json = json.loads(data_str)
# Heurística para encontrar o pedaço de texto
chunk = data_json.get("content", "") or data_json.get("text", "")
if isinstance(chunk, str):
print(chunk, end="", flush=True)
full_text += chunk
except json.JSONDecodeError:
# Ignora linhas que não são JSON válido
pass
except Exception as e:
print(f"\n[API] Erro durante o streaming da resposta: {e}")
textprint() # Nova linha no final return full_text
def send_chat_request(prompt: str, cookies: Dict[str, str], model: str, token: str) -> str:
"""Envia a requisição de chat e processa a resposta em stream."""
session = requests.Session()
session.headers.update(BASE_HEADERS)
text# Adiciona request-id e traceparent, como vistos no cURL request_id = f'|{uuid.uuid4().hex}.{uuid.uuid4().hex[:16]}' traceparent = f'00-{uuid.uuid4().hex}-{uuid.uuid4().hex[:16]}-01' session.headers.update({ 'request-id': request_id, 'traceparent': traceparent, }) for k, v in cookies.items(): if v: session.cookies.set(k, v) payload = build_api_payload(prompt, model, token) try: with session.post(GENSPARK_API_URL, json=payload, stream=True, timeout=180) as resp: resp.raise_for_status() return process_sse_stream(resp) except requests.HTTPError as e: print(f"\n[API] ERRO HTTP: {e.response.status_code}") print(f" Resposta: {e.response.text[:500]}") except Exception as e: print(f"\n[API] ERRO Inesperado: {e}") return ""
async def chat_cli():
"""Loop principal para a interface de linha de comando."""
print("=== GenSpark AI CLI ===")
print("Comandos: /quit, /exit")
print(f"Modelo atual: {DEFAULT_MODEL}")
textwhile True: try: user_input = input("\nVocê> ").strip() except (KeyboardInterrupt, EOFError): print("\nEncerrando.") break if not user_input: continue if user_input.lower() in ("/quit", "/exit"): print("Até mais!") break # 1. Obter o token reCAPTCHA para esta mensagem token = await get_recaptcha_token(COOKIES) if not token: print("[ERRO] Não foi possível obter o token reCAPTCHA. Tente novamente.") print("[DICA] Verifique se os cookies estão corretos e válidos.") continue # 2. Enviar a mensagem para a API print(f"GenSpark ({DEFAULT_MODEL})> ", end="", flush=True) send_chat_request(user_input, COOKIES, DEFAULT_MODEL, token)
if name == "main":
if not COOKIES.get("session_id") or not COOKIES.get("ai_user"):
print("ERRO DE CONFIGURAÇÃO:")
print("Por favor, preencha os valores de 'session_id' e 'ai_user' no dicionário COOKIES no início do script.")
sys.exit(1)
texttry: asyncio.run(chat_cli()) except Exception as e: print(f"\nOcorreu um erro fatal no loop principal: {e}") # Tenta executar no loop de evento existente, caso esteja em um ambiente como IPython/Jupyter try: loop = asyncio.get_running_loop() if loop.is_running(): print("Tentando agendar em um loop de evento já em execução...") task = loop.create_task(chat_cli()) loop.run_until_complete(task) except RuntimeError: pass # Se não houver loop, o programa termina
Pelo erro, o Playwright está esperando um textarea[placeholder*="Ask me anything"]
, mas você forçou pt-BR
nos cookies (i18n_set: "pt-BR"
). Com isso, o placeholder não é “Ask me anything”, e o seletor nunca aparece — daí o timeout.
Além disso, muitos chats modernos nem usam <textarea>
: usam um <div contenteditable="true">
com role="textbox"
. Então mesmo em inglês o seletor pode falhar.
A correção é tornar os seletores de UI “agnósticos de idioma” e tolerantes ao tipo de campo. Também é bom ter um fallback de envio via Enter
. Abaixo vai uma versão robusta de get_recaptcha_token
com essas melhorias (e mais alguns ajustes úteis):
pythonimport re from playwright.async_api import async_playwright, Route, TimeoutError as PwTimeout async def get_recaptcha_token(cookies: Dict[str, str], headless: bool = True) -> Optional[str]: print("[Playwright] Iniciando navegador para obter token reCAPTCHA...") token_captured = asyncio.Event() captured_token: Optional[str] = None async def route_handler(route: Route): nonlocal captured_token req = route.request # Intercepta o POST do chat para extrair o token if req.url == GENSPARK_API_URL and req.method == "POST": try: data = await req.post_data_json() tok = data.get("g_recaptcha_token") if tok: print("[Playwright] Token reCAPTCHA capturado com sucesso.") captured_token = tok token_captured.set() await route.abort() # aborta para não consumirmos quota/ação return except Exception as e: print(f"[Playwright] Erro ao processar POST do chat: {e}") await route.continue_() p = browser = context = page = None try: p = await async_playwright().start() browser = await p.chromium.launch(headless=headless, args=["--disable-blink-features=AutomationControlled"]) context = await browser.new_context( user_agent=BASE_HEADERS["User-Agent"], locale="pt-BR", # combina com seus cookies timezone_id="America/Sao_Paulo", # opcional, mas ajuda a parecer “humano” viewport={"width": 1366, "height": 768} ) # Aplica cookies (sem depender do placeholder em inglês) await context.add_cookies([ {"name": k, "value": v, "domain": ".genspark.ai", "path": "/"} for k, v in cookies.items() if v ]) page = await context.new_page() await page.route("**/*", route_handler) # Carrega a página e espera a app SPA estabilizar await page.goto(GENSPARK_CHAT_URL, wait_until="domcontentloaded") await page.wait_for_load_state("networkidle") # aguarda bundles/SPA # Alguns sites mostram banner de cookies/termos; tente fechar se existir (opcional e tolerante a erro) try: # Procura qualquer botão com texto “Aceitar/Accept/OK” (português/inglês) btn = page.get_by_role("button", name=re.compile(r"(aceit|accept|ok|entendi)", re.I)).first if await btn.is_visible(): await btn.click() except Exception: pass # Localizador do campo de entrada — agnóstico de idioma e do tipo (textarea ou contenteditable) # Preferimos role="textbox" (Playwright mapeia automaticamente). textbox = page.get_by_role("textbox").first # Fallback: procura manualmente por elementos comuns de chat async def ensure_textbox(): nonlocal textbox try: await textbox.wait_for(state="visible", timeout=10000) return True except PwTimeout: pass # Tenta padrões alternativos candidates = [ 'textarea', '[contenteditable="true"]', 'div[contenteditable="true"]', 'form textarea', ] for sel in candidates: loc = page.locator(sel).first try: await loc.wait_for(state="visible", timeout=3000) textbox = loc return True except PwTimeout: continue return False ok = await ensure_textbox() if not ok: raise PwTimeout("Campo de entrada do chat não encontrado (nem textbox/textarea/contenteditable).") # Digita e envia a mensagem para disparar o POST com o token try: await textbox.click() # Algumas implementações de contenteditable não suportam fill() try: await textbox.fill("Olá") except Exception: await page.keyboard.type("Olá", delay=50) # Tente clicar em um botão “Enviar/Send” se existir; senão, Enter try: send_btn = page.get_by_role("button", name=re.compile(r"(enviar|send|ask|falar)", re.I)).first if await send_btn.is_visible(): await send_btn.click() else: await page.keyboard.press("Enter") except Exception: await page.keyboard.press("Enter") except Exception as e: raise RuntimeError(f"Falha ao interagir com a UI do chat: {e}") # Aguarda o token capturado pela rota await asyncio.wait_for(token_captured.wait(), timeout=45) return captured_token except asyncio.TimeoutError: print("[Playwright] ERRO: Timeout ao esperar pelo token. A página pode ter mudado, login expirou ou há um desafio adicional (ex.: captcha visível).") return None except Exception as e: print(f"[Playwright] ERRO: Ocorreu uma exceção inesperada: {e}") return None finally: if context: await context.close() if browser: await browser.close() if p: await p.stop() print("[Playwright] Navegador finalizado.")
"Ask me anything"
. Usa get_by_role("textbox")
e fallbacks.contenteditable
: se não houver <textarea>
, ainda funciona.Enter
.domcontentloaded
+ networkidle
reduz falsos timeouts.timeout=45
dá margem para o backend.headless=False
para ver o que a página mostra (login, banner, captcha visível, etc.).storage_state
:
pythonawait context.storage_state(path="state.json") # Depois: context = await browser.new_context(storage_state="state.json", ...)
page.locator('button:has(svg), [aria-label*=send i], [data-testid*=send i]').first
antes do Enter.await route.abort()
após capturar o token evita consumir a requisição inteira; se quiser deixar a mensagem “seguir”, troque para await route.continue_()
(mas aí você não aborta).Coloque esse get_recaptcha_token
no seu script e deve parar o timeout do wait_for_selector
. Se quiser, posso adaptar o seletor do botão aos atributos reais que você vê no DOM (aria-label, data-testid, etc.).