Scraping BrowserGuiasBypass de CloudFlare na raspagem da Web

Scraping de Navegador e Cloudflare

Este documento técnico explica como usar as ferramentas Scrapeless Scraping Browser e Scrapeless Web Unlocker para lidar com vários desafios de segurança configurados pelo Cloudflare. Recursos-chave incluem contornar o Desafio JS do Cloudflare, o Cloudflare Turnstile e executar a renderização de JavaScript para acessar conteúdo protegido pelo Cloudflare. Este documento fornecerá conhecimento de fundo relevante, introduções de recursos, etapas operacionais e explicações de exemplos de código.

Compreendendo os Desafios e Camadas de Segurança do Cloudflare

O Cloudflare, um serviço popular de segurança e desempenho da web, protege principalmente os sites de tráfego malicioso ou inesperado, como bots e scanners. Para isso, o Cloudflare implementa vários mecanismos de detecção e defesa, incluindo, mas não se limitando a:

1. Desafio JS (Desafio JavaScript): Requer que o navegador do visitante execute código JavaScript específico para verificar se é um ambiente de navegador legítimo com funcionalidade padrão.

2. Alternativa CAPTCHA Turnstile: Um mecanismo de verificação menos intrusivo para distinguir entre usuários humanos e bots.

3. Impressão digital do navegador: Coleta e analisa as características técnicas do navegador e do dispositivo (por exemplo, User-Agent, resolução da tela, fontes instaladas, plug-ins) para identificar e rastrear visitantes.

4. Limitação de taxa: Monitora e limita o número de solicitações de uma única fonte (por exemplo, endereço IP) dentro de um tempo específico para evitar força bruta ou abuso de recursos.

Essas camadas de segurança impedem que bibliotecas de solicitação HTTP básicas, scripts simples ou navegadores headless configurados incorretamente acessem sites protegidos pelo Cloudflare, resultando em falhas de verificação e negação de acesso.

Diferenças entre o Desafio JS do Cloudflare e outros Desafios

A singularidade do Desafio JS do Cloudflare reside em seu método de verificação. Ele não apenas exige que os usuários concluam uma tarefa interativa simples (por exemplo, reconhecimento de imagem); ele exige que o ambiente do cliente (navegador) analise e execute com sucesso o código JavaScript gerado dinamicamente, muitas vezes ofuscado, do Cloudflare. Esse código executa verificações de ambiente, tarefas computacionalmente intensivas ou outra lógica para verificar as capacidades de comportamento complexo do cliente, imitando um navegador real.

Superar com sucesso o Desafio JS envolve a geração de um token de liberação válido (geralmente na forma de um cookie cf_clearance). Este token prova que o cliente passou na verificação da capacidade de execução de JavaScript. Muitas ferramentas de automação não possuem um mecanismo de execução JavaScript completo e uma simulação de ambiente de navegador realista, falhando, portanto, nesses desafios.

Contornando o Desafio JS do Cloudflare usando o Scrapeless Scraping Browser

O Scrapeless Scraping Browser foi projetado para lidar com medidas complexas de proteção de sites, incluindo o Desafio JS do Cloudflare.

Passos e Exemplo de Código

Configuração do Ambiente

Criar uma Pasta de Projeto

Crie uma nova pasta para o projeto, por exemplo: scrapeless-bypass.

Navegue até a pasta no seu terminal:

cd path/to/scrapeless-bypass

Inicializar o Projeto Node.js

Execute o seguinte comando para criar um arquivo package.json:

npm init -y

Instalar Dependências Necessárias

Instale o Puppeteer-core, que permite a conexão remota a instâncias do navegador:

npm install puppeteer-core

Se o Puppeteer ainda não estiver instalado em seu sistema, instale a versão completa:

npm install puppeteer puppeteer-core

Obtenha e configure sua chave de API Scrapeless.

Conecte-se e certifique-se de que o CAPTCHA foi resolvido com sucesso

O Scrapeless detecta e resolve automaticamente os CAPTCHAs ao se conectar ao navegador para acessar o site de destino. No entanto, precisamos garantir que o CAPTCHA foi resolvido com sucesso. O Scrapeless Scraping Browser estende o CDP (Chrome DevTools Protocol) padrão com um conjunto poderoso de recursos personalizados. O status do solucionador de CAPTCHA pode ser observado diretamente verificando os resultados retornados da API CDP:

  • Captcha.detected: CAPTCHA detectado
  • Captcha.solveFinished: CAPTCHA resolvido com sucesso
  • Captcha.solveFailed: Falha na resolução do CAPTCHA
import puppeteer from "puppeteer-core";
import EventEmitter from 'events';
const emitter = new EventEmitter()
const scrapelessUrl = 'wss://browser.scrapeless.com/browser?token=your_api_key&session_ttl=180&proxy_country=ANY';
 
export async function example(url) {
  const browser = await puppeteer.connect({
    browserWSEndpoint: scrapelessUrl,
    defaultViewport: null
  });
  console.log("Verbonden met Scrapeless browser");
  try {
    const page = await browser.newPage();
    // Listen for captcha events
    console.debug("addCaptchaListener: Start listening for captcha events");
    await addCaptchaListener(page);
    console.log("Navigated to URL:", url);
    await page.goto(url, { waitUntil: "domcontentloaded", timeout: 30000 });
    console.log("onCaptchaFinished: Waiting for captcha solving to finish...");
    await onCaptchaFinished()
    // Screenshot for debugging
    console.debug("Taking screenshot of the final page...");
    await page.screenshot({ path: 'screenshot.png', fullPage: true });
  } catch (error) {
    console.error(error);
  } finally {
    await browser.close();
    console.log("Browser closed");
  }
}
 
async function addCaptchaListener(page) {
  const client = await page.createCDPSession();
  client.on("Captcha.detected", (msg) => {
    console.debug("Captcha.detected: ", msg);
  });
  client.on("Captcha.solveFinished", async (msg) => {
    console.debug("Captcha.solveFinished: ", msg);
    emitter.emit("Captcha.solveFinished", msg);
    client.removeAllListeners()
  });
}
 
async function onCaptchaFinished(timeout = 60_000) {
  return Promise.race([
    new Promise((resolve) => {
      emitter.on("Captcha.solveFinished", (msg) => {
        resolve(msg);
      });
    }),
    new Promise((_, reject) => setTimeout(() => reject('Timeout'), timeout))
  ])
}

Este exemplo de fluxo de trabalho acessa o site de destino e confirma que o CAPTCHA foi resolvido com sucesso, ouvindo o evento Captcha.solveFinished CDP. Finalmente, ele captura uma captura de tela da página para verificação.

Este exemplo define dois métodos principais:

  • addCaptchaListener: para ouvir eventos CAPTCHA dentro da sessão do navegador
  • onCaptchaFinished: para esperar até que o CAPTCHA tenha sido resolvido

O código de exemplo acima pode ser usado para ouvir eventos CDP para três tipos comuns de CAPTCHA discutidos neste artigo: reCAPTCHA v2, Cloudflare Turnstile e Cloudflare 5s Challenge.

Observe que o Cloudflare 5s Challenge é um pouco especial. Às vezes, ele não aciona um desafio real, e depender apenas da detecção de eventos CDP para o sucesso pode levar a timeouts. Portanto, esperar que um elemento específico apareça na página após o desafio é uma solução mais estável.

Conectando-se ao WebSocket Scrapeless Browserless

Scrapeless fornece uma conexão WebSocket, permitindo que o Puppeteer interaja diretamente com o navegador headless, contornando os desafios do Cloudflare.

O endereço completo de conexão WebSocket:

wss://browser.scrapeless.com/browser?token=APIKey&session_ttl=180&proxy_country=ANY

Exemplo de Código: Contornando o Desafio do Cloudflare

Precisamos apenas do seguinte código para conectar ao serviço browserless do Scrapeless.

import puppeteer from 'puppeteer-core';
 
const API_KEY = 'your_api_key'
const host = 'wss://browser.scrapeless.com';
const query = new URLSearchParams({
  token: API_KEY,
  session_ttl: '180', // The life cycle of a browser session, in seconds
  proxy_country: 'GB', // Agent country
  proxy_session_id: 'test_session_id', // The proxy session id is used to keep the proxy ip unchanged. The session time is 3 minutes by default, based on the proxy_session_duration setting.
  proxy_session_duration: '5' // Agent session time, unit minutes
}).toString();
 
const connectionURL = `${host}/browser?${query}`;
const browser = await puppeteer.connect({
    browserWSEndpoint: connectionURL,
    defaultViewport: null,
});
console.log('Connected!')

Acessando sites protegidos pelo Cloudflare e verificação de captura de tela

Em seguida, usamos o scrapeless browserless para acessar diretamente o site de teste do desafio do cloudflare e adicionar uma captura de tela, permitindo a verificação visual. Antes de tirar a captura de tela, observe que você precisa usar waitForSelector para esperar os elementos na página, garantindo que o desafio do Cloudflare tenha sido contornado com sucesso.

const page = await browser.newPage();
await page.goto('https://www.scrapingcourse.com/cloudflare-challenge', {waitUntil: 'domcontentloaded'});
// By waiting for elements in the site page, ensuring that the Cloudflare challenge has been successfully bypassed.
await page.waitForSelector('main.page-content .challenge-info', {timeout: 30 * 1000})
await page.screenshot({path: 'challenge-bypass.png'});

Neste ponto, você contornou o desafio do Cloudflare usando o Scrapeless Browserless.

Após passar no desafio do Cloudflare, você pode recuperar os cabeçalhos da solicitação e o cookie cf_clearance da página bem-sucedida.

const cookies = await browser.cookies()
const cfClearance = cookies.find(cookie => cookie.name === 'cf_clearance')?.value

Ative a interceptação de solicitações para capturar os cabeçalhos da solicitação e corresponder às solicitações da página após o desafio do Cloudflare.

await page.setRequestInterception(true);
page.on('request', request => {
  // Match page requests after cloudflare challenge
  if (request.url().includes('https://www.scrapingcourse.com/cloudflare-challenge') && request.headers()?.['origin']) {
    const accessRequestHeaders = request.headers();
    console.log('[access_request_headers] =>', accessRequestHeaders);
  }
  request.continue();
});

Contornando o Cloudflare Turnstile usando o Scrapeless Scraping Browser

O Scrapeless Scraping Browser também lida com desafios do Cloudflare Turnstile.

Da mesma forma, ao enfrentar o Cloudflare Turnstile, o navegador de scraping browserless ainda pode lidar com ele automaticamente. O exemplo a seguir acessa o site de teste do cloudflare-turnstile. Após inserir o nome de usuário e a senha, ele usa o método waitForFunction para aguardar dados de window.turnstile.getResponse(), garantindo que o desafio seja contornado com sucesso. Em seguida, ele tira uma captura de tela e clica no botão de login para navegar para a próxima página.

Passos e Exemplo de Código:

const page = await browser.newPage();
await page.goto('https://www.scrapingcourse.com/login/cf-turnstile', { waitUntil: 'domcontentloaded' });
await page.locator('input[type="email"]').fill('admin@example.com')
await page.locator('input[type="password"]').fill('password')
// Wait for turnstile to unlock successfully
await page.waitForFunction(() => {
  return window.turnstile && window.turnstile.getResponse();
});
await page.screenshot({ path: 'challenge-bypass-success.png' });
await page.locator('button[type="submit"]').click()
await page.waitForNavigation()
await page.screenshot({ path: 'next-page.png' });

Após executar este script, você verá o efeito de desbloqueio por meio de capturas de tela.

Usando o Scrapeless Web Unlocker para renderização JavaScript

Para sites protegidos pelo Cloudflare em que o conteúdo principal depende da execução de JavaScript do lado do cliente para o carregamento e exibição completos, o Scrapeless Web Unlocker fornece uma solução dedicada.

A API Universal Scrapeless permite a renderização de JavaScript e interação dinâmica, tornando-a uma ferramenta eficaz para contornar o Cloudflare.

Renderização JavaScript

A renderização JavaScript suporta o tratamento de conteúdo carregado dinamicamente e SPAs (Single-Page Applications). Ele suporta um ambiente de navegador completo, lidando com interações de página e requisitos de renderização mais complexos.

Com js_render=true, usaremos o navegador para a solicitação

{
  "actor": "unlocker.webunlocker",
  "input": {
    "url": "https://www.google.com/",
    "js_render": true
  },
  "proxy": {
    "country": "US"
  }
}

Instruções JavaScript

Fornece um amplo conjunto de instruções JavaScript, permitindo a interação dinâmica com páginas da web.

Essas instruções permitem clicar em elementos, preencher formulários, enviar formulários ou esperar que elementos específicos apareçam, fornecendo flexibilidade para tarefas como clicar em um botão “Ler Mais” ou enviar um formulário.

{
  "actor": "unlocker.webunlocker",
  "input": {
    "url": "https://example.com",
    "js_render": true,
    "js_instructions": [
      {
        "wait_for": [
          ".dynamic-content",
          30000
        ]
        // Wait for element
      },
      {
        "click": [
          "#load-more",
          1000
        ]
        // Click element
      },
      {
        "fill": [
          "#search-input",
          "search term"
        ]
        // Fill form
      },
      {
        "keyboard": [
          "press",
          "Enter"
        ]
        // Simulate key press
      },
      {
        "evaluate": "window.scrollTo(0, document.body.scrollHeight)"
        // Execute custom JS
      }
    ]
  }
}

Exemplo de contorno de desafio

O exemplo a seguir usa o axios para enviar uma solicitação ao serviço Web Unlocker do Scrapeless. Ele habilita js_render e usa a instrução wait_for no parâmetro js_instructions para esperar um elemento na página após contornar o desafio do Cloudflare:

import axios from 'axios'
 
async function sendRequest() {
  const host = "api.scrapeless.com";
  const url = `https://${host}/api/v1/unlocker/request`;
  const API_KEY = 'your_api_key'
 
  const payload = {
    actor: "unlocker.webunlocker",
    proxy: {
      country: "US"
    },
    input: {
      url: "https://www.scrapingcourse.com/cloudflare-challenge",
      js_render: true,
      js_instructions: [
        {
          wait_for: [
            "main.page-content .challenge-info",
            30000
          ]
        }
      ]
    },
  }
 
  try {
    const response = await axios.post(url, payload, {
      headers: {
        'Content-Type': 'application/json',
        'x-api-token': API_KEY
      }
    });
    console.log("[page_html_body] =>", response.data);
  } catch (error) {
    console.error('Error:', error);
  }
}
sendRequest();

Após executar o script acima, você poderá ver o HTML da página que contornou com sucesso o desafio do Cloudflare no console.