在 Python 中使用 cURL 的指南

此文将介绍如何结合 Python 和 cURL 来自动执行 GET、POST 和 PUT 请求以及下载文件和网页。
4 min read
在 Python 中使用 cURL 的指南

cURL 是一种多功能开源命令行工具,用于通过网络传输数据。它带有各种各样的参数,几乎可以处理任何请求。此外,cURL 是可扩展的,基本在每种现代编程语言中都有一个接口。

将 cURL 与编程语言结合使用有很多好处。例如,可以自动发出请求以进行调试或网络数据抓取。

本文将介绍如何结合使用 Python 和 cURL 来自动执行 GET、POST 和 PUT 请求以及下载文件和网页。

什么是cURL?

cURL 是一个软件,这个名字在不同的产品中出现时表示不同的意思:一个名为 libcurl 的库和一个名为curl 的命令行工具(使用 libcurl)。当本文中提到curl时,它指的是命令行工具。

 cURL功能强大;然而,它的核心任务很简单:通过各种网络协议传输数据。鉴于当今网络的复杂性,cURL 提供了大量选项 来处理最复杂的请求。

 cURL于1996年首次发布,当时名为 HttpGet,后来更名为 urlget,之后才更名为cURL。它的第一个用例是获取货币汇率并在 IRC 通道中使用它们。如今,curl 支持通过多种方法传输数据,包括 FTP(S)、HTTP(S)(POST、GET、PUT)、IMAP、POP3、MQTT 和 SMB。此外,curl 可以处理 cookie 和 SSL 证书。

当curl 通过 HTTPS 建立连接时,它会获取远程服务器证书并对照其 CA 证书存储进行检查,以确保远程服务器是它所声称的服务器。例如,以下请求将 HTTPS 请求发送到 Bright Data 网站,并设置一个名为greeting 的 cookie,其值为  hello:

curl --cookie "greeting=hello" https://www.brightdata.com

为什么在 Python 中使用curl?

尽管curl是一种多功能工具,但仍然需要将其与Python一起使用,最主要原因:Python可以自动执行您的请求。以下是三个用例,它们都很有用:

网络数据抓取

网页数据抓取需要从一个或多个网页收集(通常是大量)数据。为了使用 Python 抓取数据,人们通常依赖requests库。对于递归抓取,您可以使用wget。然而,对于具有复杂 HTTP(S) 调用的高级抓取用例,使用 Python 的curl 是理想的选择。

虽然可以生成并处理 HTTP(S) 请求的单个curl 命令来收集网页数据,但它不能递归地执行此操作。在 Python 代码中嵌入curl,您可以通过操作请求参数、cookie 和用户代理等元素来模拟网站上的导航路径。

导航甚至不需要修复,取决于抓取的内容,每个新请求都可以是完全动态的。

例如,您正在抓取热门新闻网站的评论,目标是包含恶意关键字评论,你只想抓取作者的个人资料页面,要达到这个目的,您可以创建一个评论的条件语句,并轻松应用此条件动态过滤器实现抓取。

此外,许多网站都有安全反数据采集机制,这使得抓取大量页面变得困难:比如分布式拒绝服务 (DDoS)  保护或reCAPTCHA 提示。通过应用某些规则和请求之间的暂停,可以模拟更难以检测到人类行为。

测试与调试

在您自己的网站上使用curl不恰当,但它在测试和调试上下文中很有用。测试或调试应用程序的一个或多个一般非常繁琐。它需要使用各种设置或参数进行反复测试。尽管有许多现成的测试工具,但 Python 和curl 可以轻松设置一些快速测试,依然是最受欢迎的。

例如,如果您要为复杂线上服务发布一个新的结帐流程,该流程使用 cookie、依赖于引荐来源网址、每个浏览器(即用户代理)存在细微差别,并将结帐流程中的所有步骤打包到正文中对于 POST 请求,手动测试所有变化需要大量时间。在Python中,您可以创建一个包含整个参数集的字典,并使用curl为每个可能的组合发送请求。

工作流程自动化

除了测试和调试以及网页抓取之外,curl 还可以用于工作流程自动化用例。例如,许多数据集成管道都是从数据导出的重复转储开始的,例如 CSV 或Apache Parquet 文件。通过在 (S)FTP 服务器上轮询新文件的 Python 应用程序,可以完全自动化复制数据转储。

或者考虑设置邮件挂钩。想象一下,如果应用程序可以轮询包含查询的电子邮件,则可以自动化很多日常任务。通过  POP3 或 IMAP 协议轮询新邮件,当邮箱收到特定电子邮件时,可以触发 Python 应用程序。

如何在 Python 中使用 cURL

在Python 中使用curl 发出请求的方法有多种。本文涵盖两个选项。第一个是通过 os 和 subprocess Python 包在命令行中模拟curl 请求。这种简单的方法以编程方式将命令发送到操作系统的命令行界面。

第二个选项是使用PycURL包。如果您想了解使用 Python 抓取网站的其他方法(不使用curl),您可以点击查看使用 Python 抓取数据指南。

准备工作

在开始之前,请确保您已下载并安装了curl。如果您使用Windows,请确保将curl添加到您的PATH环境变量中,以便您可以简单地执行curl命令。

要与您的操作系统建立 Python 接口,您可以使用各种包。最受欢迎的两个是os和subprocess。要安装它们,请运行以下 pip 命令:

pip install os subprocess

使用curl和os发出请求

OS包是一个非常简单的包。执行curl请求而不处理响应只需要两行代码。您只需要传递上一个示例中描述的 cookie,输出就会写入 output.txt 文件:

import os
os.system('curl -o output.txt --cookie "greeting=hello" -k https://curl.se')

如果您想在 Python 中处理响应而不是将其写入文件,则应使用下一节中讨论的 subprocess 包。

以下代码将运行相同的语句,但不是将响应写入文件,而是将 stdout 和 stderr 作为元组输出。然后可以使用其他 Python 包处理此输出,例如  Beautiful Soup:

import shlex
import subprocess
shell_cmd = shlex.split('curl --cookie "greeting=hello" -k https://curl.se')
process = subprocess.Popen(shell_cmd,
                    stdout = subprocess.PIPE,
                    stderr = subprocess.PIPE,
                    text = True,
                    shell = True
                    )
std_out, std_err = process.communicate()
std_out.strip(), std_err

使用 PycURL

您可以使用 PycURL 包,而不是使用 Python 与终端交互。如果您是 Linux 用户,那么就很简单,因为您可以使用 pip 安装 PycURL:

pip install pycurl
pip install certifi

您还应该安装certifi,以通过 HTTPS 协议进行交互。如果遇到问题,请点击查看 Stack Overflow 中的说明进行操作

虽然 PycURL 也可以安装在 Windows 上,但非常麻烦。如果您尝试通过 pip 安装它,它将返回以下错误:

Please specify --curl-dir=/path/to/built/libcurl

这就是为什么你需要从源代码安装它,这种方法可能“不适合胆小的人,因为存在多种可能的依赖项,并且每个依赖项都有自己的目录结构、配置风格、参数和其它千奇百怪的情况。”

因此,如果您在 Windows 计算机上工作,建议坚持使用基本网络请求的requests 包。”

如何使用 PycURL 发出请求

本文的其余部分将详细介绍如何使用 PycURL 包创建各种类型的请求。

使用 PycURL 发出 GET 请求

使用 PycURL 可以发出的最简单的GET 请求。它基本上是本节中所有其他模板的标准模板。

您可以在以下代码中识别出五个步骤:

  • 所有必需的包均已导入。
  • 创建两个对象:curl 请求将在其中存储其响应的缓冲区;用于发出请求的curl 对象。
  • 指定请求的选项:URL、目标和 SSL 验证。
  • 执行请求
  • 输出请求
# Preparation
import pycurl
import certifi
from io import BytesIO

# Set buffer and Curl object.
buffer = BytesIO()
c = pycurl.Curl()

# Set request options.
## Set the request destination.
c.setopt(c.URL, 'http://pycurl.io/')

## Set the buffer as the destination of the request's response.
c.setopt(c.WRITEDATA, buffer)

## Refer to the installed certificate authority bundle for validating the SSL certificate.
c.setopt(c.CAINFO, certifi.where())

# Execute and close the request.
c.perform()
c.close()

# Print the buffer's content with a Latin1 (iso-8859-1) encoding.
body = buffer.getvalue()
data = body.decode('iso-8859-1')
print(data)

使用 PycURL 发出 POST 请求

使用 PycURL 发出 POST 请求与发出 GET 请求非常相似。但是,请求中添加了一个额外选项:POST 正文。在以下代码片段中,设置了一个键值并对其进行 URL 编码,以确保正常运行:

# Preparation
import pycurl
import certifi
from io import BytesIO

# Set buffer and Curl object.
buffer = BytesIO()
c = pycurl.Curl()

# Set request options.
## Set the request destination.
c.setopt(c.URL, 'http://pycurl.io/')

## Set the request's body.
post_body = {'greeting': 'hello'}
postfields = urlencode(post_body)
c.setopt(c.POSTFIELDS, postfields)

## Set the buffer as the destination of the request's response.
c.setopt(c.WRITEDATA, buffer)

## Refer to the installed certificate authority bundle for validating the SSL certificate.
c.setopt(c.CAINFO, certifi.where())

# Execute and close the request.
c.perform()
c.close()

# Print the buffer's content with a Latin1 (iso-8859-1) encoding.
body = buffer.getvalue()
print(body.decode('iso-8859-1'))

使用 PycURL 发出 PUT 请求

上一节中创建的 POST 请求也可以作为 PUT 请求发送。将其作为以UTF-8编码的文件表示形式发送,而不是在请求正文中发送键值。该方法也可用于上传文件:

import pycurl
import certifi
from io import BytesIO

c = pycurl.Curl()

# Set request options.
## Set the request destination.
c.setopt(c.URL, 'http://pycurl.io/')

## Set data for the PUT request.
c.setopt(c.UPLOAD, 1)
data = '{"greeting": "hello"}'
buffer = BytesIO(data.encode('utf-8'))
c.setopt(c.READDATA, buffer)

## Refer to the installed certificate authority bundle for validating the SSL certificate.
c.setopt(c.CAINFO, certifi.where())

# Execute and close the request.
c.perform()
c.close()

使用 PycURL 下载文件

下一个代码片段演示了如何使用 PycURL 下载文件。请求随机 JPEG 图像,并打开 some_image.jpg 的写入流,将其传递给 PycURL 作为文件的目标:

import pycurl
import certifi

c = pycurl.Curl()

# Set the request destination.
c.setopt(c.URL, 'http://pycurl.io/some_image.jpg')

# Refer to the installed certificate authority bundle for validating the SSL certificate.
c.setopt(c.CAINFO, certifi.where())

# Execute and close the request.
with open('some_image.jpg', 'w') as f:
    c.setopt(c.WRITEFUNCTION, f.write)
    c.perform()

c.close()

使用 PycURL 下载和处理网页

由于许多 PycURL 用例都涉及网页抓取,因此下一个片段描述了如何使用 Beautiful Soup(一种用于解析 HTML 文件的流行包)处理请求的响应。

首先,使用 pip 安装 Beautiful Soup 4:

pip install beautifulsoup4

其次,将下一个片段放在发出 GET 请求的第一个 PycURL 片段后面。这将使 Beautiful Soup 处理响应数据。

为了演示,使用 find_all 方法 查找所有段落元素,并打印各个段落的内容:

from bs4 import BeautifulSoup

# Parsing data using BeautifulSoup
soup = BeautifulSoup(data, 'html.parser')

# Find all paragraphs
paragraphs = soup.find_all('p')
for p in paragraphs:
   print(p.text)

代理网络和PycURL一起使用

当您使用代理网络时,大规模网络抓取效果最佳。这样做的好处是,您可以并行模拟浏览行为,而不会被标记为机器人或进行异常行为。

在最后一部分中,您将了解如何通过代理网络 使用 PycURL 创建请求。如上文所示,这是通过调整请求选项来实现的。随后描述了四种设置,但您可以 根据自己的情况进行调整:

  • 为了方便起见,启用了不安全的代理。
  • 代理服务器已设置。
  • 该脚本通过服务器进行身份验证。
  • 代理设置为 HTTPS。
# Enable insecure proxies
c.setopt(c.PROXY_SSL_VERIFYHOST, 0)
c.setopt(c.PROXY_SSL_VERIFYPEER, 0)

# Set proxy server
c.setopt(pycurl.PROXY, <YOUR_HTTPS_PROXY_SERVER>)

# Authenticate with the proxy server
c.setopt(pycurl.PROXYUSERPWD, f"{<YOUR_USERNAME>}:{<YOUR_PASSWORD>}")

# Set proxy type to https
c.setopt(pycurl.PROXYTYPE, 2)

这些选项可以插入到前面描述的代码片段中的任何位置,以使请求通过代理服务器重新路由。

总结

本文详细解释了curl 和Python 的组合,强调了为什么将它们一起使用来生成网络数据抓取和应用程序测试用例的复杂请求的有效性。提供了多个案例来演示 PycURL 用于生成大量网络请求的多功能性。

或者,您可以使用 Bright Data 代理网络及其 Web Scraper IDE,该 IDE 专为解放开发人员的繁重工作而研发。这样,您就可以专注于处理抓取的数据,而不必担心如何通过或避开反数据抓取机制的限制。