什么是 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
}
当你使用 cURL 命令调用 API 时,大多数 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”不被视为外部或内部命令。批处理文件是一个用于执行操作的程序。
安装 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,并针对该 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 请求。以下是一个 Python 函数的示例,该函数向https://httpbin.org/post 发送 POST 请求:
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)
你可能已经注意到,我们现在不再使用 os 模块,而是改用了 subprocess 和 json 库。我们之所以使用 subprocess 库,是因为我们希望能够保存命令的输出结果,而 os 模块只是执行命令而不进行存储。这段代码是一个简单的 API GET 请求,它会以 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'}}
这只是 cURL 在 Python 中的众多用途之一。我们不再依赖 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')
这段代码将返回以下输出:
列表中存在一位名为 Clementina DuBuque 的用户,其 ID 为 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 的方法,并鼓励你去尝试编写一些脚本。




