全部文章

网页抓取与自动化

Puppeteer、Playwright、curl 抓取技巧与反爬应对

目录 20 节

网页抓取与自动化

这页适合作为“网页数据抓取与浏览器自动化”的起步说明。真正重要的不是会不会抓,而是先判断目标站点是静态页面、动态渲染页面,还是明确提供了 API;选错抓取方式,后面维护成本会很高。

先按页面类型选方案

  • 静态 HTML:优先 curl + cheerio / BeautifulSoup
  • 强依赖前端渲染:优先 Playwright
  • 需要浏览器交互和脚本执行Playwright / Puppeteer
  • 有官方 API:优先直接用 API,不要硬抓页面

只要能直接用 API,就尽量别走页面抓取。

curl 基础

# GET 请求
curl https://api.example.com/data

# 带 Header
curl -H "Authorization: Bearer token" https://api.example.com

# POST JSON
curl -X POST https://api.example.com/data \
  -H "Content-Type: application/json" \
  -d '{"key": "value"}'

# 下载文件
curl -O https://example.com/file.zip
curl -o output.zip https://example.com/file.zip

# 跟随重定向
curl -L https://example.com

# 查看响应头
curl -I https://example.com

Node.js 抓取

cheerio(静态页面)

pnpm add cheerio
import * as cheerio from "cheerio";

const html = await fetch("https://example.com").then((r) => r.text());
const $ = cheerio.load(html);

$("h2").each((i, el) => {
  console.log($(el).text());
});

const links = $("a")
  .map((i, el) => $(el).attr("href"))
  .get();

Playwright(动态页面)

pnpm add playwright
npx playwright install chromium
import { chromium } from "playwright";

const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto("https://example.com");

// 等待元素
await page.waitForSelector(".content");

// 获取文本
const title = await page.textContent("h1");

// 截图
await page.screenshot({ path: "screenshot.png", fullPage: true });

// 点击与输入
await page.fill("#search", "keyword");
await page.click("button[type=submit]");

await browser.close();

Puppeteer

pnpm add puppeteer
import puppeteer from "puppeteer";

const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
await page.goto("https://example.com", { waitUntil: "networkidle2" });

const data = await page.evaluate(() => {
  return Array.from(document.querySelectorAll(".item")).map((el) => ({
    title: el.querySelector("h3")?.textContent,
    link: el.querySelector("a")?.href,
  }));
});

await browser.close();

Python 抓取

requests + BeautifulSoup

import requests
from bs4 import BeautifulSoup

resp = requests.get("https://example.com")
soup = BeautifulSoup(resp.text, "html.parser")

for item in soup.select(".item"):
    title = item.select_one("h3").text
    link = item.select_one("a")["href"]
    print(title, link)

实用技巧

请求头伪装

const headers = {
  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
  Accept: "text/html,application/xhtml+xml",
  "Accept-Language": "zh-CN,zh;q=0.9",
};

请求间隔

function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

for (const url of urls) {
  await fetch(url);
  await sleep(1000 + Math.random() * 2000); // 1-3 秒随机间隔
}

代理

import { HttpsProxyAgent } from "https-proxy-agent";

const agent = new HttpsProxyAgent("http://proxy:8080");
const resp = await fetch(url, { agent });

推荐执行顺序

一个稳妥的抓取流程通常是:

  1. 先观察目标页面是静态还是动态
  2. 再检查网络请求里是否已有可用 API
  3. 确定数据结构后,再决定用轻量抓取还是浏览器自动化
  4. 最后补节流、重试和异常处理

如果一开始就上完整浏览器自动化,很多简单任务会被做得过重。

常见问题

本地能抓,跑一会就失败

高频原因通常包括:

  • 请求频率太高
  • 缺少必要 Header 或 Cookie
  • 目标站点风控升级
  • 依赖页面结构,DOM 一改就失效

Playwright 很重,跑得慢

这很正常。只有在必须执行 JS、等待登录态、模拟点击时,才值得用浏览器自动化;静态页面优先轻量方案。

数据抓到了,但不好维护

建议尽早做这几件事:

  • 把选择器集中管理
  • 记录页面结构假设
  • 为关键字段做兜底和空值判断
  • 降低对文案和顺序的强依赖

风险提醒

  • 尊重目标站点条款、robots 和访问频率限制
  • 不要抓取超出授权范围的内容
  • 涉及账号、Cookie、验证码、付费内容时尤其要谨慎

延伸阅读

参考链接

阅读建议
  • - 先读标题和摘要,再结合目录决定从哪个章节开始精读。
  • - 看到具体命令、配置或步骤时,尽量在自己的环境里同步验证。
  • - 工具类页面更适合和同类替代方案一起比较,不建议只看单一推荐。
适合谁看
  • - 希望把零散经验整理成长期可复用工作流的人
  • - 希望快速筛选在线服务并减少信息噪音的人
  • - 希望阅读时顺手建立自己的操作清单或收藏体系的人
执行前检查
  • - 先浏览标题、摘要和目录,带着问题阅读会更高效
  • - 确认要上传的数据是否敏感,并优先使用临时数据做首次验证
  • - 如果页面里提到相关文档,尽量一起打开对照,效果通常更完整
同类内容
← 上一篇图片与视频处理