为了达到本文的目的——即学习如何在 Python 中使用 cURL,我们首先需要介绍一下 cURL。Client URL(cURL)简而言之,是一个专为开发者设计的、易于使用的命令行工具,用于从服务器获取数据。
什么是 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 osos.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 certifiprint(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 的方法,并鼓励你去尝试编写一些脚本。




