DocumentaçãoNavegador e CrawlAgent BrowserOtimização de custos

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:

  1. Interceptação de recursos: Reduza o consumo de tráfego interceptando requisições de recursos desnecessárias.
  2. 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.
  3. Simular dispositivos móveis: Use configurações de dispositivos móveis para obter versões mais leves da página.
  4. 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 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 no lugar⭐ Seguro
mediaArquivos de mídiaArquivos de vídeo/áudioO conteúdo de mídia não pode ser reproduzido⭐ Seguro
manifestWeb App ManifestArquivo de configuração de PWAA funcionalidade de PWA pode ser afetada⭐ Seguro
prefetchRecursos de pré-busca<link rel="prefetch">Impacto mínimo na página⭐ Seguro
stylesheetFolha de estilos CSSArquivos CSS externosOs estilos da página são perdidos, pode afetar o layout⚠️ Cuidado
websocketWebSocketConexão de comunicação em tempo realFuncionalidade em tempo real desativada⚠️ Cuidado
eventsourceServer-Sent EventsDados enviados pelo servidorFuncionalidade de push desativada⚠️ Cuidado
preflightRequisição preflight de CORSRequisição OPTIONSRequisições de origem cruzada falham⚠️ Cuidado
scriptScripts JavaScriptArquivos JS externosFuncionalidade dinâmica desativada, SPA pode não renderizar❌ Evitar
xhrRequisições XHRRequisições de dados AJAXImpossível obter dados dinâmicos❌ Evitar
fetchRequisições FetchRequisições AJAX modernasImpossível obter dados dinâmicos❌ Evitar
documentDocumento principalA própria página HTMLA 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

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

Padrões de URL Interceptáveis Comuns

Padrão de URLDescriçãoExemploRecomendação
Serviços de publicidadeDomínios de redes de anúnciosad.doubleclick.net, googleadservices.com⭐ Seguro
Serviços de análiseScripts de estatísticas 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 grandesArquivos grandes de vídeo, áudioExtensões como .mp4, .webm, .mp3⭐ Seguro
Serviços de fontesServiços de fontes onlinefonts.googleapis.com, use.typekit.net⭐ Seguro
Recursos de CDNCDN de recursos estáticoscdn.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

  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 móveis geralmente carregam imagens menores
  3. CSS e JavaScript simplificados: As versões móveis geralmente usam estilos e scripts simplificados
  4. Redução de anúncios e conteúdo não essencial: As versões móveis frequentemente removem algumas funcionalidades não essenciais
  5. 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árioTráfego Usado (MB)Taxa de Economia
Não otimizado6.03—
Otimizado0.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.