Como é que o Cloudflare deteta navegadores headless?
A Cloudflare é uma empresa de tecnologia com uma rede gigantesca. Concentra-se em serviços como CDN, DNS e vários sistemas de segurança online. O seu Web Application Firewall é normalmente concebido para proteger contra ataques como DDoS ou cross site scripting. Nos últimos anos, a Cloudflare adicionou, e outros fornecedores na área introduziram, sistemas de fingerprinting, capazes de detetar navegadores headless. Como se pode imaginar, um dos primeiros afetados por estas técnicas é o Selenium. E como a indústria de web scraping depende fortemente desta tecnologia, os scrapers também são diretamente afetados.
Antes de avançarmos para as técnicas anti-bot, penso que é importante discutir como o Cloudflare deteta o Selenium. Bem, o sistema pode ser muito complexo. Por exemplo, existem propriedades num navegador que faltam a um web driver. A interface `navigator` num navegador tem até uma propriedade chamada `webdriver` que indica se um navegador é controlado por automação. E isso é uma pista imediata. Se quiser experimentar:
- Abra as ferramentas de programador do seu navegador
- Navegue até à consola
- Digite o seguinte comando: `navigator.webdriver`
No seu caso, deve devolver `false`. Mas se o experimentar com o Puppeteer ou o Selenium, obterá `true`. Se está a perguntar-se como é que o Cloudflare aproveita isto para detetar bots, bem, é bastante simples. Tudo o que precisam de fazer é inserir um script como o que se segue no site do seu parceiro:
// detection-script.js
const webdriver = navigator.webdriver
// If webdriver returns true, display a reCaptcha
// In this example, I am transferring the user to a Cloudflare challenge page.
// But you get the idea
if ( webdriver ) location.replace('https://cloudflarechallenge.com')
É claro que, na vida real, existem muitos mais níveis de deteção que estes fornecedores utilizam. Até mesmo o tamanho do ecrã, o layout do teclado ou os plugins utilizados pelos navegadores são usados para identificar especificamente um navegador. Se estiver interessado em saber como funciona a deteção sem navegador, consulte o meu teste simples de service worker. E isso é apenas se se limitar ao navegador. Também é possível detetar atividade de bots analisando o endereço IP de onde a solicitação se origina. Por exemplo, se estiver a utilizar IPs de centros de dados, as suas hipóteses de ser bloqueado aumentam a cada solicitação. É por isso que se recomenda utilizar proxies residenciais ou de ISP quando estiver a criar um web scraper.
Como contornar o Cloudflare com o Selenium
Felizmente, a comunidade de web scraping é muito ativa. E como existe tanta procura para contornar o Cloudflare e outros fornecedores anti-bot, existem soluções de código aberto nessa área. É possível alcançar grandes resultados quando as comunidades de programação trabalham em conjunto! De agora em diante, sugiro que sigamos estes passos:
- Executar alguns testes para verificar se o Selenium padrão consegue contornar o Cloudflare
- Adicionar algumas evasões extra aos nossos scripts para os tornar mais furtivos
Então, vamos começar com o nosso primeiro passo:
#1: O Selenium padrão consegue contornar o Cloudflare?
Não sou do tipo que faz suposições. E isso deve-se especialmente ao facto de não sabermos ao certo como funcionam os sistemas da Cloudflare. Eles utilizam todo o tipo de ofuscação no seu código, o que torna mais difícil a engenharia reversa. É por isso que, ao longo da minha experiência como programador, aprendi que testar é a melhor forma de compreender como um sistema funciona. Vamos, então, criar um scraper básico e ver como ele se comporta num alvo real, protegido pelo Cloudflare.
1.1. Configurar o ambiente
Com o Python, é melhor isolar os nossos projetos dentro de um único diretório. Então, vamos criar uma nova pasta, abrir uma janela de terminal e navegar até ela:
# Create a new virtual environment and activate it
~ » python3 -m venv env && source env/bin/activate
# Install dependencies
~ » python3 -m pip install selenium
# Create a new .py file and open the project inside your IDE
~ » touch app.py && code .
1.2. Criar um scraper web simples com Selenium
Agora que configurou o seu projeto com sucesso, é hora de adicionar algum código. Não vamos criar nada sofisticado aqui. Precisamos apenas deste script para fins de teste. Se quiser aprender sobre scraping avançado, consulte este tutorial [LINK](AICI TREBUIE POSTAT ARTICOLUL) sobre o Pyppeteer.
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
# Set Chrome to open in headless mode
options = Options()
options.headless = True
# Create a new Chrome instance and navigate to target
driver = webdriver.Chrome(options=options)
driver.get('https://www.snipesusa.com/')
# Give it some time to load
time.sleep(10)
# Take screenshot of page
driver.get_screenshot_as_file('screenshot.png')
# Close browser
driver.quit()
Agora veja a captura de ecrã. Eis o que obtive:
Acho que podemos concluir com segurança que o teste falhou. O site alvo está protegido pelo Cloudflare e, como pode ver, estamos a ser bloqueados. Portanto, por predefinição, o Selenium não consegue contornar o Cloudflare. Não vou aprofundar o assunto nem verificar com outros fornecedores de deteção de bots. Se quiser testar mais, aqui estão alguns alvos e os seus fornecedores:

#2: O Selenium furtivo consegue contornar o Cloudflare?
Em primeiro lugar, deixem-me esclarecer os termos. Por Selenium «stealthy» refiro-me a uma versão do Selenium que consegue passar despercebida e contornar o Cloudflare. Não me refiro a nenhuma técnica específica de ocultação. Existem algumas formas de implementar técnicas de evasão no Selenium. Existem pacotes que tratam disso, ou pode usar o `execute_cdp_cmd` para interagir diretamente com a API do Chrome. Esta última opção permite-lhe mais controlo, mas requer mais trabalho. Aqui está um exemplo de como poderia usá-la para alterar o valor do agente do utilizador:
driver.execute_cdp_cmd('Emulation.setUserAgentOverride', {
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win32; x86) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36",
"platform": "Win32",
"acceptLanguage":"ro-RO"
})
Mas teria de passar pelo CDP e identificar as APIs que permitem efetuar todas as alterações necessárias. Por isso, por enquanto, vamos testar com alguns pacotes.
1.1. Selenium Stealthy
Existem pelo menos dois pacotes que pode utilizar para tornar o Selenium furtivo. Até ao momento, porém, nenhum deles garante contornar o Cloudflare. Mais uma vez, precisamos de testar e ver se algum deles funciona. Primeiro, vamos dar uma olhada no `selenium-stealth`. Este pacote é um wrapper em torno do `puppeteer-extra-plugin-stealth`, tornando possível usar as evasões do Puppeteer com o Selenium do Python. Para usá-lo, tem de o instalar primeiro. Abra uma janela de terminal e digite este comando:
# Install selenium-stealth
~ » python3 -m pip install selenium-stealth
Já está tudo pronto. Podemos usá-lo para tornar o nosso scraper anterior mais discreto:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium_stealth import stealth
import time
# Set Chrome to open in headless mode
options = Options()
options.headless = True
# Create a new Chrome instance
driver = webdriver.Chrome(options=options)
# Apply stealth to your webdriver
stealth(driver,
languages=["en-US", "en"],
vendor="Google Inc.",
platform="Win32",
webgl_vendor="Intel Inc.",
renderer="Intel Iris OpenGL Engine",
fix_hairline=True,
)
# Navigate to target
driver.get('https://www.snipesusa.com/')
# Give it some time to load
time.sleep(10)
# Take screenshot of page
driver.get_screenshot_as_file('stealth.png')
# Close browser
driver.quit()
Ao executar o script, obtive resultados diferentes desta vez, em comparação com as configurações padrão do Selenium:
A segunda opção que pode utilizar é o `undetected_chromedriver`. Este é descrito como um «chromedriver Selenium otimizado». Vamos testá-lo:
# Install undetected_chromedriver
~ » python3 -m pip install undetected_chromedriver
O código é muito semelhante ao nosso script padrão. A principal diferença está no nome do pacote. Aqui está um scraper básico com `undetected_chromedriver` e vamos ver se consegue contornar o Cloudflare:
import undetected_chromedriver as uc
import time
# Set Chrome to open in headless mode
options = uc.ChromeOptions()
options.headless = True
# Create a new Chrome instance and maximize the window
driver = uc.Chrome(options=options, executable_path='/Applications/Google Chrome.app/Contents/MacOS/Google Chrome')
driver.maximize_window()
# Navigate to target
driver.get('https://www.snipesusa.com/')
# Give it some time to load
time.sleep(10)
# Take screenshot of page
driver.get_screenshot_as_file('stealth-uc.png')
# Close browser
driver.quit()
Mais uma vez, a execução do script correu bem para mim. Parece que, pelo menos, estes dois pacotes conseguem contornar com sucesso a proteção do Cloudflare. Pelo menos a curto prazo. Para dizer a verdade, é provável que, se utilizar estes scripts extensivamente, o Cloudflare detete o seu endereço IP e o bloqueie.
Por isso, deixe-me apresentar-lhe uma terceira opção: a API de Web Scraping.
1.2. Selenium com a API de Web Scraping
A Web Scraping API tem uma funcionalidade incrível chamada Modo Proxy. Pode ler mais sobre isso aqui. Mas o que quero salientar aqui é que o nosso Modo Proxy pode ser integrado com sucesso com o Selenium. Desta forma, obtém acesso a todas as funcionalidades de evasão que implementámos. E deixe-me dizer-lhe que temos uma equipa dedicada a trabalhar em técnicas de evasão personalizadas. Em termos técnicos, estamos a gerir rotações de IP, a utilizar vários proxies, a resolver captchas e a utilizar a API do Chrome para alterar continuamente a nossa impressão digital. Em termos não técnicos, isto traduz-se em menos complicações da sua parte e numa maior taxa de sucesso. Basicamente, obtém a versão mais discreta do Selenium que existe. E eis como se faz:
# Install selenium-wire
~ » python3 -m pip install selenium-wire
Estamos a utilizar o `selenium-wire` para utilizar o Selenium com um proxy. Aqui está o script:
from seleniumwire import webdriver
import time
# Method to encode parameters
def get_params(object):
params = ''
for key,value in object.items():
if list(object).index(key) < len(object) - 1:
params += f"{key}={value}."
else:
params += f"{key}={value}"
return params
# Your WSA API key
API_KEY = '<YOUR_API_KEY>'
# Default proxy mode parameters
PARAMETERS = {
"proxy_type":"datacenter",
"device":"desktop",
"render_js":1
}
# Set Selenium to use a proxy
options = {
'proxy': {
"http": f"http://webscrapingapi.{ get_params(PARAMETERS) }:{ API_KEY }@proxy.webscrapingapi.com:80",
}
}
# Create a new Chrome instance
driver = webdriver.Chrome(seleniumwire_options=options)
# Navigate to target
driver.get('https://www.httpbin.org/get')
# Retrieve the HTML documeent from the page
html = driver.page_source
print(html)
# Close browser
driver.quit()
Se executar este script algumas vezes, verá como o endereço IP muda sempre. Esse é o nosso sistema de rotação de IP. Em segundo plano, ele também adiciona técnicas de evasão. Nem precisa de se preocupar com elas. Nós tratamos da parte de contornar o Cloudflare para que se possa concentrar mais na análise dos dados.
Conclusões
Se quiser criar um scraper capaz de contornar o Cloudflare, tem de ter em conta muitos fatores. Uma equipa dedicada pode trabalhar 24 horas por dia, 7 dias por semana, e mesmo assim não há garantia de que as técnicas de evasão funcionem sempre. Isto porque, com cada lançamento de uma nova versão do navegador, existe a possibilidade de serem adicionadas novas funcionalidades à API. E algumas dessas funcionalidades podem ser usadas para identificar e detetar bots.
Diria mesmo que o melhor navegador para contornar o Cloudflare e outros fornecedores é aquele que você mesmo constrói. E nós construímos um na Web Scraping API. Agora estamos a partilhá-lo consigo. Por isso, aproveite o scraping!




