使用 requests 访问 Python 包索引 JSON API

PyPI 的 JSON API 是机器可读的数据来源,与您在浏览网站时访问的数据类型相同。
90 位读者喜欢这个。
Python programming language logo with question marks

Opensource.com

PyPI,即 Python 包索引,为其软件包提供 JSON API 以获取信息。这本质上是机器可读的数据来源,与您在浏览网站时访问的数据类型相同。例如,作为一个人,我可以访问浏览器中的 NumPy 项目页面,点击浏览,查看有哪些版本,哪些文件可用,以及发布日期和支持的 Python 版本等信息

但是,如果我想编写一个程序来访问这些数据,我可以使用 JSON API,而无需抓取和解析这些页面上的 HTML。

顺便说一句:在旧的 PyPI 网站上,当它托管在 pypi.python.org 时,NumPy 项目页面位于 pypi.python.org/pypi/numpy,访问 JSON 非常简单,只需在末尾添加 /json,因此网址为 https://pypi.ac.cn/pypi/numpy/json。现在 PyPI 网站托管在 pypi.org,NumPy 的项目页面位于 pypi.org/project/numpy。新站点不包含 JSON 渲染,但它仍然像以前一样运行。因此,现在您不必在 URL 末尾添加 /json,而是必须记住它们所在的 URL。

您可以通过访问 NumPy 的 URL 在浏览器中打开其 JSON。Firefox 将其很好地呈现为这样

您可以打开 inforeleasesurls 来检查其中的内容。或者您可以将其加载到 Python shell 中。以下是一些入门行

import requests
url = "https://pypi.ac.cn/pypi/numpy/json"
r = requests.get(url)
data = r.json()

获得数据后(调用 .json() 提供数据 字典),您可以检查它

打开 releases,并检查其中的键

这表明 releases 是一个字典,其中版本号作为键。选择一个(例如,最新的一个)并检查它

每个版本都是一个列表,这个版本包含 24 个项目。但是每个项目是什么?由于它是一个列表,您可以索引第一个并查看

此项目是一个字典,其中包含有关特定文件的详细信息。因此,列表中的 24 个项目中的每一个都与与此特定版本号关联的文件有关,即 https://pypi.ac.cn/project/numpy/1.20.1/#files 上列出的 24 个文件。

您可以编写一个脚本来查找可用数据中的内容。例如,以下循环查找具有 sdist(源代码分发)文件且指定了 requires_python 属性的版本并打印它们

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'])

piwheels

去年,我在 piwheels 网站上 实施了类似的 APIpiwheels.org 是一个 Python 包索引,为 Raspberry Pi 架构提供 wheels(预编译的二进制包)。它本质上是 PyPI 上软件包集的镜像,但使用 Arm wheels 而不是软件包维护者上传到 PyPI 的文件。

由于 piwheels 模仿了 PyPI 的 URL 结构,您可以将项目页面的 URL 的 pypi.org 部分更改为 piwheels.org。它将向您显示一个类似的项目页面,其中包含有关我们构建的版本以及哪些文件可用的详细信息。由于我喜欢旧站点允许您在 URL 末尾添加 /json 的方式,因此我让我们的站点也以这种方式工作,因此 PyPI 上 NumPy 的项目页面是 pypi.org/project/numpy。在 piwheels 上,它是 piwheels.org/project/numpy,JSON 位于 piwheels.org/project/numpy/json

无需复制 PyPI API 的内容,因此我们提供有关 piwheels 上可用内容的信息,并包含所有已知版本的列表、一些基本信息以及我们拥有的文件列表

与之前的 PyPI 示例类似,您可以创建一个脚本来分析 API 内容,例如,显示 piwheels 为每个 NumPy 版本拥有的文件数

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))

此外,每个文件都包含一些元数据

一个方便的功能是 apt_dependencies 字段,其中列出了使用该库所需的 Apt 包。对于此 NumPy 文件,除了使用 pip 安装 NumPy 外,您还需要使用 Debian 的 Apt 包管理器安装 libatlas3-baselibgfortran

这是一个示例脚本,显示了软件包的 Apt 依赖项

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')

我们还为软件包列表提供了一个通用的 API 端点,其中包括每个软件包的下载统计信息

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 当前由于其 XMLRPC 接口过载而被禁用,人们一直在寻找替代方案。您可以使用 piwheels JSON API 来搜索软件包名称,因为软件包集是相同的

#!/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")

有关更多信息,请参阅 piwheels JSON API 文档


本文最初发表在 Ben Nuttall 的 Tooling Tuesday 博客 上,并经许可重复使用。

接下来阅读什么
标签
User profile image.
Ben 是 BBC News Labs 的软件工程师,曾任 Raspberry Pi 的社区经理。他热衷于 Linux、Python 和所有开源事物!在 Twitter 上关注 Ben @ben_nuttall。

1 条评论

嗯,这非常有用。谢谢!

知识共享许可协议本作品根据知识共享署名-相同方式共享 4.0 国际许可协议获得许可。
© . All rights reserved.