cURL 是从终端获取网页的最快方式。它支持 HTTP、HTTPS、FTP 等协议,几乎在你会接触到的每台机器上都已预装,而且它只做好一件事:发送请求并返回原始响应。这使得使用 cURL 进行网页抓取成为一个自然的首选工具,无论你是手动探测端点、在编写真正代码之前先验证请求,还是将单行命令接入 shell 脚本。

本指南是一个实用的命令行演练。你将获取一个页面,将其保存到磁盘,跟随重定向,设置请求头和 User-Agent,发送 cookie,POST 表单和 JSON 数据,通过代理路由,以及读取 HTTP 状态码。然后我们来看裸 cURL 在哪里遇到瓶颈(JavaScript 渲染页面和反爬拦截),以及如何通过 Crawlbase Crawling APISmart AI Proxy 在不离开终端的情况下获取完整 HTML。

为什么要用 cURL 来抓取

大多数抓取最终会用 Python 或 Node 完成,那为什么从命令行开始?因为 cURL 是从"我想知道这个 URL 返回什么"到得到答案的最短路径。无需安装任何东西,无需编写脚本,无需管理依赖。你输入一条命令,就能看到服务器发送的确切字节,包括请求头。当抓取程序出错时,在 cURL 中重现请求是找出问题在于你的代码还是服务器的最快方式。

cURL 也具有可组合性。因为它将原始输出写入 stdout,你可以将其直接管道传输到解析器、grep 或文件,并在几行 bash 中对 URL 列表进行循环。对于小型任务,这个模式通常就是你所需要的全部。对于较大的任务,cURL 仍然是你在扩大规模之前用来调试请求的工具。

使用 GET 请求获取页面

最简单的抓取就是一次裸 GET 请求。将 cURL 指向 URL,它就会将响应体打印到终端。

bash
curl https://example.com

默认情况下 cURL 发起 GET 请求,无需添加任何参数。HTML 会涌入你的终端,快速查看没问题,但对于更大的内容就不适合了。接下来几步是关于控制这个输出:保存它,减少噪音,以及读取响应体周围的元数据。关于请求方面的深入介绍,请参阅如何使用 cURL 发送 GET 请求

将响应保存到文件

两个参数用于保存。使用 -o 写入你选择的文件名,或使用 -O(大写 O)保留 URL 中的远程文件名。

bash
# Write the body to a named file
curl -o page.html https://example.com

# Keep the remote filename (saves as report.pdf)
curl -O https://example.com/files/report.pdf

保存到磁盘是任何批量抓取的基础:一次获取,之后解析,避免在迭代提取逻辑时反复请求服务器。它还保留了一份原始副本,当页面标记在你下方变化时,你可以进行差异比较。

使用 -L 跟随重定向

默认情况下 cURL 不跟随重定向。如果 URL 返回 301 或 302,你得到的是重定向响应本身,而不是它指向的页面,这是抓取结果为空的经典原因。-L 参数告诉 cURL 跟随 Location 请求头到最终目标。

bash
curl -L https://example.com/old-path

大多数生产站点将 HTTP 重定向到 HTTPS,规范化末尾斜杠,或移动页面,因此 -L 是你几乎总想要加上的参数。如果你需要检查重定向链而不是盲目跟随,去掉 -L 并直接读取状态行和 Location 请求头。

设置 User-Agent 和其他请求头

cURL 以类似 curl/8.4.0 的 User-Agent 自我标识,许多站点会立即将其标记为非浏览器。发送真实的 User-Agent 是你可以设置的单个最高价值的请求头。使用 -H 添加任何请求头,或使用专用的 -A 参数设置 User-Agent。

bash
# Set a browser-like User-Agent with -A
curl -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" https://example.com

# Add multiple headers with repeated -H flags
curl https://example.com \
  -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
  -H "Accept-Language: en-US,en;q=0.9" \
  -H "Referer: https://www.google.com/"

真实的请求头让你的请求看起来像浏览器而不是脚本。合理的默认集包括当前的 User-Agent、AcceptAccept-Language 组合,有时还有 Referer。关于哪些请求头重要以及为什么,完整说明请参阅如何使用 cURL 发送 HTTP 请求头

某些页面在返回内容之前需要会话:同意 cookie、地区选择或已登录状态。cURL 用两个参数处理 cookie。使用 -b 发送 cookie,使用 -c 将服务器设置的 cookie 保存到文件(cookie jar)中,以便后续请求可以重用。

bash
# Send a cookie inline
curl -b "consent=1; region=us" https://example.com

# First request: save cookies the server sets into a jar
curl -c cookies.txt https://example.com/start

# Second request: replay the saved cookies
curl -b cookies.txt https://example.com/dashboard

保存再重放的模式让两步流程可以从命令行工作:先访问入口页面收集 cookie,然后将其带入你实际想要的页面。你可以在一次请求中组合 -b-c,在会话演进时同时加载和更新 jar。

POST 表单和 JSON 数据

抓取并不总是 GET。搜索表单、过滤器和 API 经常期待 POST 请求。-d 参数发送数据并隐式将方法切换为 POST。默认情况下它发送表单编码数据;设置 Content-Type: application/json 来发送 JSON 体。

bash
# Form-encoded POST (application/x-www-form-urlencoded)
curl -d "query=laptops&page=2" https://example.com/search

# JSON POST: set the method and content type explicitly
curl -X POST https://example.com/api/search \
  -H "Content-Type: application/json" \
  -d '{"query": "laptops", "page": 2}'

对于表单数据,用 & 分隔字段,就像浏览器一样。对于 JSON,将请求体包裹在单引号中,以免 shell 破坏双引号,并始终发送匹配的 Content-Type,否则服务器可能拒绝或错误解读负载。直接像这样访问 JSON API,当端点可用时,通常比抓取渲染后的 HTML 更简洁。

通过代理路由 cURL

从单个 IP 大量抓取会导致该 IP 被速率限制或封锁。通过代理路由会在你的请求前放置一个不同的地址。-x 参数设置代理,可选的 user:pass@ 凭证格式。

bash
# Plain HTTP proxy
curl -x http://proxy.example.com:8080 https://example.com

# Authenticated proxy
curl -x http://user:[email protected]:8080 https://example.com

单个静态代理只是将问题转移到一个新 IP 上。让真实抓取保持活跃的是跨多个地址的轮换,这样没有单一地址会触发限制。将 cURL 指向代理的完整机制,包括 SOCKS 和轮换端点,在如何在 cURL 中使用代理中有详细介绍。

静默、详细模式和读取状态码

在脚本中通常希望 cURL 保持安静,但当出错时需要看到一切。-s 参数静默进度条;-v 转储完整的请求和响应,包括所有请求头,这在调试拦截时非常有价值。要只读取 HTTP 状态码,使用写出模板。

bash
# Silent: no progress meter, just the body
curl -s https://example.com -o page.html

# Verbose: see the full request/response exchange
curl -v https://example.com

# Print only the HTTP status code, discard the body
curl -s -o /dev/null -w "%{http_code}\n" https://example.com

最后那条命令是个实用工具:它丢弃响应体,只打印状态码,为脚本提供一个干净的分支信号。200 意味着继续;403 或 429 意味着你正在被挑战或限速,应该回退或改变策略。读取状态码是你区分健康运行和被封锁运行的方式。

将 cURL 管道传输到解析器

cURL 负责获取,不负责解析。Unix 的答案是将其输出管道传输到能解析的工具。对于快速字段抓取,管道传输到 grep 或小型 Python 单行命令;对于真正的 HTML 查询,像 htmlq(命令行 CSS 选择器)这样的工具难以超越。

bash
# Grab the <title> with grep
curl -s https://example.com | grep -o '<title>[^<]*</title>'

# Parse properly with htmlq (CSS selectors)
curl -s https://example.com | htmlq 'h1' --text

# Hand the HTML to Python for structured extraction
curl -s https://example.com | python3 -c \
  "import sys; from bs4 import BeautifulSoup; \
print(BeautifulSoup(sys.stdin.read(), 'html.parser').title.text)"

grep 进行正则表达式匹配对一次性字段提取没问题,但对真实标记很脆弱;一旦结构有嵌套,就要使用 HTML 感知的解析器。Python 管道在你的提取超出单个选择器时自然扩展为完整的 BeautifulSoup 脚本。

在 bash 中循环遍历 URL 列表

一个 URL 是测试;抓取是一个列表。一个简短的 bash 循环从文件读取 URL,获取每一个,检查状态,并保存好的。在请求之间控制节奏,避免对服务器造成冲击。

bash
while read url; do
  slug=$(echo "$url" | md5sum | cut -c1-8)
  code=$(curl -s -L -o "out_$slug.html" -w "%{http_code}" "$url")
  echo "$code  $url"
  sleep 2
done < urls.txt

这个模式涵盖了令人惊讶的广泛场景:一个 URL 文件,每个逐一获取,跟随重定向,记录状态,以稳定名称保存输出,以及两秒的请求间隔。根据目标的容忍度调整 sleep,六行代码就得到了一个礼貌、可重启的爬取程序。

裸 cURL 遇到瓶颈的地方

cURL 是 HTTP 客户端,不是浏览器。这个区别正是它在现代抓取中停止工作的全部原因,体现在两个方面。

它无法运行 JavaScript。 cURL 获取服务器发送的原始 HTML,仅此而已。在客户端渲染的站点上(大多数 React、Vue 和 Angular 应用),初始 HTML 几乎是一个空壳;真实内容由在浏览器中运行的脚本绘制。cURL 从不运行这些脚本,因此你得到的是骨架,而没有数据。没有任何参数能修复这个问题,因为没有 JavaScript 引擎可以开启。

它会被封锁。 即使在服务端渲染的页面上,反爬系统也会读取请求:数据中心 IP、缺失或默认的 User-Agent、没有类似浏览器的请求头集,以及不匹配真实浏览器的 TLS 指纹。裸 cURL 在大多数这些检查上失败,因此会遭遇 403、CAPTCHA 或静默的诱饵页面。你可以用请求头和代理来掩盖一些问题,但对于严密防御的目标,这是一场消耗战。更广泛的方案在如何在不被封锁的情况下抓取网站中有介绍。

双重问题

对现代站点进行有效的抓取需要同时满足两个条件:实际渲染页面的浏览器,以及站点认为是真实访客的 IP。cURL 两者都不提供。你可以自行组合无头浏览器加轮换住宅代理池,但保持该技术栈健康才是大部分工作所在。下一节将两者折叠进单次 cURL 调用。

使用 Crawling API 获取完整 HTML

在继续使用 cURL 的同时解决渲染和封锁问题,最干净的方式是从命令行调用 Crawlbase Crawling API。你传入你的 token 和目标 URL;API 在受信住宅 IP 后获取页面并返回 HTML。添加 &javascript=true,它会首先在真实浏览器中渲染页面,这样客户端内容就出现在你获取的结果中。

bash
# Static fetch through the Crawling API
curl "https://api.crawlbase.com/?token=YOUR_TOKEN&url=https://example.com"

# JavaScript-rendered fetch for client-side pages
curl "https://api.crawlbase.com/?token=YOUR_JS_TOKEN&javascript=true&url=https://example.com"

你想要抓取的 URL 放在 url 参数中,如果它包含自己的查询字符串,应该进行 URL 编码。静态页面使用你的普通 token,渲染页面使用带 javascript=true 的 JavaScript token。由于响应只是 stdout 上的 HTML,之前所有的管道和解析技巧仍然适用:将其重定向到文件,管道传输到 htmlq,或交给 Python 解析器。你保留 cURL 工作流,并将渲染和 IP 问题转移出去。

Crawlbase Crawling API

裸 cURL 会被封锁且无法运行 JavaScript。Crawling API 接受你的 token 和一个 URL,在轮换住宅 IP 后获取页面,可选地在真实浏览器中渲染,并将完整 HTML 返回到 stdout,直接嵌入你现有的 cURL 管道和循环。在免费额度上开始,保持相同的命令行工作流。

通过 Smart AI Proxy 路由 cURL

如果你更想保留自己的请求逻辑,只替换网络路径,Smart AI Proxy(也称为 AI Proxy)为你提供单一代理端点后的轮换住宅 IP。它是你已熟悉的 -x 参数的直接替代,因此你现有的 cURL 命令几乎不需要改变。

bash
curl -x http://YOUR_TOKEN:@smartproxy.crawlbase.com:8012 -k \
  https://example.com

这里你的 token 是代理用户名(密码留空),通过该端点的每个请求都会自动在住宅池中轮换。-k 参数告诉 cURL 接受代理的 TLS 拦截。当你的抓取程序已经围绕 cURL 或库的代理支持构建,而你只需要 IP 轮换时,而不是完整的服务端渲染时,这是正确的选择。对于客户端渲染的页面,优先使用带 javascript=true 的 Crawling API。

回顾

核心要点

  • cURL 是最快的获取和调试工具。curl URL 打印响应;-o/-O 保存,-L 跟随重定向,-s/-v 控制噪音。
  • 请求头和 cookie 让你看起来像浏览器。-A-H 设置真实的 User-Agent,使用 -b/-c 在会话中发送和存储 cookie。
  • POST 和代理涵盖其余基础内容。 -d 发送表单或 JSON 数据(配合正确的 Content-Type),-x 通过代理路由。
  • 管道和循环用于扩展。 将 cURL 输出传输到 grephtmlq 或 Python,并在 URL 列表上用状态检查和节奏控制包装 bash 循环。
  • 裸 cURL 无法渲染 JS 且会被封锁。 调用 Crawling API(对渲染页面添加 javascript=true)或通过 Smart AI Proxy 路由,以在保留 cURL 工作流的同时获取完整 HTML。

常见问题

cURL 可以用于网页抓取吗?

可以。cURL 发送 HTTP 请求并返回原始响应,你可以将其保存到文件或管道传输到 grep、htmlq 或 Python 脚本等解析器。它对于静态、服务端渲染的页面以及调试请求非常出色。其局限性在于它无法运行 JavaScript 且容易被反爬系统封锁,因此对于客户端渲染或受保护的站点,你需要配合渲染和代理服务使用。

为什么 cURL 返回空页面或不完整的页面?

通常是两个原因之一。要么站点是客户端渲染的,真实内容由 cURL 从不运行的 JavaScript 绘制,你只得到了 HTML 外壳;要么站点检测到非浏览器请求并提供了一个拦截或诱饵页面。用 -w "%{http_code}" 检查状态码:200 但没有数据指向 JavaScript 渲染问题,而 403 或 429 指向封锁问题。

如何在 cURL 中设置 User-Agent?

使用带有类似浏览器字符串的 -A 参数,例如 curl -A "Mozilla/5.0 (...)" https://example.com,或用 -H "User-Agent: ..." 将其设置为请求头。默认的 curl/x.y.z 标识符是请求不是浏览器的直接提示,因此当页面封锁你时,真实的 User-Agent 是第一个要修复的请求头。

如何使用 cURL 发送 POST 数据?

使用 -d,它会发送数据并自动将方法切换为 POST。默认情况下发送表单编码数据(-d "a=1&b=2")。对于 JSON,添加 -H "Content-Type: application/json",并将请求体作为单引号 JSON 字符串传递,以免 shell 破坏引号。

如何在 cURL 中使用代理?

使用 -x 参数:curl -x http://host:port https://example.com,对于需要认证的代理在主机前添加 user:pass@。但单个静态代理只改变你的 IP 一次;要大量抓取,你需要跨多个 IP 的轮换,Smart AI Proxy 等服务在单一端点后提供这种能力。

如何使用 cURL 抓取 JavaScript 密集的页面?

单独使用 cURL 无法做到,因为 cURL 没有 JavaScript 引擎,从不执行渲染内容的脚本。实际的解决方案是从 cURL 调用渲染服务:向带有 javascript=true 的 Crawling API 发送 URL,它会在真实浏览器中渲染页面,然后将完整 HTML 返回到 stdout,你通常的 cURL 管道和解析仍然有效。

开始构建

大规模爬取任何站点,无需与基础设施对抗。

Crawlbase 负责处理代理、指纹和 CAPTCHA,让你的团队专注于交付数据流水线,而非维护爬取管道。1,000 次请求免费,无需信用卡。

自助开通 · 无需销售通话 · 提供企业级爬取量