在 Puppeteer 中设置轮换代理,避免被封禁

最后更新于 August 10, 2026
Hand-drawn diagram of a Puppeteer-controlled browser rotating requests through multiple proxy nodes
AI 摘要
- 对比 Puppeteer 轮换架构的实战方案,包括按代理重启浏览器、网关托管轮换、隔离浏览器池和浏览器分片。 - 了解代理凭据应该放在哪里、HTTPS CONNECT 如何改变请求路径,以及为什么仅靠页面级认证并不能解决浏览器启动或隧道失败问题。 - 构建具备健康状态感知的选择逻辑:有限重试、冷却时间、按原因分类的失败处理和会话一致性,而不是每次错误后都盲目轮换。 - 通过识别 403、407、429、导航超时、DNS 和 TLS 失败来自哪一层,来排查问题,而不是一上来就改路由。 - 使用生产环境检查清单:可观测性、密钥管理、并发限制、优雅关闭,以及基于策略的失败即停止(fail-closed)行为。

Puppeteer 里常见的一种失败模式是:前几次请求都很顺,后面却开始返回 403 或 429,或者直接超时,甚至跳到验证页面。可很多教程还是把轮换代理讲得像是改两行配置就搞定了。

事实并不是这样。把“加上 --proxy-server 参数”和搭出一个能长期维护的系统,这两者之间差得非常远。这篇指南会讲到浏览器级轮换、带认证的网关、浏览器分片或外部中继、稳定的浏览器配置文件、生产级错误处理,以及什么时候你根本不该自己管代理。

什么是轮换代理?为什么 Puppeteer 需要它?

代理位于你的 Puppeteer 实例和目标网站之间。目标网站看到的是代理出口 IP,而不是你机器的 IP。轮换代理会在一组出口 IP 之间切换——有时按请求切换,有时按会话切换——这样你的流量就不会看起来像同一个客户端一直猛刷同一台服务器。

Puppeteer 尤其需要这一点,因为无头 Chrome 用单个 IP 连续发出几百个请求,正是反爬系统最容易识别的模式。Cloudflare 官方文档 也提到,它会同时运行多层检测——规则判断、JavaScript 指纹检查、机器学习模型以及行为异常检测。轮换 IP 只能解决其中一层问题。只是其中一层。

常见代理类型有三种,不能混在一起看:

  • 数据中心代理——便宜、速度快,来自云服务或机房。目标站点很容易识别,因为 ASN(网络段)一看就是数据中心,不像住宅网络。
  • 住宅代理——通过真实家庭宽带 ISP 转发,看起来更像普通家庭上网。速度更慢、价格更高,但更不容易被怀疑。
  • 移动代理——来自运营商网络,通常最贵,但当你确实需要“移动网络身份”时很有用。

只看 ASN 分类的话,住宅出口通常比数据中心出口更不显眼,但这两类都不是免封的。没有什么通用的“检测率”:最终效果取决于目标站点、出口信誉、地理位置、会话历史、浏览器配置文件和请求行为。

还有一个很容易混淆的区别:自己维护的静态代理列表(你负责管理代理池、选择下一个 IP、处理失败)和 backconnect/网关代理(你只访问一个入口,代理商在后台自动切换出口)并不是一回事。两者都能用,只是复杂度落在不同地方。

为什么要在 Puppeteer 里设置轮换代理?常见应用场景

老实说,你可能一直到真的需要轮换时才会开始用它,而一旦需要,就会非常需要。

使用场景为什么需要轮换
商品目录价格监控同一 IP 反复请求目录页,容易积累限流和信誉信号
线索补全 / 联系人数据采集同一 IP 反复访问个人资料,行为更像爬虫而不是浏览,容易被行为引擎标记
SERP 抓取搜索引擎对基于 IP 的限流和验证码拦截最严格
竞品情报分析连续多天反复抓同一域名,会形成与你的 IP 和 Cookie 历史绑定的指纹
内容聚合单页价值低、页面量大——这正是反爬最敏感的流量形态

不存在那种“Amazon 在第 51 次请求时就封你”的固定数字。网站不会公开统一阈值,而且控制策略会随着端点、账号状态、ASN 信誉和流量形态而变化。最稳妥的做法是先从最低、且经过授权的请求频率开始,同时校验内容和状态码;只有在实际行为与目标站点政策都支持时,再逐步增加轮换。

Puppeteer 的三种代理轮换策略:你到底该用哪一种?

Three Puppeteer proxy strategies compared: browser relaunch, rotating gateway, and browser sharding

这部分通常是很多教程直接跳过,或者只给你看最粗糙的版本。实际上,这里有三种粒度,选错了要么白白浪费时间,要么把简单任务搞得过于复杂。

轮换策略粒度需要重启浏览器吗?复杂度最适合
按浏览器轮换(--proxy-server每个浏览器实例 1 个代理需要简单、低频率抓取
网关托管轮换(proxy-chain + backconnect 入口)由服务商的会话策略决定不需要带认证的轮换网关
浏览器分片或外部中继每个浏览器分片或中继规则 1 个代理不存在单进程内切换需要可控并发和细粒度路由

在你做选择之前,先提醒一句:Puppeteer 官方网络拦截文档 明确说明,setRequestInterception 并不是一个可以“按请求无缝切换代理”的开关——每个被拦截的请求都会暂停,直到你显式继续、响应或中止它。真正的按请求代理路由,通常意味着通过本地可编程网关(例如 proxy-chain)转发请求,而不是在拦截处理器里直接改代理。方法 3 下面会讲到这一点,先记住它。

如何在 Puppeteer 中设置轮换代理:分步指南

难度: 中级
所需时间: 三种方法全部完成约 30–45 分钟
你需要准备: Node.js 18+、npm、代理列表或服务商账号(格式:protocol://user:pass@host:port),以及 puppeteerproxy-chainpuppeteer-extra 这些包

开始前的准备工作

先安装核心依赖:

npm install puppeteer proxy-chain puppeteer-extra puppeteer-extra-plugin-stealth

从代理服务商拿到代理列表(如果不是随便测试,优先选住宅代理),或者至少准备几条测试代理,先验证代码能不能跑通,再把真实请求量放上去。凭据要放到环境变量里——不要硬编码,也不要把它们直接写进最终会出现在日志里的 URL。

方法 1:使用 --proxy-server 做按浏览器轮换

这是大家最常从这里起步的方案,也确实有它的道理——可预测。Puppeteer 的 LaunchOptions 说明了 args 可以用来传递 Chrome 命令行参数,而 --proxy-server 本身就是 Chromium 原生参数。

import puppeteer from 'puppeteer';

const proxyPool = [
  'http://proxy1.example:8080',
  'http://proxy2.example:8080',
  'http://proxy3.example:8080',
];

let proxyIndex = 0;

async function scrapeWithRotation(url) {
  const proxy = proxyPool[proxyIndex % proxyPool.length];
  proxyIndex++;

  const browser = await puppeteer.launch({
    headless: true,
    args: [`--proxy-server=${proxy}`],
  });

  const page = await browser.newPage();

  // 如果代理需要认证,这一步必须在任何跳转前执行
  await page.authenticate({
    username: process.env.PROXY_USER,
    password: process.env.PROXY_PASS,
  });

  await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30_000 });
  const content = await page.content();

  await browser.close(); // 切换代理前先关闭浏览器
  return content;
}

注意,page.authenticate() 会在后台悄悄启用请求拦截,这是 Puppeteer 文档里明确写到的——这会带来一点性能开销,提前知道总比你之后排查“为什么感觉变慢了”要好。

预期结果: 每次调用都会启动一个绑定到不同代理的新浏览器。想轮换就只能关闭再重启——这部分启动开销绕不过去。对于抓 50 个页面来说,光浏览器启动时间就会明显比另外两种方法慢。

适用场景: 低并发脚本、一次性抓取,或者你更看重调试简单性而不是速度的情况。

方法 2:用 proxy-chain 连接带认证的轮换网关

Chrome 不能直接接受 user:pass@host 这种把凭据嵌在代理 URL 里的写法。proxy-chain(由 Apify 维护)通过启动一个本地匿名代理来解决认证问题,这个本地代理再转发到你的上游认证代理。如果上游是服务商提供的轮换或 backconnect 网关,那么服务商会根据会话策略在这个入口后面自动切换出口 IP。proxy-chain 本身不会给现有的 Puppeteer 页面逐个分配不同代理。

import puppeteer from 'puppeteer';
import { anonymizeProxy, closeAnonymizedProxy } from 'proxy-chain';

async function scrapeThroughGateway(upstreamProxyUrl, targetUrl) {
  const localProxy = await anonymizeProxy(upstreamProxyUrl);
  let browser;

  try {
    browser = await puppeteer.launch({
      headless: true,
      args: [`--proxy-server=${localProxy}`],
    });
    const page = await browser.newPage();
    await page.goto(targetUrl, { waitUntil: 'domcontentloaded' });
    return await page.content();
  } finally {
    if (browser) await browser.close();
    await closeAnonymizedProxy(localProxy, true); // 一定要清理
  }
}

这个 finally 不是装饰用的——本地代理服务如果没关,会漏端口。我还遇到过爬虫跑了一整晚,结果把可用文件描述符耗光的情况,原因就是匿名代理没有关闭。proxy-chain 还能返回具体的错误码(例如 593 表示 DNS 问题、594 表示连接被拒绝、597 表示认证失败),这对故障分类非常有用——后面还会提到。

适用场景: 带认证的住宅/数据中心网关,且轮换由服务商入口或会话参数控制。如果你需要多个固定代理身份并发使用,就应该用多个浏览器进程(浏览器分片)或者专门的外部中继;原生 Puppeteer 并没有支持按页面设置代理的接口。

方法 3:按请求路由必须依赖外部中继

这是粒度最高的一种方式——理论上,页面上的每个图片、脚本和 API 请求都可以走不同出口。实际操作里,这也是最脆弱、文档最少的一种,因为 Puppeteer 的请求拦截本意是筛选和修改请求,而不是按请求更换网络传输路径。

import puppeteer from 'puppeteer';

async function inspectRequests(url) {
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();

  await page.setRequestInterception(true);

  page.on('request', async (request) => {
    // 实际上,真正的按请求代理切换需要通过本地中继(proxy-chain)转发,
    // 而不是在飞行中切换浏览器的网络传输——Chrome 本身不支持这样做。
    // 大多数生产环境会把这个处理器用于过滤/中止资源类型,
    // 再配合浏览器分片或网关方案。
    if (['image', 'font', 'stylesheet'].includes(request.resourceType())) {
      request.abort();
    } else {
      request.continue();
    }
  });

  await page.goto(url, { waitUntil: 'networkidle2' });
  await browser.close();
}

说实话: Puppeteer 里并没有通过 setRequestInterception() 来真正按请求切换 IP 的能力。如果你真的需要这个粒度,就应该把 Chrome 通过一个可编程的外部中继转发,或者直接用基于代理会话构建的爬取框架。对大多数项目来说,每个浏览器分片用一个代理,或者用服务商托管的轮换网关,更容易运维,也更容易审计。

完整的反检测栈:只靠轮换代理并不能保证不被封

一个很常见的抱怨是:“我都用了代理,还是被封。”IP 只是现代反爬系统会评估的多个信号之一;如果只轮换 IP,其他特征却始终不一致,反而可能制造出更明显的异常。比如浏览器声称自己是 Windows Chrome,但客户端提示、时区或语言环境却对不上,这就很可疑。

第一层:轮换住宅代理

前面已经讲过——住宅出口通常比数据中心出口更合理,但没有统一的最小代理池规模。代理池大小应该根据实际请求量、会话时长、冷却时间和服务商复用策略来定,而不是随便拍一个数字。

第二层:用 Stealth 插件隐藏无头 Chrome 特征

puppeteer-extra-plugin-stealth 会修补一批常见的无头痕迹:navigator.webdriver、WebGL vendor 字符串、缺失的 Chrome runtime 对象,以及一些其他 CDP 泄漏。它确实很实用,但 项目自己的 README 也说得很直接:这是一场猫鼠游戏,想做到完全不被识破,大概率不现实。把它当作基础层,而不是保险承诺。

第三层:稳定的浏览器配置文件和合理的请求节奏

User-Agent 字符串必须和浏览器报告的其他信息彼此一致。Chrome 的 User-Agent Client Hints 会暴露结构化的平台数据,所以你手写的 user-agent 可能和真实平台互相矛盾。最好直接使用随附 Chrome 版本提供的 user-agent,在同一会话里保持 viewport、语言和时区稳定,并且控制请求节奏,不要每个页面都伪造一套新指纹。

下面是把这三层放在一起的一套启动配置:

import puppeteer from 'puppeteer-extra';
import StealthPlugin from 'puppeteer-extra-plugin-stealth';
import { anonymizeProxy, closeAnonymizedProxy } from 'proxy-chain';

puppeteer.use(StealthPlugin());

function boundedDelay(minMs = 800, maxMs = 1800) {
  return new Promise((r) => setTimeout(r, minMs + Math.random() * (maxMs - minMs)));
}

async function stableProfileScrape(targetUrl, upstreamProxy) {
  const localProxy = await anonymizeProxy(upstreamProxy);
  let browser;

  try {
    browser = await puppeteer.launch({
      headless: true,
      args: [`--proxy-server=${localProxy}`, '--lang=en-US'],
    });
    const page = await browser.newPage();
    await page.setViewport({ width: 1366, height: 768 });
    await boundedDelay();
    await page.goto(targetUrl, { waitUntil: 'domcontentloaded' });
    return await page.content();
  } finally {
    if (browser) await browser.close();
    await closeAnonymizedProxy(localProxy, true);
  }
}

这就是很多竞品教程不会展示的部分——代理、隐身和指纹随机化放在同一处,直接可复制后再按需改造。

适合生产环境的错误处理与代理健康检查

Proxy pool health state machine for 403, 407, 429, timeout, cooldown, and quarantine handling

很多教程一旦“能跑通”就结束了。真实抓取远没有这么顺利——代理会挂、凭据会过期、目标站点会在跑到一半时限流,而这些都不是靠“但愿如此”就能解决的。

带指数退避和随机抖动的重试逻辑

function backoffMs(attempt, base = 1000, cap = 30_000) {
  const exponential = Math.min(cap, base * 2 ** attempt);
  return Math.floor(exponential * (0.5 + Math.random() * 0.5)); // 抖动可避免惊群
}

async function withRetry(fn, maxRetries = 4) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await fn();
    } catch (err) {
      if (attempt === maxRetries) throw err;
      const delay = backoffMs(attempt);
      console.warn(`第 ${attempt + 1} 次尝试失败:${err.message}。将在 ${delay}ms 后重试`);
      await new Promise((r) => setTimeout(r, delay));
    }
  }
}

自动拉黑失败代理

const proxyStats = new Map(); // proxyUrl -> { success, failure }

function recordResult(proxyUrl, success) {
  const stats = proxyStats.get(proxyUrl) || { success: 0, failure: 0 };
  success ? stats.success++ : stats.failure++;
  proxyStats.set(proxyUrl, stats);
}

function isHealthy(proxyUrl) {
  const stats = proxyStats.get(proxyUrl);
  if (!stats) return true;
  const total = stats.success + stats.failure;
  if (total < 5) return true; // 数据还不够
  return stats.failure / total < 0.5; // 失败率超过 50% 就拉黑
}

function getHealthyProxy(pool) {
  const healthy = pool.filter(isHealthy);
  if (healthy.length === 0) throw new Error('代理池里没有可用代理了');
  return healthy[Math.floor(Math.random() * healthy.length)];
}

要记录的是错误类型,而不只是成功/失败——407(凭据错误)和 429(限流)需要完全不同的处理方式。如果一个代理是认证失败,你却还在快速重试,那只是白白浪费时间;正确的修复方式是检查凭据,而不是更快地轮换。

Puppeteer 中常见轮换代理错误的排查

错误可能原因解决办法
ERR_PROXY_CONNECTION_FAILED代理宕机或无法连接从代理池移除,改用下一个代理重试
407 Proxy Authentication Required凭据错误或不支持该认证方式检查 page.authenticate() 的账号密码;URL 内嵌认证请用 proxy-chain
TimeoutError代理太慢或目标站点在阻断增加超时时间;换住宅代理
403 ForbiddenIP 或指纹被标记更换代理 + 开启 stealth + 随机化 UA
ERR_TUNNEL_CONNECTION_FAILEDHTTPS 隧道异常检查是否支持 CONNECT 方法;尝试使用 proxy-chain 本地隧道

还有几点值得单独说明,没法整整齐齐塞进表格里:200 状态码并不等于成功。很多软封锁会返回一个完整的 HTML 页面——比如登录墙或验证页——但状态码还是正常,所以你要验证的是实际内容,而不只是响应状态。卡住的时候,Puppeteer 的调试指南 建议把 headless 设为 false,加上 slowMo,并设置 NODE_DEBUG="puppeteer:*" 来获取更详细的协议日志——只是要注意,这些日志可能包含敏感请求数据,所以不要在生产凭据环境里长期开启。

自己管理代理轮换 vs 代理网关 vs AI 提取 API

维度自己维护的列表轮换Backconnect 网关(Bright Data、Oxylabs、Decodo)AI 提取 API(Thunderbit)
成本(低流量)低到中按 GB 计费,中到高低(有免费层,之后按单位计费)
可靠性取决于你的健康检查高(由服务商托管)高(托管基础设施)
反检测能力自己实现部分具备(仅 IP 轮换)内置
结构化输出否(原始 HTML)否(原始 HTML)是(按 schema 返回 JSON)
部署时间数小时几分钟几分钟
控制力完全控制受服务商 API 限制受 schema 模型限制

按当前厂商价格(查看于 2026-08-07),可以大致看出网关方案的成本曲线:Bright Data 的住宅代理定价 提供按量付费和套餐方案,促销可能会变化;Oxylabs 显示 5 GB 时为 $6/GB、1 TB 时为 $2.50/GB;Decodo(原 Smartproxy)则显示 3 GB 时为 $3.75/GB、100 GB 时为 $2.75/GB,并提供 $4/GB 的按量付费方案。Decodo 还宣传有 1.15 亿+ IP 池和 99.92% 成功率——这是厂商声明,不是独立复现的测试结果。

我实际用的决策逻辑是:你需要和页面交互吗?比如点击、滚动、填写表单、保持登录会话?那就用 Puppeteer 加代理。你只是要页面上已经存在的数据?那在自己搭一整套要长期维护的代理基础设施之前,先看看提取 API。

当 Puppeteer + 代理过于复杂时:直接用 API 提取结构化数据

有那么一次,大概是我第三次为一个“只需要把商品价格放进表格”的项目重建代理健康检查系统时,我突然意识到:这些基础设施解决的是“从页面拿到原始 HTML”这个问题——而这其实并不是开发者真正的目标。真正的目标是结构化数据。HTML 只是中间那个麻烦格式。

Thunderbit 的 Open API 把提取当成核心操作,而不是浏览器自动化的副作用。POST /extract 接收一个 URL 和 JSON Schema,并返回匹配的结构化数据——在后端处理 JS 渲染、反爬措施和验证码,而不是让你自己去接 stealth 插件和代理池:

curl -X POST https://openapi.thunderbit.com/openapi/v1/extract \
  -H "Authorization: Bearer $THUNDERBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/product",
    "schema": {
      "type": "object",
      "properties": {
        "name": {"type": "string"},
        "price": {"type": "number"}
      },
      "required": ["name", "price"]
    }
  }'

如果你只想要干净的 Markdown,而不是严格 schema,也可以用 POST /distill。另外还支持批量提取:一次调用就能把同一套 schema 跑到多个 URL 上。根据 Thunderbit 当前 API 定价,Distill 每页 1 个单位,Extract 每页 20 个单位;免费层包含 600 次一次性单位,足够你在正式投入前先把流程验证一遍。

对于在 Claude、Cursor 或其他兼容 MCP 的客户端里工作的开发者,Thunderbit 还提供 thunderbit_extractthunderbit_distill 这两个 MCP 工具,让代理在任务进行中自己判断什么时候需要从页面拉数据,而不用单独写一套抓取步骤。我会先看最新的 API 参考文档,再去配置 MCP,因为工具名称和参数会随着文档版本变化。

维度Puppeteer + 轮换代理Thunderbit API
配置复杂度高——代理池、轮换逻辑、隐身、重试都要自己做低——一个带 JSON Schema 的 API 调用即可
反爬处理手动实现内置
输出原始 HTML(需要解析)与 schema 匹配的结构化 JSON
维护成本高——选择器会失效,代理会老化
最适合自定义自动化、登录流程、小众交互大规模数据提取

也得公平地说一句 DIY 路线:如果你的场景涉及登录账号、点击多步流程,或者需要在一个会话里持续保持状态,那提取 API 通常替代不了它——Thunderbit 自己的 FAQ 也明确说明,目前 API 还不支持交互式登录流程。这种情况下,Puppeteer 加代理依然更合适。但如果你的任务只是“把一堆公开网页里的数据抓出来,放进我定义好的 schema”,那自己搭代理轮换栈,实际上是在解决一个比你真正需求更难的问题。对于想完全跳过代码的团队,Thunderbit Chrome Extension 提供了同样的 AI 驱动提取能力,而且是点选式界面——如果你在比较 无代码网页抓取 和完整开发方案,这个值得看看。

结论与要点总结

在 Puppeteer 里设置轮换代理,并不是一种单一技巧。按浏览器轮换最简单,也最隔离。带认证的 backconnect 网关可以在一个浏览器级入口后自动切换出口。更细粒度的按请求或并发身份,则需要浏览器分片或外部中继;单靠请求拦截并不能改变 Chrome 的网络路由。

不过,如果没有其他配套,这些都意义不大。代理解决的是 IP 信誉问题;stealth 插件和指纹一致性解决的是浏览器信号问题;抖动和节奏控制解决的是行为问题。少了任何一层,你都还是会被封,只是原因不同。

如果你准备自己动手,先从 proxy-chain 仓库 和上面的代码块开始——它们比大多数付费课程更能帮到你。如果你更想跳过代理管理,直接拿到结构化数据,那么在花一个周末搭健康检查基础设施之前,先花十分钟看看 Thunderbit 的 API 文档 值不值得。两条路都合理——关键是你要解决自己真正遇到的问题,而不是教程默认假设你遇到的问题。想更全面了解 AI 正在如何改变这个领域,可以继续阅读我们关于 AI 网页抓取 以及它与传统方法对比的深入分析。

常见问题解答

在 Puppeteer 里应该多久轮换一次代理?

这取决于目标站点的限流有多严格。对于反爬很强的网站,最好按页面或按会话轮换。对于限制较松的网站,按会话轮换,甚至整个抓取过程都用一个稳定 IP,也完全可以。没有统一数值——把 403、429 和超时当作你该更激进轮换的信号,而不是固定请求次数。

Puppeteer 抓取可以用免费代理吗?

技术上可以,但除了快速测试,我不建议。免费代理列表通常速度慢、不稳定,而且经常已经被你要抓的网站拉黑。只要是生产场景,付费服务商的住宅代理或托管网关都更值得。

puppeteer-extra-plugin-stealth 能对付所有反爬系统吗?

不能,插件文档 也明确这么说。它能减少一些常见的无头 Chrome 特征,但目标站点仍然可以检查网络信誉、TLS 特征、Cookie、客户端提示和行为模式。把它当成一层兼容性补丁,而不是万无一失的解决方案。

proxy-chain 和 Puppeteer 里的 --proxy-server 有什么区别?

--proxy-server 是 Chromium 原生启动参数,它会把一个代理端点分配给整个浏览器实例,而且 Chrome 不支持在那里直接嵌入代理凭据。proxy-chain 会先在本地创建一个匿名隧道,再转发到带认证的上游代理。真正的轮换来自重新启动并切换上游、使用服务商托管的 backconnect 网关,或者自己额外搭建的中继,而不是 proxy-chain 给单个 Puppeteer 页面分配代理。

轮换代理就足以彻底避免被封吗?

不够——这也是最常见的误解。像 Cloudflare 的 bot management 这样的现代反爬系统,会把 IP 信誉和浏览器指纹、行为模式以及会话历史一起关联分析。代理只解决 IP 信誉这一项;你仍然需要 stealth 配置、一致的指纹和合理的时间间隔,才能避免在其他信号上被标记。

了解更多

Ke
Ke
Thunderbit 首席技术官 | 高级数据科学家与机器学习专家 Ke Shen 拥有近十年的机器学习和数据科学经验,毕业于哥伦比亚大学,曾任 Walmart Labs 高级数据科学家。他在 Python、R、Java 和统计学方面拥有深厚且备受同行认可的专业能力,并分享如何将复杂的 AI 算法从理论落地到生产级架构的实战经验。
Topics
Puppeteer 代理轮换代理轮换浏览器自动化
目录
Thunderbit · AI 网页数据代理

1 次点击 中从任何页面提取数据

受到超过 250,000+ 用户的信赖
提供免费计划
使用 AI 提取数据
轻松将数据传输到 Google Sheets、Airtable 或 Notion
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week