返回博客
指南
Andrei OgiolanLast updated on Mar 31, 20263 min read

了解如何在 Python 中使用 cURL

了解如何在 Python 中使用 cURL

什么是 cURL?

为了达到本文的目的——即学习如何在 Python 中使用 cURL,我们首先需要介绍一下 cURL。Client URL(cURL)简而言之,是一个专为开发者设计的、易于使用的命令行工具,用于从服务器获取数据。

如何使用 cURL?

如前所述,使用 cURL 非常简单,仅需一行命令即可提取信息。首先,你需要打开终端,输入 curl 并跟上网站链接,例如:

$ curl 'https://www.webscrapingapi.com/'

恭喜,您已成功使用 cURL 发送了第一个请求。这条简单的命令就像传统浏览器一样向服务器请求信息,并返回页面的 HTML 内容。并非所有网站都会返回 HTML,有些接口会以 JSON 对象的形式返回数据。请看这个示例:

$ curl 'https://jsonplaceholder.typicode.com/todos/1'

在终端中输入此命令,你应该会收到如下响应:

{
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}

当你对 API 运行 cURL 命令时,大多数 API 会返回 HTML 或 JSON 格式。但这并非 cURL 的全部功能。实际上,它是一个非常强大的工具。如果你想进一步了解 cURL,我强烈建议你查阅 cURL 文档,以便更好地理解其参数。或者,你可以运行以下命令:

$ curl --help

这将向您展示 cURL 可设置的一些选项:

Usage: curl [options...] <url>
-d, --data <data> HTTP POST data
-f, --fail Fail silently (no output at all) on HTTP errors
-h, --help <category> Get help for commands
-i, --include Include protocol response headers in the output
-o, --output <file> Write to file instead of stdout
-O, --remote-name Write output to a file named as the remote file
-s, --silent Silent mode
-T, --upload-file <file> Transfer local FILE to destination
-u, --user <user:password> Server user and password
-A, --user-agent <name> Send User-Agent <name> to server
-v, --verbose Make the operation more talkative
-V, --version Show version number and quit

This is not the full help, this menu is stripped into categories.
Use "--help category" to get an overview of all categories.
For all options use the manual or "--help all".

如您所见,这甚至还不是 cURL 的全部选项,它是一个按类别划分的菜单。您可能已经猜到了,若要获取所有可用的选项,您需要运行:

$ curl --help all

如何在 Python 中使用 cURL?

此步骤有两个先决条件。第一个显而易见,您需要在计算机上安装 Python。您可以访问 Python 官方网站,并安装适合您操作系统的版本。请确保安装的是新版,因为旧版本很可能不包含 pip,而我们后续要使用的多数包都需要 pip。安装完成后,请运行以下命令:

$ pip --version

安装成功后,系统应显示您已安装的 pip 版本。 

否则,您很可能会收到以下提示:

"pip" is not considered to be an external or internal command. A batch file is a program to operate.

安装 pip 至关重要,因为后续安装包时需要用到它。

第二个先决条件是,您应熟悉 Python 的语法,或者至少具备其他编程语言的入门级经验。

为何要在 Python 中使用 cURL?

您可能在想:仅在命令行中使用 cURL 难道不够吗?我们只需执行一行命令,API 就会返回所需信息。这确实没错,但在实际应用中,我们需要对从服务器接收到的数据进行某种处理,因此才需要编程语言。这就是 Python 派上用场的时候。

为何选择 Python?

Python 是一种用途广泛的高级编程语言。其简洁的语法和易用性使得初学者能够轻松上手。此外,它拥有庞大的社区随时准备为您提供帮助,因此如果您遇到任何问题,请不要犹豫,大胆提问。StackOverflow 是一个绝佳的提问平台,那里总会有人为您解答。

如何在 Python 中集成 cURL

与之前一样,Python 中的 cURL 操作同样非常直观。还记得我们之前只用一行命令就能从服务器获取数据吗?不同之处在于,现在你需要编写两行代码来完成这个简单的调用,例如:

import os
os.system(f'curl "https://www.webscrapingapi.com/product/"')

现在让我们看看使用编程语言的真正优势。我们可以编写一个函数,该函数可以接收自定义 URL 并针对其运行 cURL 命令:

import os

def cURL(url):
return os.system(f'curl "{url}"')

cURL('https://www.webscrapingapi.com/blog/')

你可以将 https://www.webscrapingapi.com/blog/ 替换为任何你想获取数据的网站。恭喜,至此你已创建了一个脚本,它能接收一个 URL,执行 cURL 命令,并在控制台显示结果。虽然你可以在终端中直接运行 Python,但为了获得更好的编程体验,我强烈建议你使用集成开发环境(IDE)。 可选的开发环境有很多,但针对 Python,我推荐 PyCharm,您可从这里下载

正如我之前提到的,cURL 的功能远不止于此。除了发送 GET 请求外,它还能完成大量其他任务。它还可以下载文件或发送 POST、PUT 或 DELETE 请求。以下是一个向 https://httpbin.org/post 发送 POST 请求的 Python 函数示例:

import os

def cURL(method,url,data):
return os.system(f'curl -X "{method}" --url "{url}" --data {data} ')

data = '{"foo":"bar"}'

cURL('POST', 'https://httpbin.org/post', data)

如您所见,发送 POST 请求时的命令会略有不同。在之前的请求中,您无需使用 -X 和 –data 参数,因为 cURL 的默认方法是 GET。执行此命令后,您应从 httpbin API 收到包含您的请求、IP 地址、参数以及提交的请求主体的响应,内容大致如下:

{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "{foo:bar}": ""
  }, 
  "headers": {
    "Accept": "*/*", 
    "Content-Length": "9", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/X.XX.X", 
    "X-Amzn-Trace-Id": "Root=X-XXXXX-XXXXXX"
  }, 
  "json": null, 
  "origin": "0.0.0.0", 
  "url": "https://httpbin.org/post"
}

至此,你已经构建了一个简单的工具,可以发送 GET、POST、PUT、PATCH、DELETE 等请求来从 API 获取数据。现在,我们只需在 Python 脚本中直接设置 URL、方法和请求主体,而无需手动输入。 不过,这只是在 Python 中使用 cURL 带来的次要好处。主要优势在于,即使 API 没有提供我们期望的数据获取方式,我们现在也能按需处理数据。例如,假设我们收到了一份所有用户的列表,但希望将其分为两组,并获取第二组中的用户。

借助 Python,我们可以将响应存储在一个名为 users 的变量中,并使用 json.loads() 方法将其转换为 JSON 对象数组(关于该方法的更多信息可在此处查阅)。之后,我们可以遍历 users 数组,并仅显示列表后半部分的用户,或者 ID 编号大于列表中点位置的用户。为了便于理解,代码实现如下:

import subprocess
import json

def cURL(url):
   return subprocess.check_output(['curl',url])

users = json.loads(cURL('https://jsonplaceholder.typicode.com/users'))

for user in users:
   if(user['id'] > len(users) / 2): print(user)

您可能已经注意到,我们现在使用的是 subprocess 和 json 库,而不是 os 模块。我们选择 subprocess 库是因为需要保存命令的输出结果,而 os 模块仅执行命令而不进行数据存储。这段代码是一个简单的 GET 请求,用于向 API 获取用户列表,并以 JSON 对象的形式返回。输出结果应为:

{'id': 6, 'name': 'Mrs. Dennis Schulist', 'username': 'Leopoldo_Corkery', 'email': 'Karley_Dach@jasper.info', 'address': {'street': 'Norberto Crossing', 'suite': 'Apt. 950', 'city': 'South Christy', 'zipcode': '23505-1337', 'geo': {'lat': '-71.4197', 'lng': '71.7478'}}, 'phone': '1-477-935-8478 x6430', 'website': 'ola.org', 'company': {'name': 'Considine-Lockman', 'catchPhrase': 'Synchronised bottom-line interface', 'bs': 'e-enable innovative applications'}}

{'id': 7, 'name': 'Kurtis Weissnat', 'username': 'Elwyn.Skiles', 'email': 'Telly.Hoeger@billy.biz', 'address': {'street': 'Rex Trail', 'suite': 'Suite 280', 'city': 'Howemouth', 'zipcode': '58804-1099', 'geo': {'lat': '24.8918', 'lng': '21.8984'}}, 'phone': '210.067.6132', 'website': 'elvis.io', 'company': {'name': 'Johns Group', 'catchPhrase': 'Configurable multimedia task-force', 'bs': 'generate enterprise e-tailers'}}

{'id': 8, 'name': 'Nicholas Runolfsdottir V', 'username': 'Maxime_Nienow', 'email': 'Sherwood@rosamond.me', 'address': {'street': 'Ellsworth Summit', 'suite': 'Suite 729', 'city': 'Aliyaview', 'zipcode': '45169', 'geo': {'lat': '-14.3990', 'lng': '-120.7677'}}, 'phone': '586.493.6943 x140', 'website': 'jacynthe.com', 'company': {'name': 'Abernathy Group', 'catchPhrase': 'Implemented secondary concept', 'bs': 'e-enable extensible e-tailers'}}

{'id': 9, 'name': 'Glenna Reichert', 'username': 'Delphine', 'email': 'Chaim_McDermott@dana.io', 'address': {'street': 'Dayna Park', 'suite': 'Suite 449', 'city': 'Bartholomebury', 'zipcode': '76495-3109', 'geo': {'lat': '24.6463', 'lng': '-168.8889'}}, 'phone': '(775)976-6794 x41206', 'website': 'conrad.com', 'company': {'name': 'Yost and Sons', 'catchPhrase': 'Switchable contextually-based project', 'bs': 'aggregate real-time technologies'}}

{'id': 10, 'name': 'Clementina DuBuque', 'username': 'Moriah.Stanton', 'email': 'Rey.Padberg@karina.biz', 'address': {'street': 'Kattie Turnpike', 'suite': 'Suite 198', 'city': 'Lebsackbury', 'zipcode': '31428-2261', 'geo': {'lat': '-38.2386', 'lng': '57.2232'}}, 'phone': '024-648-3804', 'website': 'ambrose.net', 'company': {'name': 'Hoeger LLC', 'catchPhrase': 'Centralized empowering task-force', 'bs': 'target end-to-end models'}}

这只是 Python 中 cURL 的众多用途之一。我们不再依赖 API 以特定格式返回数据,而是可以进行多种方式的处理,例如根据姓名、邮箱、电话号码或任何其他个人特征,判断某人是否出现在响应列表中。 

例如,假设我们要检查列表中是否存在某个特定姓名。为此,我们可以编写一个函数,该函数接收已转换为 JSON 数组的响应数据(以便 Python 解析)。

import subprocess
import json

def cURL(url):
   return subprocess.check_output(['curl',url])

users = json.loads(cURL('https://jsonplaceholder.typicode.com/users'))

def check_if_user_exists(users,name):
   for user in users:
       if(user['name'] == name): print(f'An user called {name} exists in the list and has the id of {user["id"]}')

check_if_user_exists(users,'Clementina DuBuque')

这段代码将返回以下输出:

An user called Clementina DuBuque exists in the list and has the id of 10

恭喜。您已编写了一个脚本,能够从服务器获取数据、存储数据并随后进行解析。Python 的优势不仅限于此,它甚至还提供了一个专为使用 cURL 设计的特殊接口,名为 PycURL,我们接下来将对此进行讨论。

什么是 PycURL?

正如之前提到的,简而言之,PycURL 是一个帮助我们更自然地使用 cURL 的 Python 工具。 其一大优势在于 PycURL 经过深度优化且支持并发,这意味着它运行速度极快(比流行的 Python request 库更快)。另一方面,PycURL 的使用并不像我们之前所见的那样简单,它是一款面向高级开发者的工具。不过您不必因此感到畏难,因为最终您将对网络通信有更深入的理解,并且对 Python 的掌握也会更加得心应手。

如何安装?

与其他包一样,你可以使用 pip 安装: 

$ pip install pycurl 

出于安全考虑,本次使用 pycurl 时建议同时安装 certifi。Certifi 是一款在验证 TLS 主机身份时用于验证 SSL 证书的工具。若想进一步了解 certifi,强烈建议查阅其文档。安装方式与上述相同: 

$ pip install certifi

现在你可以运行以下脚本测试安装是否成功: 

import certifi
print(certifi.where())

输出结果应显示包的安装路径:

/usr/local/lib/python3.10/site-packages/certifi/cacert.pem

如何使用 pycURL?

与之前操作的不同之处在于,现在我们仅编写代码而不直接执行命令。简而言之,我们创建一个 pycurl.Curl() 类的实例,获取数据并将其写入缓冲区,随后我们将对缓冲区进行解码以读取接收到的数据:

import pycurl
import certifi
from io import BytesIO

buffer = BytesIO()
c = pycurl.Curl()
c.setopt(c.URL, 'https://docs.webscrapingapi.com/')
c.setopt(c.WRITEDATA, buffer)
c.setopt(c.CAINFO, certifi.where())
c.perform()
c.close()

body = buffer.getvalue()
print(body.decode('iso-8859-1'))

你猜对了,就像之前的示例一样,这段代码会抓取 WebScrapingAPI 网页的 HTML 内容,并将其打印在命令行中。

POST请求与之大同小异,区别仅在于你需要告知pycurl.Curl()类的实例将使用POST方法,并根据需要设置请求主体和头部。具体实现如下:

​​import pycurl
import certifi
import json
from io import BytesIO

buffer = BytesIO()
c = pycurl.Curl()
c.setopt(c.URL, 'https://httpbin.org/post')
c.setopt(pycurl.HTTPHEADER, [ 'Content-Type: application/json' , 'Accept: application/json'])
data = json.dumps({"foo": "bar"})

c.setopt(pycurl.POST, 1)
c.setopt(pycurl.POSTFIELDS, data)
c.setopt(c.WRITEDATA, buffer)
c.setopt(c.CAINFO, certifi.where())

c.perform()
c.close()

body = buffer.getvalue()

print(body.decode('iso-8859-1'))

我们应该会收到一个响应,就像之前一样,其中包含你的请求、IP 地址、参数和请求体:

{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "{foo:bar}": ""
  }, 
  "headers": {
    "Accept": "*/*", 
    "Content-Length": "9", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/X.XX.X", 
    "X-Amzn-Trace-Id": "Root=X-XXXXX-XXXXXX"
  }, 
  "json": null, 
  "origin": "0.0.0.0", 
  "url": "https://httpbin.org/post"
}

正如我之前提到的,pycURL 能为我们做的事情仅是基础功能。它是一个非常复杂且功能强大的工具,我们可以围绕它撰写许多文章。如果你想进一步探索它的更多功能,我强烈建议你查阅其文档

总结

总而言之,在 Python 中使用 cURL 非常高效且能节省大量时间,更重要的是,它可以作为数据分析或网页抓取等主题中一些有趣项目的起点。我建议的做法是:先熟悉 cURL 和 Python,然后再进阶使用 pycURL。希望这篇指南能帮助你掌握在 Python 中使用 cURL 的方法,并鼓励你去尝试编写一些脚本。

关于作者
Andrei Ogiolan, 全栈开发工程师 @ WebScrapingAPI
Andrei Ogiolan全栈开发工程师

安德烈·奥吉奥兰(Andrei Ogiolan)是 WebScrapingAPI 的全栈开发工程师,他在产品各领域均有贡献,并协助为该平台构建可靠的工具和功能。

开始构建

准备好扩展您的数据收集规模了吗?

加入2,000多家企业,使用WebScrapingAPI在无需任何基础设施开销的情况下,以企业级规模提取网络数据。