使用 resuests 訪問(wèn) Python 包索引(PyPI)的 JSON API
PyPI 的 JSON API 是一種機(jī)器可直接使用的數(shù)據(jù)源,你可以訪問(wèn)和你瀏覽網(wǎng)站時(shí)相同類(lèi)型的數(shù)據(jù)。
PyPI(Python 軟件包索引)提供了有關(guān)其軟件包信息的 JSON API。本質(zhì)上,它是機(jī)器可以直接使用的數(shù)據(jù)源,與你在網(wǎng)站上直接訪問(wèn)是一樣的的。例如,作為人類(lèi),我可以在瀏覽器中打開(kāi) Numpy 項(xiàng)目頁(yè)面,點(diǎn)擊左側(cè)相關(guān)鏈接,查看有哪些版本,哪些文件可用以及發(fā)行日期和支持的 Python 版本等內(nèi)容:
NumPy project page
但是,如果我想編寫(xiě)一個(gè)程序來(lái)訪問(wèn)此數(shù)據(jù),則可以使用 JSON API,而不必在這些頁(yè)面上抓取和解析 HTML。
順便說(shuō)一句:在舊的 PyPI 網(wǎng)站上,還托管在 pypi.python.org
時(shí),NumPy 的項(xiàng)目頁(yè)面位于 pypi.python.org/pypi/numpy
,訪問(wèn)其 JSON API 也很簡(jiǎn)單,只需要在最后面添加一個(gè) /json
,即 https://pypi.org/pypi/numpy/json
?,F(xiàn)在,PyPI 網(wǎng)站托管在 pypi.org
,NumPy 的項(xiàng)目頁(yè)面是 pypi.org/project/numpy
。新站點(diǎn)不會(huì)有單獨(dú)的 JSON API URL,但它仍像以前一樣工作。因此,你不必在 URL 后添加 /json
,只要記住 URL 就夠了。
你可以在瀏覽器中打開(kāi) NumPy 的 JSON API URL,F(xiàn)irefox 很好地渲染了數(shù)據(jù):
JSON rendered in Firefox
你可以查看 info
,release
和 urls
其中的內(nèi)容?;蛘?,你可以將其加載到 Python Shell 中,以下是幾行入門(mén)教程:
import requests
url = "https://pypi.org/pypi/numpy/json"
r = requests.get(url)
data = r.json()
獲得數(shù)據(jù)后(調(diào)用 .json()
提供了該數(shù)據(jù)的 字典),你可以對(duì)其進(jìn)行查看:
Inspecting data
查看 release
中的鍵:
Inspecting keys in releases
這表明 release
是一個(gè)以版本號(hào)為鍵的字典。選擇一個(gè)并查看以下內(nèi)容:
Inspecting version
每個(gè)版本都包含一個(gè)列表,release
包含 24 項(xiàng)。但是每個(gè)項(xiàng)目是什么?由于它是一個(gè)列表,因此你可以索引第一項(xiàng)并進(jìn)行查看:
Indexing an item
這是一個(gè)字典,其中包含有關(guān)特定文件的詳細(xì)信息。因此,列表中的 24 個(gè)項(xiàng)目中的每一個(gè)都與此特定版本號(hào)關(guān)聯(lián)的文件相關(guān),即在 https://pypi.org/project/numpy/1.20.1/#files 列出的 24 個(gè)文件。
你可以編寫(xiě)一個(gè)腳本在可用數(shù)據(jù)中查找內(nèi)容。例如,以下的循環(huán)查找?guī)в?sdist(源代碼包)的版本,它們指定了 requires_python
屬性并進(jìn)行打?。?/p>
for version, files in data['releases'].items():
for f in files:
if f.get('packagetype') == 'sdist' and f.get('requires_python'):
print(version, f['requires_python'])
sdist files with requires_python attribute
piwheels
去年,我在 piwheels 網(wǎng)站上實(shí)現(xiàn)了類(lèi)似的 API。piwheels.org 是一個(gè) Python 軟件包索引,為樹(shù)莓派架構(gòu)提供了 wheel(預(yù)編譯的二進(jìn)制軟件包)。它本質(zhì)上是 PyPI 軟件包的鏡像,但帶有 Arm wheel,而不是軟件包維護(hù)者上傳到 PyPI 的文件。
由于 piwheels 模仿了 PyPI 的 URL 結(jié)構(gòu),因此你可以將項(xiàng)目頁(yè)面 URL 的 pypi.org
部分更改為 piwheels.org
。它將向你顯示類(lèi)似的項(xiàng)目頁(yè)面,其中詳細(xì)說(shuō)明了構(gòu)建的版本和可用的文件。由于我喜歡舊站點(diǎn)允許你在 URL 末尾添加 /json
的方式,所以我也支持這種方式。NumPy 在 PyPI 上的項(xiàng)目頁(yè)面為 pypi.org/project/numpy,在 piwheels 上,它是 piwheels.org/project/numpy,而 JSON API 是 piwheels.org/project/numpy/json 頁(yè)面。
沒(méi)有必要重復(fù) PyPI API 的內(nèi)容,所以我們提供了 piwheels 上可用內(nèi)容的信息,包括所有已知發(fā)行版的列表,一些基本信息以及我們擁有的文件列表:
JSON files available in piwheels
與之前的 PyPI 例子類(lèi)似,你可以創(chuàng)建一個(gè)腳本來(lái)分析 API 內(nèi)容。例如,對(duì)于每個(gè) NumPy 版本,其中有多少 piwheels 文件:
import requests
url = "https://www.piwheels.org/project/numpy/json"
package = requests.get(url).json()
for version, info in package['releases'].items():
if info['files']:
print('{}: {} files'.format(version, len(info['files'])))
else:
print('{}: No files'.format(version))
此外,每個(gè)文件都包含一些元數(shù)據(jù):
Metadata in JSON files in piwheels
方便的是 apt_dependencies
字段,它列出了使用該庫(kù)所需的 Apt 軟件包。本例中的 NumPy 文件,或者通過(guò) pip
安裝 Numpy,你還需要使用 Debian 的 apt
包管理器安裝 libatlas3-base
和 libgfortran
。
以下是一個(gè)示例腳本,顯示了程序包的 Apt 依賴(lài)關(guān)系:
import requests
def get_install(package, abi):
url = 'https://piwheels.org/project/{}/json'.format(package)
r = requests.get(url)
data = r.json()
for version, release in sorted(data['releases'].items(), reverse=True):
for filename, file in release['files'].items():
if abi in filename:
deps = ' '.join(file['apt_dependencies'])
print("sudo apt install {}".format(deps))
print("sudo pip3 install {}=={}".format(package, version))
return
get_install('opencv-python', 'cp37m')
get_install('opencv-python', 'cp35m')
get_install('opencv-python-headless', 'cp37m')
get_install('opencv-python-headless', 'cp35m')
我們還為軟件包列表提供了一個(gè)通用的 API 入口,其中包括每個(gè)軟件包的下載統(tǒng)計(jì):
- import requests
- url = "https://www.piwheels.org/packages.json"
- packages = requests.get(url).json()
- packages = {
- pkg: (d_month, d_all)
- for pkg, d_month, d_all, *_ in packages
- }
- package = 'numpy'
- d_month, d_all = packages[package]
- print(package, "has had", d_month, "downloads in the last month")
- print(package, "has had", d_all, "downloads in total")
pip search
pip search
因?yàn)槠?XMLRPC 接口過(guò)載而被禁用,因此人們一直在尋找替代方法。你可以使用 piwheels 的 JSON API 來(lái)搜索軟件包名稱(chēng),因?yàn)檐浖募鲜窍嗤模?/p>
#!/usr/bin/python3
import sys
import requests
PIWHEELS_URL = 'https://www.piwheels.org/packages.json'
r = requests.get(PIWHEELS_URL)
packages = {p[0] for p in r.json()}
def search(term):
for pkg in packages:
if term in pkg:
yield pkg
if __name__ == '__main__':
if len(sys.argv) == 2:
results = search(sys.argv[1].lower())
for res in results:
print(res)
else:
print("Usage: pip_search TERM")
有關(guān)更多信息,參考 piwheels 的 JSON API 文檔.