O scraping de job boards é um dos cenários mais procurados para coleta de dados para análise de RH, monitoramento do mercado de trabalho e automação de recrutamento. No entanto, os sites de vagas estão ativamente se protegendo contra a coleta automática de dados: bloqueiam IPs após 50-100 solicitações, exibem captcha e banem contas suspeitas. Neste artigo, vamos discutir como configurar corretamente proxies para scraping estável do hh.ru, Superjob, LinkedIn e outras plataformas sem bloqueios.
Por que job boards bloqueiam scraping e como funciona a proteção
Os sites de vagas perdem dinheiro com scraping: os dados são vendidos para concorrentes, agregadores sem licença são criados, e empregadores contornam as publicações pagas. Portanto, todas as grandes plataformas implementaram uma proteção em múltiplas camadas contra a coleta automática de dados.
Principais métodos de proteção dos job boards:
- Limitação de taxa por IP — hh.ru bloqueia IP após 80-120 solicitações por hora, Superjob — após 50-70 solicitações. O bloqueio pode durar de 1 hora a um dia.
- Fingerprinting do navegador — os sites analisam o User-Agent, cabeçalhos HTTP, resolução de tela, fontes instaladas. Se os dados não corresponderem a um navegador real — a solicitação é bloqueada.
- Verificações JavaScript — muitos sites usam Cloudflare ou seus próprios scripts para verificar se a solicitação vem de um navegador real, e não de um bot.
- Armadilhas Honeypot — links e campos ocultos que só o parser vê. Se o bot clicar neles — o IP é colocado na lista negra.
- Captcha em caso de atividade suspeita — aparece após uma série de solicitações rápidas ou ao usar IPs de data centers.
Sem proxies, você conseguirá coletar no máximo 100-200 vagas, após o que seu IP será banido. Para coleta em larga escala (milhares de vagas diariamente), proxies se tornam uma ferramenta obrigatória.
Importante: O scraping deve estar de acordo com os termos de uso do site. Muitos job boards oferecem APIs oficiais para acesso legal aos dados. Por exemplo, hh.ru tem uma API gratuita com limite de solicitações, que é adequada para a maioria das tarefas.
Qual tipo de proxy escolher para scraping de vagas
A escolha do tipo de proxy depende da escala do scraping, do orçamento e dos requisitos de velocidade. Vamos discutir três opções principais com cenários de uso específicos.
| Tipo de proxy | Velocidade | Risco de banimento | Quando usar |
|---|---|---|---|
| Data center | Alta (50-200 ms) | Alto | Teste do parser, coleta de dados públicos sem autenticação |
| Residenciais | Média (200-800 ms) | Baixo | Scraping em larga escala do hh.ru, Superjob com rotação de IP |
| Móveis | Média (300-1000 ms) | Muito baixo | Scraping com autenticação, contornando a proteção rigorosa do LinkedIn |
Proxies de data center para scraping
Esta é a opção mais rápida e barata, mas com limitações. IPs de data center são facilmente reconhecidos pelos sites, portanto, eles são adequados apenas para tarefas simples: scraping de listas de vagas sem autenticação, coleta de dados públicos, teste do parser antes de iniciar com proxies residenciais.
Quando os proxies de data center funcionam:
- Scraping de pequeno volume de dados (até 500 vagas por dia)
- Coleta de dados de sites sem proteção rigorosa (pequenos job boards regionais)
- Uso de APIs oficiais com rotação de IP para contornar limites de taxa
- Scraping de feeds RSS e arquivos XML de vagas
Para hh.ru e Superjob, proxies de data center funcionarão de forma instável: você receberá captcha após 20-30 solicitações, e muitos IPs já estão em listas negras desses sites.
Proxies residenciais — a escolha ideal para job boards
Proxies residenciais usam endereços IP de usuários reais, portanto, os sites os percebem como visitantes normais. Esta é a melhor relação custo-benefício para scraping de vagas.
Vantagens para scraping de job boards:
- Baixo risco de bloqueio — hh.ru e Superjob não conseguem distinguir um IP residencial de um usuário real
- Grande pool de endereços IP — é possível configurar a rotação a cada solicitação ou a cada 5-10 minutos
- Vinculação geográfica — é possível fazer scraping de vagas de uma cidade específica, usando IP dessa região
- Estabilidade — um IP residencial pode processar 200-500 solicitações sem bloqueio
Para scraping em larga escala (mais de 1000 vagas por dia), proxies residenciais com rotação de IP são a solução padrão. Você configura a troca de IP a cada 5-10 minutos, adiciona delays aleatórios entre as solicitações (3-7 segundos) e obtém uma coleta de dados estável sem bloqueios.
Proxies móveis para LinkedIn e scraping com autenticação
Proxies móveis usam IPs de operadoras de telefonia. Sua principal vantagem é que um IP é usado por centenas de usuários reais ao mesmo tempo, portanto, os sites não podem bloquear esse endereço sem o risco de bloquear milhares de visitantes comuns.
Quando são necessários proxies móveis:
- Scraping do LinkedIn — esta plataforma tem a proteção mais rigorosa contra bots e bloqueia agressivamente IPs de data center e até mesmo residenciais
- Trabalho com autenticação — se você precisa fazer scraping de vagas fechadas ou dados de perfis, IPs móveis reduzem o risco de banimento da conta
- Scraping de job boards estrangeiros — Indeed, Glassdoor, Monster usam sistemas de proteção avançados, onde IPs móveis funcionam de forma mais confiável
- Contornando bloqueios rigorosos — se seus proxies residenciais começaram a receber captcha, mudar para móveis resolverá o problema
A desvantagem dos proxies móveis é o alto custo e a menor velocidade. Mas para tarefas críticas, onde o bloqueio é inaceitável, essa é a melhor escolha.
Particularidades do scraping do hh.ru: proteção e formas de contorno
hh.ru é o maior site de vagas da Rússia, com a proteção mais avançada contra scraping entre os job boards nacionais. O site usa uma combinação de limitação de taxa, fingerprinting e análise comportamental para identificar bots.
Como funciona a proteção do hh.ru
1. Limites por endereço IP: Após 80-120 solicitações por hora de um único IP, o site começa a mostrar captcha ou retorna HTTP 429 (Too Many Requests). O bloqueio dura de 1 a 6 horas, dependendo da agressividade do scraping.
2. Verificação de User-Agent e cabeçalhos: hh.ru analisa os cabeçalhos das solicitações HTTP. Se o User-Agent não corresponder a um navegador real ou se faltarem cabeçalhos padrão (Accept-Language, Accept-Encoding), a solicitação é bloqueada.
3. Verificações JavaScript: Algumas páginas do hh.ru exigem a execução de JavaScript para carregar dados. Um parser HTTP simples sem um navegador headless não conseguirá obter o conteúdo completo.
4. Links Honeypot: Nas páginas há elementos ocultos que só o parser vê. Se seu script clicar nesses links — o IP é colocado na lista negra por 24 horas.
Estratégia de contorno da proteção do hh.ru com proxies
Para scraping estável do hh.ru sem bloqueios, use a seguinte configuração:
Configuração ideal para scraping do hh.ru:
- Tipo de proxy: Residenciais com rotação de IP a cada 5-10 minutos
- Delay entre solicitações: 4-8 segundos (valor aleatório)
- User-Agent: Rotação de User-Agents reais de navegadores modernos (Chrome, Firefox, Safari das últimas versões)
- Cabeçalhos: Conjunto completo de cabeçalhos padrão de navegador (Accept, Accept-Language, Accept-Encoding, Referer)
- Cookies: Manutenção e transmissão de cookies entre solicitações dentro de uma mesma sessão
- Limite de solicitações: Não mais que 60-80 solicitações por IP, após o que troca-se o proxy
Exemplo de sequência de ações seguras:
- Conectar-se a um proxy residencial com IP da região desejada (por exemplo, Moscovo)
- Fazer a primeira solicitação na página inicial do hh.ru, obter e salvar cookies
- Aguardar 5-7 segundos (simulando a leitura da página)
- Fazer uma solicitação na página de busca de vagas com os filtros desejados
- Fazer scraping da lista de vagas (normalmente 20-50 por página)
- Para cada vaga, fazer uma solicitação na página detalhada com um delay de 4-6 segundos
- Após 60-70 solicitações, trocar o proxy e repetir o ciclo
Com essa estratégia, você pode fazer scraping de 1000-2000 vagas por dia de um único fluxo sem um único bloqueio. Se precisar de um volume maior — inicie vários fluxos paralelos com diferentes proxies.
Dica: hh.ru oferece uma API gratuita para acesso a vagas. Para a maioria das tarefas (análise do mercado de trabalho, monitoramento de salários), a API será uma solução mais estável do que o scraping de HTML. Proxies podem ser usados para rotação de IP ao trabalhar com a API, para contornar limites de taxa.
Scraping do Superjob, LinkedIn e plataformas estrangeiras
Superjob: particularidades da proteção
O Superjob tem uma proteção menos rigorosa em comparação com o hh.ru, mas ainda assim luta ativamente contra o scraping. As principais diferenças:
- Limite de taxa mais baixo: O bloqueio ocorre após 50-70 solicitações por hora (contra 80-120 do hh.ru)
- Verificação de cabeçalhos menos rigorosa: É possível usar um conjunto simplificado de cabeçalhos
- Ausência de proteção JavaScript: A maioria dos dados está disponível através de uma simples solicitação HTTP sem um navegador headless
- Bloqueio regional: Algumas vagas estão disponíveis apenas com IP de uma região específica
Para o Superjob, são suficientes proxies residenciais com rotação a cada 10-15 minutos e delay entre solicitações de 3-5 segundos. Isso permitirá fazer scraping de 500-1000 vagas por dia de forma estável.
LinkedIn: a proteção mais rigorosa
O LinkedIn é uma história à parte. A plataforma usa algoritmos avançados de aprendizado de máquina para identificar bots e possui um dos sistemas de proteção mais agressivos entre todas as redes sociais e job boards.
Particularidades da proteção do LinkedIn:
- Autenticação obrigatória: A maioria dos dados está disponível apenas para usuários autenticados
- Análise comportamental: O LinkedIn analisa padrões de ação: velocidade de rolagem, movimentos do mouse, tempo na página
- Bloqueio de contas: Com atividade suspeita, não apenas o IP é bloqueado, mas também a conta em si
- Limitações na visualização de perfis: Contas gratuitas podem visualizar um número limitado de perfis por mês
- Execução obrigatória de JavaScript: Sem um navegador headless, o scraping é impossível
Estratégia de scraping do LinkedIn:
- Use proxies móveis — eles oferecem o menor risco de bloqueio. Um IP móvel pode ser usado para 100-200 visualizações de perfis por dia.
- Navegador headless é obrigatório — use Puppeteer ou Playwright com configuração de fingerprint real do navegador (resolução de tela, WebGL, Canvas).
- Velocidade de scraping lenta — não mais que 20-30 perfis por hora de uma conta. Adicione delays de 10-20 segundos entre visualizações.
- Simulação de comportamento real — rolagem da página, cliques aleatórios, transições entre seções do perfil.
- Preparação de contas — novas contas do LinkedIn não podem ser usadas imediatamente para scraping. É necessário 1-2 semanas simulando a atividade de um usuário comum.
- Rotação de contas — use várias contas com diferentes proxies para distribuir a carga.
O scraping do LinkedIn é a tarefa mais difícil entre todos os job boards. Se você precisa de dados dessa plataforma, considere usar a API oficial do Sales Navigator ou serviços de terceiros que fornecem dados legalmente.
Job boards estrangeiros: Indeed, Glassdoor, Monster
As plataformas estrangeiras geralmente têm proteção mais rigorosa do que os sites russos (exceto hh.ru). As principais características:
- Indeed — usa Cloudflare com verificações JavaScript. É necessário um navegador headless e proxies residenciais/móveis do país cujas vagas você está scraping.
- Glassdoor — requer autenticação para visualizar a maioria dos dados. Bloqueia ativamente IPs de data center. Use proxies residenciais e velocidade de scraping lenta (delay de 8-12 segundos).
- Monster — tem uma API para parceiros, mas para scraping de HTML são necessários proxies residenciais com vinculação geográfica ao país desejado.
Para todas as plataformas estrangeiras, a vinculação geográfica dos proxies é crítica. Se você está scraping vagas nos EUA, use IPs residenciais americanos. Solicitações com IPs de outros países podem levantar suspeitas e levar ao bloqueio.
Configuração de rotação de IP e delays entre solicitações
A configuração correta da rotação de proxies é a chave para um scraping estável sem bloqueios. Vamos discutir duas estratégias principais: rotação a cada solicitação e rotação por tempo.
Rotação a cada solicitação (Rotating Proxies)
Com essa abordagem, cada solicitação HTTP é feita com um novo endereço IP. Este é o método mais seguro, mas tem limitações:
Vantagens:
- Impossível rastrear a atividade de um único IP
- É possível fazer mais solicitações em um curto período
- Não é necessário monitorar limites para cada IP
Desvantagens:
- Impossível manter a sessão (cookies são perdidos ao trocar de IP)
- Não é adequado para scraping com autenticação
- Alguns sites bloqueiam solicitações se o IP mudar com muita frequência
A rotação a cada solicitação é adequada para scraping de páginas públicas do hh.ru e Superjob sem autenticação. É configurada através do parâmetro do provedor de proxies (geralmente é um endpoint especial com rotação automática).
Rotação por tempo (Sticky Sessions)
Com essa abordagem, um IP é usado por um determinado período (5-30 minutos), após o qual ocorre a troca automática. Esta é a opção ideal para a maioria das tarefas de scraping de job boards.
Intervalos de rotação recomendados:
| Site | Intervalo de rotação | Máx. solicitações por IP | Delay entre solicitações |
|---|---|---|---|
| hh.ru | 5-10 minutos | 60-80 | 4-8 segundos |
| Superjob | 10-15 minutos | 50-70 | 3-5 segundos |
| 30-60 minutos | 20-40 | 10-20 segundos | |
| Indeed | 10-20 minutos | 40-60 | 5-10 segundos |
| Glassdoor | 15-30 minutos | 30-50 | 8-12 segundos |
Configuração de delays aleatórios
Um delay fixo entre solicitações (por exemplo, exatamente 5 segundos) parece suspeito para sistemas de proteção. Um usuário real não pode agir com tal precisão. Sempre use delays aleatórios dentro de um intervalo.
Exemplos de implementação de delays aleatórios:
// Python
import time
import random
# Delay de 4 a 8 segundos
delay = random.uniform(4, 8)
time.sleep(delay)
# Lógica mais complexa: às vezes fazemos uma pausa longa
if random.random() < 0.1: # 10% de probabilidade
time.sleep(random.uniform(15, 30)) # Simulando distração do usuário
else:
time.sleep(random.uniform(4, 8))
// JavaScript / Node.js
const sleep = (min, max) => {
const delay = Math.random() * (max - min) + min;
return new Promise(resolve => setTimeout(resolve, delay * 1000));
};
// Uso
await sleep(4, 8); // Delay de 4-8 segundos
// Com probabilidade de pausa longa
if (Math.random() < 0.1) {
await sleep(15, 30); // 10% de probabilidade de pausa longa
} else {
await sleep(4, 8);
}
Adicionar pausas longas aleatórias (15-30 segundos) com uma probabilidade de 5-10% torna o comportamento do parser ainda mais semelhante ao de um usuário real, que pode se distrair com uma ligação ou outra tarefa.
Tratamento de captcha e outros bloqueios
Mesmo com a configuração correta de proxies e delays, você pode se deparar com captcha ou outros tipos de bloqueios. Vamos discutir como reagir corretamente a essas situações.
Tipos de bloqueios dos job boards
1. HTTP 429 Too Many Requests — o tipo de bloqueio mais comum. O site informa claramente que você excedeu o limite de solicitações. Geralmente, no cabeçalho da resposta há um Retry-After, que indica em quantos segundos você pode repetir a solicitação.
Como tratar: Mude imediatamente o proxy e adicione o IP atual à lista negra pelo tempo indicado no Retry-After (geralmente 1-6 horas). Se o Retry-After estiver ausente, adicione o IP à lista negra por 2 horas.
2. HTTP 403 Forbidden — IP bloqueado no nível do servidor. Este é um bloqueio mais sério, que pode durar de algumas horas a um dia.
Como tratar: Mude o proxy e adicione o IP a uma lista negra de longo prazo (24 horas). Analise os logs: talvez você esteja scraping de forma muito agressiva ou usando IPs de data center onde são necessários residenciais.
3. Captcha (CAPTCHA) — o site exibe uma verificação "não sou um robô". Isso significa que seu comportamento pareceu suspeito, mas o IP ainda não foi completamente bloqueado.
Como tratar: Existem três opções:
- Mudar de proxy — a forma mais simples. O IP atual é adicionado à lista negra por 6-12 horas.
- Solução automática de captcha — uso de serviços como 2Captcha, Anti-Captcha, CapSolver. Eles custam de $1 a $3 por 1000 soluções.
- Solução manual — se o scraping não for crítico em termos de tempo, você pode enviar o captcha para solução manual por um operador.
4. Cloudflare Challenge — verificação JavaScript que exige a execução de código no navegador. Uma biblioteca HTTP comum não passará por essa verificação.
Como tratar: Use um navegador headless (Puppeteer, Playwright, Selenium) com configuração de fingerprint real. Bibliotecas como puppeteer-extra-plugin-stealth ajudam a contornar a detecção do modo headless.
Integração de serviços de solução de captcha
Se você decidiu resolver captcha automaticamente, aqui está um exemplo de integração com o popular serviço 2Captcha:
// Python usando a biblioteca 2captcha-python
from twocaptcha import TwoCaptcha
import requests
solver = TwoCaptcha('YOUR_API_KEY')
try:
# Resolvendo reCAPTCHA v2
result = solver.recaptcha(
sitekey='6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-',
url='https://hh.ru/search/vacancy',
proxy={
'type': 'HTTPS',
'uri': 'login:password@ip:port'
}
)
# Obtendo o token da solução
captcha_token = result['code']
# Enviando solicitação com o token
response = requests.post(
'https://hh.ru/search/vacancy',
data={
'g-recaptcha-response': captcha_token,
# outros parâmetros do formulário
},
proxies={
'http': 'http://login:password@ip:port',
'https': 'http://login:password@ip:port'
}
)
except Exception as e:
print(f'Erro ao resolver captcha: {e}')
Resolver um captcha leva de 10 a 30 segundos e custa cerca de $0.001-0.003. Para scraping em larga escala, isso pode ser caro, então é melhor configurar o scraping para que o captcha apareça o menos possível.
Sistema de monitoramento e alertas
Para o funcionamento estável do parser, é importante configurar o monitoramento de bloqueios e alertas automáticos:
O que monitorar:
- Percentual de solicitações bem-sucedidas — se cair abaixo de 90%, é necessário verificar os proxies e as configurações
- Número de captchas por hora — se mais de 5-10, você está scraping de forma muito agressiva
- Velocidade média de resposta dos proxies — se aumentar abruptamente, pode ser que os proxies estejam sobrecarregados
- Número de erros 429/403 — indicador da qualidade dos proxies e da correção das configurações
- Lista de IPs bloqueados — se o mesmo IP está sendo bloqueado constantemente, exclua-o do pool
Configure o envio de notificações (Telegram, email, Slack) se o percentual de solicitações bem-sucedidas cair abaixo de um valor limite. Isso permitirá reagir rapidamente a problemas e não perder tempo de scraping.
Configuração de proxies em ferramentas populares de scraping
Vamos discutir como configurar proxies nas ferramentas mais populares para scraping de job boards: Python (requests, Scrapy), Node.js (axios, Puppeteer) e soluções prontas.
Python: requests e Scrapy
Python é a linguagem mais popular para scraping devido às bibliotecas requests, BeautifulSoup e Scrapy.
Exemplo com a biblioteca requests:
import requests
import random
import time
# Lista de proxies (obtenha do provedor)
PROXIES = [
'http://user:[email protected]:8080',
'http://user:[email protected]:8080',
'http://user:[email protected]:8080'
]
# Lista de User-Agent para rotação
USER_AGENTS = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'
]
def parse_vacancy(url):
proxy = random.choice(PROXIES)
user_agent = random.choice(USER_AGENTS)
headers = {
'User-Agent': user_agent,
'Accept': 'text/html,application/xhtml+xml',
'Accept-Language': 'pt-BR,pt;q=0.9,en;q=0.8',
'Accept-Encoding': 'gzip, deflate, br',
'Connection': 'keep-alive'
}
proxies = {
'http': proxy,
'https': proxy
}
try:
response = requests.get(
url,
headers=headers,
proxies=proxies,
timeout=30
)
if response.status_code == 200:
return response.text
elif response.status_code == 429:
print(f'Limite de taxa para {proxy}, trocando proxy')
# Remove o proxy da lista temporariamente
return None
else:
print(f'Erro {response.status_code}')
return None
except Exception as e:
print(f'Erro na solicitação: {e}')
return None
# Uso
for i in range(100):
html = parse_vacancy('https://hh.ru/vacancy/123456')
if html:
# Processamento dos dados
pass
# Delay aleatório
time.sleep(random.uniform(4, 8))
Exemplo de configuração do Scrapy:
# settings.py
# Ativando suporte a proxies
DOWNLOADER_MIDDLEWARES = {
'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 110,
'scrapy_rotating_proxies.middlewares.RotatingProxyMiddleware': 610,
'scrapy_rotating_proxies.middlewares.BanDetectionMiddleware': 620,
}
# Lista de proxies
ROTATING_PROXY_LIST = [
'http://user:[email protected]:8080',
'http://user:[email protected]:8080',
'http://user:[email protected]:8080'
]
# Detecção automática de banimento
ROTATING_PROXY_BAN_POLICY = 'scrapy_rotating_proxies.policy.BanDetectionPolicy'
# Delay entre solicitações
DOWNLOAD_DELAY = 5
RANDOMIZE_DOWNLOAD_DELAY = True # Delay aleatório ±50%
# Rotação de User-Agent
DOWNLOADER_MIDDLEWARES.update({
'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
'scrapy_user_agents.middlewares.RandomUserAgentMiddleware': 400,
})
# Máximo de solicitações simultâneas
CONCURRENT_REQUESTS = 4
CONCURRENT_REQUESTS_PER_DOMAIN = 1
Node.js: Puppeteer com proxies
Para scraping de sites com JavaScript (LinkedIn, Indeed), é necessário um navegador headless. Puppeteer é a solução mais popular para Node.js.
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
// Plugin para contornar a detecção de navegador headless
puppeteer.use(StealthPlugin());
async function parseWithProxy() {
const proxy = 'http://user:[email protected]:8080';
const browser = await puppeteer.launch({
headless: true,
args: [
`--proxy-server=${proxy}`,
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-blink-features=AutomationControlled'
]
});
const page = await browser.newPage();
// Configurando um User-Agent real
await page.setUserAgent(
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
);
// Configurando o restante do código...