Otimizando Custos
Introdução
Ao usar o Puppeteer para coleta de dados, o consumo de tráfego é uma consideração importante. Especialmente ao usar serviços de proxy, os custos de tráfego podem aumentar significativamente. Para otimizar o uso de tráfego, podemos adotar as seguintes estratégias:
- Interceptação de recursos: Reduza o consumo de tráfego interceptando requisições de recursos desnecessárias.
- Interceptação de URL de requisição: Reduza ainda mais o tráfego interceptando requisições específicas com base nas características da URL.
- Simular dispositivos móveis: Use configurações de dispositivos móveis para obter versões mais leves da página.
- Otimização abrangente: Combine os métodos acima para alcançar os melhores resultados.
Esquema de Otimização 1: Interceptação de Recursos
Introdução à Interceptação de Recursos
No Puppeteer, page.setRequestInterception(true) pode capturar cada requisição de rede iniciada pelo navegador e decidir por continuar (request.continue()), encerrar (request.abort()) ou personalizar a resposta (request.respond()).
Esse método pode reduzir significativamente o consumo de largura de banda, sendo especialmente adequado para cenários de crawling, captura de tela e otimização de desempenho.
Tipos de Recursos Interceptáveis e Sugestões
| Tipo de Recurso | Descrição | Exemplo | Impacto Após a Interceptação | Recomendação |
|---|---|---|---|---|
image | Recursos de imagem | Imagens JPG/PNG/GIF/WebP | As imagens não serão exibidas | ⭐ Seguro |
font | Arquivos de fonte | Fontes TTF/WOFF/WOFF2 | Fontes padrão do sistema serão usadas no lugar | ⭐ Seguro |
media | Arquivos de mídia | Arquivos de vídeo/áudio | O conteúdo de mídia não pode ser reproduzido | ⭐ Seguro |
manifest | Web App Manifest | Arquivo de configuração de PWA | A funcionalidade de PWA pode ser afetada | ⭐ Seguro |
prefetch | Recursos de pré-busca | <link rel="prefetch"> | Impacto mínimo na página | ⭐ Seguro |
stylesheet | Folha de estilos CSS | Arquivos CSS externos | Os estilos da página são perdidos, pode afetar o layout | ⚠️ Cuidado |
websocket | WebSocket | Conexão de comunicação em tempo real | Funcionalidade em tempo real desativada | ⚠️ Cuidado |
eventsource | Server-Sent Events | Dados enviados pelo servidor | Funcionalidade de push desativada | ⚠️ Cuidado |
preflight | Requisição preflight de CORS | Requisição OPTIONS | Requisições de origem cruzada falham | ⚠️ Cuidado |
script | Scripts JavaScript | Arquivos JS externos | Funcionalidade dinâmica desativada, SPA pode não renderizar | ❌ Evitar |
xhr | Requisições XHR | Requisições de dados AJAX | Impossível obter dados dinâmicos | ❌ Evitar |
fetch | Requisições Fetch | Requisições AJAX modernas | Impossível obter dados dinâmicos | ❌ Evitar |
document | Documento principal | A própria página HTML | A página não pode carregar | ❌ Evitar |
Explicação dos Níveis de Recomendação:
- ⭐ Seguro: A interceptação quase não tem impacto na coleta de dados ou na renderização da primeira tela; recomenda-se bloquear por padrão.
- ⚠️ Cuidado: Pode quebrar estilos, funções em tempo real ou requisições de origem cruzada; requer avaliação de negócio.
- ❌ Evitar: Alta probabilidade de fazer com que sites SPA/dinâmicos não renderizem ou não obtenham dados normalmente, a menos que você tenha certeza absoluta de que não precisa desses recursos.
Código de Exemplo de Interceptação de Recursos
import { Scrapeless } from '@scrapeless-ai/sdk';
import puppeteer from 'puppeteer-core';
const client = new Scrapeless({ apiKey: 'API Key' });
const { browserWSEndpoint } = client.browser.create({
sessionName: 'sdk_test',
sessionTTL: 180,
proxyCountry: 'ANY',
sessionRecording: true,
fingerprint,
});
async function scrapeWithResourceBlocking(url) {
const browser = await puppeteer.connect({
browserWSEndpoint,
defaultViewport: null
});
const page = await browser.newPage();
// Enable request interception
await page.setRequestInterception(true);
// Define resource types to block
const BLOCKED_TYPES = new Set([
'image',
'font',
'media',
'stylesheet',
]);
// Intercept requests
page.on('request', (request) => {
if (BLOCKED_TYPES.has(request.resourceType())) {
request.abort();
console.log(`Blocked: ${request.resourceType()} - ${request.url().substring(0, 50)}...`);
} else {
request.continue();
}
});
await page.goto(url, {waitUntil: 'domcontentloaded'});
// Extract data
const data = await page.evaluate(() => {
return {
title: document.title,
content: document.body.innerText.substring(0, 1000)
};
});
await browser.close();
return data;
}
// Usage
scrapeWithResourceBlocking('https://www.scrapeless.com')
.then(data => console.log('Scraping result:', data))
.catch(error => console.error('Scraping failed:', error));Esquema de Otimização 2: Interceptação de URL de Requisição
Além de interceptar por tipo de recurso, é possível realizar um controle de interceptação mais granular com base nas características da URL. Isso é particularmente eficaz para bloquear anúncios, scripts de análise e outras requisições de terceiros desnecessárias.
Estratégias de Interceptação de URL
- Interceptar por domínio: Bloqueie todas as requisições de um domínio específico
- Interceptar por caminho: Bloqueie requisições de um caminho específico
- Interceptar por tipo de arquivo: Bloqueie arquivos com extensões específicas
- Interceptar por palavra-chave: Bloqueie requisições cujas URLs contenham palavras-chave específicas
Padrões de URL Interceptáveis Comuns
| Padrão de URL | Descrição | Exemplo | Recomendação |
|---|---|---|---|
| Serviços de publicidade | Domínios de redes de anúncios | ad.doubleclick.net, googleadservices.com | ⭐ Seguro |
| Serviços de análise | Scripts de estatísticas e análise | google-analytics.com, hotjar.com | ⭐ Seguro |
| Plugins de mídia social | Botões de compartilhamento social, etc. | platform.twitter.com, connect.facebook.net | ⭐ Seguro |
| Pixels de rastreamento | Pixels que rastreiam o comportamento do usuário | URLs contendo pixel, beacon, tracker | ⭐ Seguro |
| Arquivos de mídia grandes | Arquivos grandes de vídeo, áudio | Extensões como .mp4, .webm, .mp3 | ⭐ Seguro |
| Serviços de fontes | Serviços de fontes online | fonts.googleapis.com, use.typekit.net | ⭐ Seguro |
| Recursos de CDN | CDN de recursos estáticos | cdn.jsdelivr.net, unpkg.com | ⚠️ Cuidado |
Código de Exemplo de Interceptação de URL
import puppeteer from 'puppeteer-core';
import { Scrapeless } from '@scrapeless-ai/sdk';
import puppeteer from 'puppeteer-core';
const client = new Scrapeless({ apiKey: 'API Key' });
const { browserWSEndpoint } = client.browser.create({
sessionName: 'sdk_test',
sessionTTL: 180,
proxyCountry: 'ANY',
sessionRecording: true,
fingerprint,
});
async function scrapeWithUrlBlocking(url) {
const browser = await puppeteer.connect({
browserWSEndpoint,
defaultViewport: null
});
const page = await browser.newPage();
// Enable request interception
await page.setRequestInterception(true);
// Define domains and URL patterns to block
const BLOCKED_DOMAINS = [
'google-analytics.com',
'googletagmanager.com',
'doubleclick.net',
'facebook.net',
'twitter.com',
'linkedin.com',
'adservice.google.com',
];
const BLOCKED_PATHS = [
'/ads/',
'/analytics/',
'/pixel/',
'/tracking/',
'/stats/',
];
// Intercept requests
page.on('request', (request) => {
const url = request.url();
// Check domain
if (BLOCKED_DOMAINS.some(domain => url.includes(domain))) {
request.abort();
console.log(`Blocked domain: ${url.substring(0, 50)}...`);
return;
}
// Check path
if (BLOCKED_PATHS.some(path => url.includes(path))) {
request.abort();
console.log(`Blocked path: ${url.substring(0, 50)}...`);
return;
}
// Allow other requests
request.continue();
});
await page.goto(url, {waitUntil: 'domcontentloaded'});
// Extract data
const data = await page.evaluate(() => {
return {
title: document.title,
content: document.body.innerText.substring(0, 1000)
};
});
await browser.close();
return data;
}
// Usage
scrapeWithUrlBlocking('https://www.scrapeless.com')
.then(data => console.log('Scraping result:', data))
.catch(error => console.error('Scraping failed:', error));Esquema de Otimização 3: Simular Dispositivos Móveis
Simular dispositivos móveis é outra estratégia eficaz de otimização de tráfego, porque os sites móveis geralmente fornecem conteúdo de página mais leve.
Vantagens da Simulação de Dispositivos Móveis
- Versões de página mais leves: Muitos sites fornecem conteúdo mais conciso para dispositivos móveis
- Recursos de imagem menores: As versões móveis geralmente carregam imagens menores
- CSS e JavaScript simplificados: As versões móveis geralmente usam estilos e scripts simplificados
- Redução de anúncios e conteúdo não essencial: As versões móveis frequentemente removem algumas funcionalidades não essenciais
- Resposta adaptável: Obtenha layouts de conteúdo otimizados para telas pequenas
Configuração de Simulação de Dispositivos Móveis
Aqui estão os parâmetros de configuração de vários dispositivos móveis comumente usados:
const iPhoneX = {
viewport: {
width: 375,
height: 812,
deviceScaleFactor: 3,
isMobile: true,
hasTouch: true,
isLandscape: false
}
};Ou use diretamente os métodos integrados do puppeteer para simular dispositivos móveis
import { KnownDevices } from 'puppeteer-core';
const iPhone = KnownDevices['iPhone 15 Pro'];
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.emulate(iPhone);Código de Exemplo de Simulação de Dispositivos Móveis
import puppeteer from 'puppeteer-core';
import { Scrapeless } from '@scrapeless-ai/sdk';
const client = new Scrapeless({ apiKey: 'API Key' });
const { browserWSEndpoint } = client.browser.create({
sessionName: 'sdk_test',
sessionTTL: 180,
proxyCountry: 'ANY',
sessionRecording: true,
fingerprint,
});
async function scrapeWithMobileEmulation(url) {
const browser = await puppeteer.connect({
browserWSEndpoint,
defaultViewport: null
});
const page = await browser.newPage();
// Set mobile device simulation
const iPhone = KnownDevices['iPhone 15 Pro'];
await page.emulate(iPhone);
await page.goto(url, {waitUntil: 'domcontentloaded'});
// Extract data
const data = await page.evaluate(() => {
return {
title: document.title,
content: document.body.innerText.substring(0, 1000)
};
});
await browser.close();
return data;
}
// Usage
scrapeWithMobileEmulation('https://www.scrapeless.com')
.then(data => console.log('Scraping result:', data))
.catch(error => console.error('Scraping failed:', error));Exemplo de Otimização Abrangente
Aqui está um exemplo abrangente combinando todos os esquemas de otimização:
import puppeteer, {KnownDevices} from 'puppeteer-core';
import { Scrapeless } from '@scrapeless-ai/sdk';
const client = new Scrapeless({ apiKey: 'API Key' });
const { browserWSEndpoint } = client.browser.create({
sessionName: 'sdk_test',
sessionTTL: 180,
proxyCountry: 'ANY',
sessionRecording: true,
fingerprint,
});
async function optimizedScraping(url) {
console.log(`Starting optimized scraping: ${url}`);
// Record traffic usage
let totalBytesUsed = 0;
const browser = await puppeteer.connect({
browserWSEndpoint,
defaultViewport: null
});
const page = await browser.newPage();
// Set mobile device simulation
const iPhone = KnownDevices['iPhone 15 Pro'];
await page.emulate(iPhone);
// Set request interception
await page.setRequestInterception(true);
// Define resource types to block
const BLOCKED_TYPES = [
'image',
'media',
'font'
];
// Define domains to block
const BLOCKED_DOMAINS = [
'google-analytics.com',
'googletagmanager.com',
'facebook.net',
'doubleclick.net',
'adservice.google.com'
];
// Define URL paths to block
const BLOCKED_PATHS = [
'/ads/',
'/analytics/',
'/tracking/'
];
// Intercept requests
page.on('request', (request) => {
const url = request.url();
const resourceType = request.resourceType();
// Check resource type
if (BLOCKED_TYPES.includes(resourceType)) {
console.log(`Blocked resource type: ${resourceType} - ${url.substring(0, 50)}...`);
request.abort();
return;
}
// Check domain
if (BLOCKED_DOMAINS.some(domain => url.includes(domain))) {
console.log(`Blocked domain: ${url.substring(0, 50)}...`);
request.abort();
return;
}
// Check path
if (BLOCKED_PATHS.some(path => url.includes(path))) {
console.log(`Blocked path: ${url.substring(0, 50)}...`);
request.abort();
return;
}
// Allow other requests
request.continue();
});
// Monitor network traffic
page.on('response', async (response) => {
const headers = response.headers();
const contentLength = headers['content-length'] ? parseInt(headers['content-length'], 10) : 0;
totalBytesUsed += contentLength;
});
await page.goto(url, {waitUntil: 'domcontentloaded'});
// Simulate scrolling to trigger lazy-loading content
await page.evaluate(() => {
window.scrollBy(0, window.innerHeight);
});
await new Promise(resolve => setTimeout(resolve, 1000))
// Extract data
const data = await page.evaluate(() => {
return {
title: document.title,
content: document.body.innerText.substring(0, 1000),
links: Array.from(document.querySelectorAll('a')).slice(0, 10).map(a => ({
text: a.innerText,
href: a.href
}))
};
});
// Output traffic usage statistics
console.log(`\nTraffic Usage Statistics:`);
console.log(`Used: ${(totalBytesUsed / 1024 / 1024).toFixed(2)} MB`);
await browser.close();
return data;
}
// Usage
optimizedScraping('https://www.scrapeless.com')
.then(data => console.log('Scraping complete:', data))
.catch(error => console.error('Scraping failed:', error));Comparação de Otimização
Vamos tentar remover o código otimizado do exemplo abrangente para comparar o tráfego antes e depois da otimização. Aqui está o código de exemplo não otimizado:
import puppeteer from 'puppeteer-core';
import { Scrapeless } from '@scrapeless-ai/sdk';
const client = new Scrapeless({ apiKey: 'API Key' });
const { browserWSEndpoint } = client.browser.create({
sessionName: 'sdk_test',
sessionTTL: 180,
proxyCountry: 'ANY',
sessionRecording: true,
fingerprint,
});
async function unoptimizedScraping(url) {
console.log(`Starting unoptimized scraping: ${url}`);
// Record traffic usage
let totalBytesUsed = 0;
const browser = await puppeteer.connect({
browserWSEndpoint,
defaultViewport: null
});
const page = await browser.newPage();
// Set request interception
await page.setRequestInterception(true);
// Intercept requests
page.on('request', (request) => {
request.continue();
});
// Monitor network traffic
page.on('response', async (response) => {
const headers = response.headers();
const contentLength = headers['content-length'] ? parseInt(headers['content-length'], 10) : 0;
totalBytesUsed += contentLength;
});
await page.goto(url, {waitUntil: 'domcontentloaded'});
// Simulate scrolling to trigger lazy-loading content
await page.evaluate(() => {
window.scrollBy(0, window.innerHeight);
});
await new Promise(resolve => setTimeout(resolve, 1000))
// Extract data
const data = await page.evaluate(() => {
return {
title: document.title,
content: document.body.innerText.substring(0, 1000),
links: Array.from(document.querySelectorAll('a')).slice(0, 10).map(a => ({
text: a.innerText,
href: a.href
}))
};
});
// Output traffic usage statistics
console.log(`\nTraffic Usage Statistics:`);
console.log(`Used: ${(totalBytesUsed / 1024 / 1024).toFixed(2)} MB`);
await browser.close();
return data;
}
// Usage
unoptimizedScraping('https://www.scrapeless.com')
.then(data => console.log('Scraping complete:', data))
.catch(error => console.error('Scraping failed:', error));Após executar o código não otimizado, podemos ver a diferença de tráfego de forma muito intuitiva a partir das informações impressas:
| Cenário | Tráfego Usado (MB) | Taxa de Economia |
|---|---|---|
| Não otimizado | 6.03 | — |
| Otimizado | 0.81 | ≈ 86.6 % |
Ao combinar os esquemas de otimização acima, o consumo de tráfego de proxy pode ser reduzido significativamente, a eficiência da coleta pode ser aprimorada e garante-se que o conteúdo central necessário seja obtido.