Scraping BrowserGuiasOtimizando o custo

Otimizando o Custo

Introdução

Ao usar o Puppeteer para raspagem de dados, o consumo de tráfego é uma consideração importante. Especialmente quando se usa serviços proxy, os custos de tráfego podem aumentar significativamente. Para otimizar o uso de tráfego, podemos adotar as seguintes estratégias:

  1. Interceptação de recursos: Reduza o consumo de tráfego interceptando solicitações de recursos desnecessários.
  2. Interceptação de URL de solicitação: Reduza ainda mais o tráfego interceptando solicitações específicas com base nas características da URL.
  3. Simular dispositivos móveis: Use configurações de dispositivos móveis para obter versões de página mais leves.
  4. Otimização abrangente: Combine os métodos acima para obter 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 todas as solicitações de rede iniciadas pelo navegador e decidir continuar (request.continue()), encerrar (request.abort()) ou personalizar a resposta (request.respond()).

Este método pode reduzir significativamente o consumo de largura de banda, sendo especialmente adequado para cenários de raspagem, captura de tela e otimização de desempenho.

Tipos de Recursos Interceptáveis e Sugestões

Tipo de RecursoDescriçãoExemploImpacto Após a InterceptaçãoRecomendação
imageRecursos de imagemImagens JPG/PNG/GIF/WebPAs imagens não serão exibidas⭐ Seguro
fontArquivos de fonteFontes TTF/WOFF/WOFF2Fontes padrão do sistema serão usadas⭐ Seguro
mediaArquivos de mídiaArquivos de vídeo/áudioO conteúdo de mídia não poderá ser reproduzido⭐ Seguro
manifestWeb App ManifestArquivo de configuração PWAA funcionalidade PWA pode ser afetada⭐ Seguro
prefetchRecursos de pré-busca<link rel="prefetch">Impacto mínimo na página⭐ Seguro
stylesheetFolha de Estilo CSSArquivos CSS externosOs estilos da página são perdidos, podendo afetar o layout⚠️ Cuidado
websocketWebSocketConexão de comunicação em tempo realFuncionalidade em tempo real desabilitada⚠️ Cuidado
eventsourceEventos enviados pelo servidorDados push do servidorFuncionalidade push desabilitada⚠️ Cuidado
preflightSolicitação de pré-voo CORSSolicitação OPTIONSSolicitações de origem cruzada falham⚠️ Cuidado
scriptScripts JavaScriptArquivos JS externosFuncionalidade dinâmica desabilitada, SPA pode não renderizar❌ Evite
xhrSolicitações XHRSolicitações de dados AJAXImpossível obter dados dinâmicos❌ Evite
fetchSolicitações FetchSolicitações AJAX modernasImpossível obter dados dinâmicos❌ Evite
documentDocumento principalPrópria página HTMLPágina não pode carregar❌ Evite

Explicação do Nível de Recomendação:

  • Seguro: A interceptação quase não tem impacto na raspagem 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 solicitações de origem cruzada; requer julgamento comercial.
  • Evite: Alta probabilidade de causar falha na renderização ou obtenção de dados normalmente em sites SPA/dinâmicos, a menos que você tenha certeza absoluta de que não precisa desses recursos.

Exemplo de Código 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({
    session_name: 'sdk_test',
    session_ttl: 180,
    proxy_country: 'ANY',
    session_recording: 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 Solicitação

Além de interceptar por tipo de recurso, um controle de interceptação mais granular pode ser realizado com base nas características da URL. Isso é particularmente eficaz para bloquear anúncios, scripts de análise e outras solicitações de terceiros desnecessárias.

Estratégias de Interceptação de URL

  1. Interceptar por domínio: Bloquear todas as solicitações de um domínio específico
  2. Interceptar por caminho: Bloquear solicitações de um caminho específico
  3. Interceptar por tipo de arquivo: Bloquear arquivos com extensões específicas
  4. Interceptar por palavra-chave: Bloquear solicitações cujas URLs contenham palavras-chave específicas

Padrões de URL Comumente Interceptáveis

Padrão de URLDescriçãoExemploRecomendação
Serviços de publicidadeDomínios de rede de publicidadead.doubleclick.net, googleadservices.com⭐ Seguro
Serviços de análiseScripts de estatística e análisegoogle-analytics.com, hotjar.com⭐ Seguro
Plugins de mídia socialBotões de compartilhamento social, etc.platform.twitter.com, connect.facebook.net⭐ Seguro
Pixels de rastreamentoPixels que rastreiam o comportamento do usuárioURLs contendo pixel, beacon, tracker⭐ Seguro
Arquivos de mídia grandesVídeos, arquivos de áudio grandesExtensões como .mp4, .webm, .mp3⭐ Seguro
Serviços de fonteServiços de fonte onlinefonts.googleapis.com, use.typekit.net⭐ Seguro
Recursos CDNCDN de recursos estáticoscdn.jsdelivr.net, unpkg.com⚠️ Cuidado

Exemplo de Código 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({
    session_name: 'sdk_test',
    session_ttl: 180,
    proxy_country: 'ANY',
    session_recording: 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 para dispositivos móveis geralmente fornecem conteúdo de página mais leve.

Vantagens da Simulação de Dispositivos Móveis

  1. Versões de página mais leves: Muitos sites fornecem conteúdo mais conciso para dispositivos móveis
  2. Recursos de imagem menores: As versões para dispositivos móveis geralmente carregam imagens menores
  3. CSS e JavaScript simplificados: As versões para dispositivos móveis geralmente usam estilos e scripts simplificados
  4. Anúncios e conteúdo não essencial reduzidos: As versões para dispositivos móveis geralmente removem algumas funcionalidades não essenciais
  5. Resposta adaptativa: 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 para 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);

Exemplo de Código 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({
    session_name: 'sdk_test',
    session_ttl: 180,
    proxy_country: 'ANY',
    session_recording: 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({
    session_name: 'sdk_test',
    session_ttl: 180,
    proxy_country: 'ANY',
    session_recording: 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

Tentamos remover o código otimizado do exemplo abrangente para comparar o tráfego antes e depois da otimização. Aqui está o exemplo de código 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({
    session_name: 'sdk_test',
    session_ttl: 180,
    proxy_country: 'ANY',
    session_recording: 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árioTráfego Usado (MB)Taxa de Economia
Não Otimizado6.03
Otimizado0.81≈ 86.6 %

Combinando os esquemas de otimização acima, o consumo de tráfego proxy pode ser significativamente reduzido, a eficiência de raspagem pode ser melhorada e garantir que o conteúdo principal necessário seja obtido.