优化无头浏览器流量:使用Puppeteer进行高效数据抓取的成本降低策略

概述

使用 Puppeteer 进行数据抓取时,流量消耗是一个重要考虑因素。特别是在使用代理服务时,流量成本可能显著增加。为了优化流量使用,我们可以采用以下策略:

  1. 资源拦截:通过拦截不必要的资源请求来减少流量消耗。
  2. 请求 URL 拦截:根据 URL 特征进一步拦截特定请求以减少流量。
  3. 模拟移动设备:使用移动设备配置获取更轻的页面版本。
  4. 综合优化:结合上述方法以实现最佳效果。

优化方案 1:资源拦截

资源拦截介绍

在 Puppeteer 中,page.setRequestInterception(true) 可以捕捉浏览器发起的每一个网络请求,并决定 继续 (request.continue())、终止 (request.abort()) 或 自定义响应 (request.respond()).

这种方法可以显著减少带宽消耗,特别适合 爬取截图性能优化 场景。

可拦截的资源类型及建议

资源类型 描述 示例 拦截后的影响 推荐级别
image 图像资源 JPG/PNG/GIF/WebP 图像 图像将无法显示 ⭐ 安全
font 字体文件 TTF/WOFF/WOFF2 字体 将使用系统默认字体 ⭐ 安全
media 媒体文件 视频/音频文件 媒体内容无法播放 ⭐ 安全
manifest Web 应用清单 PWA 配置文件 PWA 功能可能受到影响 ⭐ 安全
prefetch 预取资源 <link rel="prefetch"> 对页面影响很小 ⭐ 安全
stylesheet CSS 样式表 外部 CSS 文件 页面样式丢失,可能影响布局 ⚠️ 注意
websocket WebSocket 实时通信连接 实时功能被禁用 ⚠️ 注意
eventsource 服务器发送事件 服务器推送数据 推送功能被禁用 ⚠️ 注意
preflight CORS 预检请求 OPTIONS 请求 跨域请求失败 ⚠️ 注意
script JavaScript 脚本 外部 JS 文件 动态功能被禁用,SPA 可能无法渲染 ❌ 避免
xhr XHR 请求 AJAX 数据请求 无法获取动态数据 ❌ 避免
fetch Fetch 请求 现代 AJAX 请求 无法获取动态数据 ❌ 避免
document 主文档 HTML 页面本身 页面无法加载 ❌ 避免

推荐级别说明:

  • 安全:拦截对数据抓取或首屏渲染几乎没有影响;建议默认拦截。
  • ⚠️ 注意:可能会破坏样式、实时功能或跨域请求;需要根据具体业务进行判断。
  • 避免:高概率会导致 SPA 或动态网站无法正常渲染或获取数据,除非你非常确定不需要这些资源。

资源拦截示例代码

javascript 复制代码
import puppeteer from 'puppeteer-core';

const scrapelessUrl = 'wss://browser.scrapeless.com/browser?token=your_api_key&session_ttl=180&proxy_country=ANY';

async function scrapeWithResourceBlocking(url) {
    const browser = await puppeteer.connect({
        browserWSEndpoint: scrapelessUrl,
        defaultViewport: null
    });
    const page = await browser.newPage();

    // 启用请求拦截
    await page.setRequestInterception(true);

    // 定义要拦截的资源类型
    const BLOCKED_TYPES = new Set([
        'image',
        'font',
        'media',
        'stylesheet',
    ]);

    // 拦截请求
    page.on('request', (request) => {
        if (BLOCKED_TYPES.has(request.resourceType())) {
            request.abort();
            console.log(`已拦截: ${request.resourceType()} - ${request.url().substring(0, 50)}...`);
        } else {
            request.continue();
        }
    });

    await page.goto(url, {waitUntil: 'domcontentloaded'});

    // 提取数据
    const data = await page.evaluate(() => {
        return {
            title: document.title,
            content: document.body.innerText.substring(0, 1000)
        };
    });

    await browser.close();
    return data;
}

// 使用示例
scrapeWithResourceBlocking('https://www.scrapeless.com')

.then(data => console.log('抓取结果:', data))
    .catch(error => console.error('抓取失败:', error));

优化方案 2:请求 URL 拦截

除了按资源类型拦截之外,还可以根据 URL 特征进行更细粒度的拦截控制。这对于阻止广告、分析脚本以及其他不必要的第三方请求特别有效。

URL 拦截策略

  1. 按域名拦截:阻止来自特定域的所有请求
  2. 按路径拦截:阻止来自特定路径的请求
  3. 按文件类型拦截:阻止具有特定扩展名的文件
  4. 按关键词拦截:阻止其 URL 包含特定关键词的请求

常见可拦截 URL 模式

URL 模式 描述 示例 推荐
广告服务 广告网络域名 ad.doubleclick.net, googleadservices.com ⭐ 安全
分析服务 统计和分析脚本 google-analytics.com, hotjar.com ⭐ 安全
社交媒体插件 社交分享按钮等 platform.twitter.com, connect.facebook.net ⭐ 安全
跟踪像素 跟踪用户行为的像素 包含 pixel, beacon, tracker 的 URL ⭐ 安全
大型媒体文件 大型视频、音频文件 扩展名如 .mp4, .webm, .mp3 ⭐ 安全
字体服务 在线字体服务 fonts.googleapis.com, use.typekit.net ⭐ 安全
CDN 资源 静态资源 CDN cdn.jsdelivr.net, unpkg.com ⚠️ 注意

URL 拦截示例代码

javascript 复制代码
import puppeteer from 'puppeteer-core';

const scrapelessUrl = 'wss://browser.scrapeless.com/browser?token=your_api_key&session_ttl=180&proxy_country=ANY';

async function scrapeWithUrlBlocking(url) {
    const browser = await puppeteer.connect({
        browserWSEndpoint: scrapelessUrl,
        defaultViewport: null
    });
    const page = await browser.newPage();

    // 启用请求拦截
    await page.setRequestInterception(true);

    // 定义要拦截的域名和 URL 模式
    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/',
    ];

    // 拦截请求
    page.on('request', (request) => {
        const url = request.url();

        // 检查域名
        if (BLOCKED_DOMAINS.some(domain => url.includes(domain))) {
            request.abort();
            console.log(`拦截域名: ${url.substring(0, 50)}...`);
            return;
        }

        // 检查路径
        if (BLOCKED_PATHS.some(path => url.includes(path))) {
            request.abort();
            console.log(`拦截路径: ${url.substring(0, 50)}...`);
            return;
        }

        // 允许其他请求
        request.continue();
    });

    await page.goto(url, {waitUntil: 'domcontentloaded'});

    // 提取数据
    const data = await page.evaluate(() => {
        return {
            title: document.title,
            content: document.body.innerText.substring(0, 1000)
        };
    });

    await browser.close();
    return data;
}

// 使用示例
scrapeWithUrlBlocking('https://www.scrapeless.com')
    .then(data => console.log('抓取结果:', data))
    .catch(error => console.error('抓取失败:', error));

优化方案 3:模拟移动设备

模拟移动设备是另一种有效的流量优化策略,因为移动网站通常提供更轻量的页面内容。

移动设备模拟的优势

  1. 更轻量的页面版本:许多网站为移动设备提供更简洁的内容
  2. 更小的图像资源:移动版本通常加载更小的图像
  3. 简化的 CSS 和 JavaScript:移动版本通常使用简化的样式和脚本
  4. 减少广告和非核心内容:移动版本通常移除一些非核心功能
  5. 自适应响应:获取为小屏幕优化的内容布局

移动设备模拟配置

以下是几个常用移动设备的配置参数:

javascript 复制代码
const iPhoneX = {
    viewport: {
        width: 375,
        height: 812,
        deviceScaleFactor: 3,
        isMobile: true,
        hasTouch: true,
        isLandscape: false
    }
};

或者直接使用 puppeteer 的内置方法模拟移动设备

javascript 复制代码
import { KnownDevices } from 'puppeteer-core';
const iPhone = KnownDevices['iPhone 15 Pro'];
javascript 复制代码
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.emulate(iPhone);
javascript 复制代码
const scrapelessUrl = 'wss://browser.scrapeless.com/browser?token=your_api_key&session_ttl=180&proxy_country=ANY';

async function optimizedScraping(url) {
  console.log(`开始优化抓取: ${url}`);

  // 记录流量使用
  let totalBytesUsed = 0;

  const browser = await puppeteer.connect({
    browserWSEndpoint: scrapelessUrl,
    defaultViewport: null
  });

  const page = await browser.newPage();

  // 设置请求拦截
  await page.setRequestInterception(true);

  // 拦截请求
  page.on('request', (request) => {
    request.continue();
  });

  // 监控网络流量
  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'});

  // 模拟滚动以触发延迟加载内容
  await page.evaluate(() => {
    window.scrollBy(0, window.innerHeight);
  });

  await new Promise(resolve => setTimeout(resolve, 1000))

  // 提取数据
  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
      }))
    };
  });

  // 输出流量使用统计
  console.log(`\n流量使用统计:`);
  console.log(`已使用: ${(totalBytesUsed / 1024 / 1024).toFixed(2)} MB`);

  await browser.close();
  return data;
}

// 使用
optimizedScraping('https://www.scrapeless.com')
  .then(data => console.log('抓取完成:', data))
  .catch(error => console.error('抓取失败:', error));

在运行未优化的代码后,我们可以从打印的信息中直观地看到流量差异:

场景 使用流量 (MB) 节省比率
未优化 6.03 ---
优化后 0.81 ≈ 86.6 %

通过结合上述优化方案,可以显著减少代理流量消耗,提高抓取效率,并确保获取所需的核心内容。

相关推荐
l木本I8 小时前
uv 技术详解
人工智能·python·深度学习·机器学习·uv
宁大小白9 小时前
pythonstudy Day31
python·机器学习
江上鹤.1489 小时前
Day34模块和库的导入
python
我爱鸢尾花9 小时前
第十四章聚类方法理论及Python实现
大数据·python·机器学习·数据挖掘·数据分析·聚类
言之。10 小时前
Dropbear远程连接
python
期待のcode10 小时前
Thymeleaf模板引擎
java·html·springboot
dhdjjsjs11 小时前
Day34 PythonStudy
python
一个java开发11 小时前
Dask 配置文件加载机制说明
大数据·python
bj_zhb11 小时前
图片的base64表示
python·llm
飞Link11 小时前
【Django】Django 调用外部 Python 程序的完整指南
后端·python·django·sqlite