第 17 章 使用API

在本章中,你将学习如何编写一个独立的程序,并对其获取的数进行可视化。这个程序将使用Web应用编程接口(API)自动请求网站的特定信息而不是整个网页,再对这些信息进行可视化。
由于这样编写的程序始终使用最新的数据来生成可视化,因此即便数据瞬息万变,它呈现的信息也都是最新的。


17.1 使用Web API


Web API是网站的一部分,用于与使用非常具体的URL请求特定信息的程序交互。这种请求称为API调用。请求的数据将以易于处理的格式(如JSON或CSV)返回。依赖于外部数据源的大多数应用程序都依赖于API调用,如集成社交媒体网站的应用程序。


17.1.1 Git和GitHub


本章的可视化将基于来自GitHub的信息,这是一个让程序员能够协作开发项目的网站。我们将使用GitHub的API来请求有关该网站中Python项目的信息,然后使用Pygal生成交互式可视化,以呈现这些项目的受欢迎程度。
GitHub(https://github.com/)的名字源自Git,Git是一个分布式版本控制系统,让程序员团队能够协作开发项目。Git帮助大家管理为项目所做的工作,避免一个人所做的修改影响其他人所做的修改。你在项目中实现新功能时,Git将跟踪你对每个文件所做的修改。确定代码可行后,你提交所做的修改,而Git将记录项目最新的状态。如果你犯了错,想撤销所做的修改,可轻松地返回以前的任何可行状态(要更深入地了解如何使用Git进行版本控制,请参阅附录D)。GitHub上的项目都存储在仓库中,后者包含与项目相关联的一切:代码、项目参与者的信息、问题或bug报告等。
对于喜欢的项目,GitHub用户可给它加星(star)以表示支持,用户还可跟踪他可能想使用的项目。在本章中,我们将编写一个程序,它自动下载GitHub上星级最高的Python项目的信息,并对这些信息进行可视化。


17.1.2 使用API调用请求数据


GitHub的API让你能够通过API调用来请求各种信息。要知道API调用是什么样的,请在浏览器的地址栏中输入如下地址并按回车键:https://api.github.com/search/repositories?
q=language:python&sort=stars
这个调用返回GitHub当前托管了多少个Python项目,还有有关最受欢迎的Python仓库的信息。下面来仔细研究这个调用。第一部分(https://api.github.com/)将请求发送到GitHub网站中响应
API调用的部分;接下来的一部分(search/repositories)让API搜索GitHub上的所有仓库。
repositories后面的问号指出我们要传递一个实参。q表示查询,而等号让我们能够开始指定查询(q=)。通过使用language:python,我们指出只想获取主要语言为Python的仓库的信息。最后一部分(&sort=stars)指定将项目按其获得的星级进行排序。
下面显示了响应的前几行。从响应可知,该URL并不适合人工输入。

{
"total_count": 713062,
"incomplete_results": false,
"items": [
{
"id": 3544424,
"name": "httpie",
"full_name": "jkbrzt/httpie",
--snip--


从第二行输出可知,编写本书时,GitHub总共有713 062个Python项目。"incomplete_results"的值为false,据此我们知道请求是成功的(它并非不完整的)。倘若GitHub无法全面处理该API,它返回的这个值将为true。接下来的列表中显示了返回的"items",其中包含GitHub上最受欢迎的Python项目的详细信息。


17.1.3 安装requests


requests包让Python程序能够轻松地向网站请求信息以及检查返回的响应。要安装requests,请执行类似于下面的命令:

$ pip install --user requests


如果你还没有使用过pip,请参阅12.2.1节(根据系统的设置,你可能需要使用这个命令的稍微不同的版本)。


17.1.4 处理API响应


下面来编写一个程序,它执行API调用并处理结果,找出GitHub上星级最高的Python项目:

python_repos.py
import requests ❶
# 执行API调用并存储响应
url = 'https://api.github.com/search/repositories?
q=language:python&sort=stars' ❷
r = requests.get(url) ❸
print("Status code:", r.status_code) ❹
# 将API响应存储在一个变量中
response_dict = r.json() ❺
# 处理结果
print(response_dict.keys())


在❶处,我们导入了模块requests。在❷处,我们存储API调用的URL,然后使用requests来执行调用(见❸)。我们调用get()并将URL传递给它,再将响应对象存储在变量r中。响应对象包含一个名为status_code的属性,它让我们知道请求是否成功了(状态码200表示请求成功)。在❹处,我们打印status_code,核实调用是否成功了。
这个API返回JSON格式的信息,因此我们使用方法json()将这些信息转换为一个Python字典(见❺)。我们将转换得到的字典存储在response_dict中。
最后,我们打印response_dict中的键。输出如下:

状态码为200,因此我们知道请求成功了。响应字典只包含三个
键:'items'、'total_count'和'incomplete_results'。
注意 像这样简单的调用应该会返回完整的结果集,因此完全可以忽略与'incomplete_results'相关联的值。但执行更复杂的API调用时,程序应检查这个值。


17.1.5 处理响应字典


将API调用返回的信息存储到字典中后,就可以处理这个字典中的数据了。下面来生成一些概述这些信息的输出。这是一种不错的方式,可确认收到了期望的信息,进而可以开始研究感兴趣的信息:

python_repos.py
import requests
# 执行API调用并存储响应
url = 'https://api.github.com/search/repositories?
q=language:python&sort=stars'
r = requests.get(url)
print("Status code:", r.status_code)
# 将API响应存储在一个变量中
response_dict = r.json()
print("Total repositories:", response_dict['total_count']) ❶
# 探索有关仓库的信息
repo_dicts = response_dict['items'] ❷
print("Repositories returned:", len(repo_dicts))
# 研究第一个仓库
repo_dict = repo_dicts[0] ❸
print("\nKeys:", len(repo_dict)) ❹
for key in sorted(repo_dict.keys()): ❺
print(key)


在❶处,我们打印了与'total_count'相关联的值,它指出了GitHub总共包含多少个Python仓库。
与'items'相关联的值是一个列表,其中包含很多字典,而每个字典都包含有关一个Python仓库的信息。在❷处,我们将这个字典列表存储在repo_dicts中。接下来,我们打印repo_dicts的长度,以获
悉我们获得了多少个仓库的信息。为更深入地了解返回的有关每个仓库的信息,我们提取了
repo_dicts中的第一个字典,并将其存储在repo_dict中(见❸)。接下来,我们打印这个字典包含的键数,看看其中有多少信息(见❹)。在❺处,我们打印这个字典的所有键,看看其中包含哪些
信息。
输出让我们对实际包含的数据有了更清晰的认识:

Status code: 200
Total repositories: 713062
Repositories returned: 30
Keys: 68 ❶
archive_url
assignees_url
blobs_url
--snip--
url
watchers
watchers_count


GitHub的API返回有关每个仓库的大量信息:repo_dict包含68个键(见❶)。通过仔细查看这些键,可大致知道可提取有关项目的哪些信息(要准确地获悉API将返回哪些信息,要么阅读文档,要么像此处这样使用代码来查看这些信息)。
下面来提取repo_dict中与一些键相关联的值:

python_repos.py
--snip--
# 研究有关仓库的信息
repo_dicts = response_dict['items']
print("Repositories returned:", len(repo_dicts))
# 研究第一个仓库
repo_dict = repo_dicts[0]
print("\nSelected information about first repository:")
print('Name:', repo_dict['name']) ❶
print('Owner:', repo_dict['owner']['login']) ❷
print('Stars:', repo_dict['stargazers_count']) ❸
print('Repository:', repo_dict['html_url'])
print('Created:', repo_dict['created_at']) ❹
print('Updated:', repo_dict['updated_at']) ❺
print('Description:', repo_dict['description'])


在这里,我们打印了表示第一个仓库的字典中与很多键相关联的值。
在❶处,我们打印了项目的名称。项目所有者是用一个字典表示的,因此在❷处,我们使用键owner来访问表示所有者的字典,再使用键key来获取所有者的登录名。在❸处,我们打印项目获得了多少个星的评级,以及项目在GitHub仓库的URL。接下来,我们显示项目的创建时间(见❹)和最后一次更新的时间(见❺)。最后,我们打印仓库的描述。输出类似于下面这样:

Status code: 200
Total repositories: 713065
Repositories returned: 30
Selected information about first repository:
Name: httpie
Owner: jkbrzt
Stars: 16101
Repository: https://github.com/jkbrzt/httpie
Created: 2012-02-25T12:39:13Z
Updated: 2015-07-13T14:56:41Z
Description: CLI HTTP client; user-friendly cURL replacement
featuring intuitive UI, JSON support, syntax highlighting, wgetlike
downloads, extensions, etc.


从上述输出可知,编写本书时,GitHub上星级最高的Python项目为HTTPie,其所有者为用户jkbrzt,有16 000多个GitHub用户给这个项目加星。我们可以看到这个项目的仓库的URL,其创建时间为2012年2月,且最近更新了。最后,描述指出HTTPie用于帮助从终端执行HTTP
调用(CLI是命令行界面的缩写)。


17.1.6 概述最受欢迎的仓库


对这些数据进行可视化时,我们需要涵盖多个仓库。下面就来编写一个循环,打印API调用返回的每个仓库的特定信息,以便能够在可视化中包含所有这些信息:

python_repos.py
--snip--
# 研究有关仓库的信息
repo_dicts = response_dict['items']
print("Repositories returned:", len(repo_dicts))
print("\nSelected information about each repository:") ❶
for repo_dict in repo_dicts: ❷
print('\nName:', repo_dict['name'])
print('Owner:', repo_dict['owner']['login'])
print('Stars:', repo_dict['stargazers_count'])
print('Repository:', repo_dict['html_url'])
print('Description:', repo_dict['description'])


在❶处,我们打印了一条说明性消息。在❷处,我们遍历repo_dicts中的所有字典。在这个循环中,我们打印每个项目的名称、所有者、星级、在GitHub上的URL以及描述:

Status code: 200
Total repositories: 713067
Repositories returned: 30
Selected information about each repository:
Name: httpie
Owner: jkbrzt
Stars: 16101
Repository: https://github.com/jkbrzt/httpie
Description: CLI HTTP client; user-friendly cURL replacement
featuring intuitive UI, JSON support, syntax highlighting, wgetlike
downloads, extensions, etc.
Name: django
Owner: django
Stars: 15028
Repository: https://github.com/django/django
Description: The Web framework for perfectionists with deadlines.
--snip--
Name: powerline
Owner: powerline
Stars: 4315
Repository: https://github.com/powerline/powerline
Description: Powerline is a statusline plugin for vim, and
provides statuslines and prompts for several other applications,
including zsh, bash, tmux, IPython, Awesome and Qtile.


上述输出中有一些有趣的项目,可能值得再看一眼。但不要在这上面花费太多时间,因为我们即将创建的可视化可让你更容易地看清结
果。


17.1.7 监视API的速率限制


大多数API都存在速率限制,即你在特定时间内可执行的请求数存在限制。要获悉你是否接近了GitHub的限制,请在浏览器中输入https://api.github.com/rate_limit,你将看到类似于下面的响应:

{
"resources": {
"core": {
"limit": 60,
"remaining": 58,
"reset": 1426082320
},
"search": { ❶
"limit": 10, ❷
"remaining": 8, ❸
"reset": 1426078803 ❹
}
},
"rate": {
"limit": 60,
"remaining": 58,
"reset": 1426082320
}
}


我们关心的信息是搜索API的速率限制(见❶)。从❷处可知,极限为每分钟10个请求,而在当前这一分钟内,我们还可执行8个请求(见❸)。reset值指的是配额将重置的Unix时间或新纪元时间(1970年1月1日午夜后多少秒)(见❹)。用完配额后,你将收到一条简单的响应,由此知道已到达API极限。到达极限后,你必须等待配额重置。
注意 很多API都要求你注册获得API密钥后才能执行API调用。
编写本书时,GitHub没有这样的要求,但获得API密钥后,配额将高得多。


17.2 使用Pygal可视化仓库


有了一些有趣的数据后,我们来进行可视化,呈现GitHub上Python项目的受欢迎程度。我们将创建一个交互式条形图:条形的高度表示项目获得了多少颗星。单击条形将带你进入项目在GitHub上的主页。下面是首次尝试这样做:

python_repos.py
import requests
import pygal
from pygal.style import LightColorizedStyle as LCS, LightenStyle
as LS
# 执行API调用并存储响应
URL = 'https://api.github.com/search/repositories?
q=language:python&sort=star'
r = requests.get(URL)
print("Status code:", r.status_code)
# 将API响应存储在一个变量中
response_dict = r.json()
print("Total repositories:", response_dict['total_count'])
# 研究有关仓库的信息
repo_dicts = response_dict['items']
names, stars = [], [] ❶
for repo_dict in repo_dicts:
names.append(repo_dict['name']) ❷
stars.append(repo_dict['stargazers_count'])
# 可视化
my_style = LS('#333366', base_style=LCS) ❸
chart = pygal.Bar(style=my_style, x_label_rotation=45,
show_legend=False) ❹
chart.title = 'Most-Starred Python Projects on GitHub'
chart.x_labels = names
chart.add('', stars) ❺
chart.render_to_file('python_repos.svg')


我们首先导入了pygal以及要应用于图表的Pygal样式。接下来,打印API调用响应的状态以及找到的仓库总数,以便获悉API调用是否出现了问题。我们不再打印返回的有关项目的信息,因为将通过可视化来呈现这些信息。
在❶处,我们创建了两个空列表,用于存储将包含在图表中的信息。我们需要每个项目的名称,用于给条形加上标签,我们还需要知道项目获得了多少个星,用于确定条形的高度。在循环中,我们将项目的名称和获得的星数附加到这些列表的末尾❷。
接下来,我们使用LightenStyle类(别名LS)定义了一种样式,并将其基色设置为深蓝色(见❸)。我们还传递了实参base_style,以使用LightColorizedStyle类(别名LCS)。然后,我们使用Bar()创建一个简单的条形图,并向它传递了my_style(见❹)。
我们还传递了另外两个样式实参:让标签绕x轴旋转45度(x_label_rotation=45),并隐藏了图例
(show_legend=False),因为我们只在图表中绘制一个数据系列。接下来,我们给图表指定了标题,并将属性x_labels设置为列表names。
由于我们不需要给这个数据系列添加标签,因此在❺处添加数据时,将标签设置成了空字符串。生成的图表如图17-1所示。从中可知,前几个项目的受欢迎程度比其他项目高得多,但所有这些项目在Python生态系统中都很重要。

图17-1 GitHub上受欢迎程度最高的Python项目


17.2.1 改进Pygal图表


下面来改进这个图表的样式。我们将进行多个方面的定制,因此先来稍微调整代码的结构,创建一个配置对象,在其中包含要传递给Bar()的所有定制:

python_repos.py
--snip--
# 可视化
my_style = LS('#333366', base_style=LCS)
my_config = pygal.Config() ❶
my_config.x_label_rotation = 45 ❷
my_config.show_legend = False
my_config.title_font_size = 24 ❸
my_config.label_font_size = 14
my_config.major_label_font_size = 18
my_config.truncate_label = 15 ❹
my_config.show_y_guides = False ❺
my_config.width = 1000 ❻
chart = pygal.Bar(my_config, style=my_style) ❼
chart.title = 'Most-Starred Python Projects on GitHub'
chart.x_labels = names
chart.add('', stars)
chart.render_to_file('python_repos.svg')


在❶处,我们创建了一个Pygal类Config的实例,并将其命名为my_config。通过修改my_config的属性,可定制图表的外观。在❷处,我们设置了两个属性——x_label_rotation和show_legend,它们原来是在创建Bar实例时以关键字实参的方式传递的。在❸处,我们设置了图表标题、副标签和主标签的字体大小。
在这个图表中,副标签是 x 轴上的项目名以及 y 轴上的大部分数字。主标签是 y 轴上为5000整数倍的刻度;这些标签应更大,以与副标签区分开来。在❹处,我们使用truncate_label将较长的项目名缩短为15个字符(如果你将鼠标指向屏幕上被截短的项目名,将显示完整的项目名)。接下来,我们将show_y_guides设置为False,以隐藏图表中的水平线(见❺)。最后,在❻处设置了自定义宽度,让图表更充分地利用浏览器中的可用空间。
在❼处创建Bar实例时,我们将my_config作为第一个实参,从而通过一个实参传递了所有的配置设置。我们可以通过my_config做任意数量的样式和配置修改,而❼处的代码行将保持不变。图17-2显示了重新设置样式后的图表。

图17-2 改进了图表的样式


17.2.2 添加自定义工具提示


在Pygal中,将鼠标指向条形将显示它表示的信息,这通常称为工具提示。在这个示例中,当前显示的是项目获得了多少个星。下面来创建一个自定义工具提示,以同时显示项目的描述。
来看一个简单的示例,它可视化前三个项目,并给每个项目对应的条形都指定自定义标签。为此,我们向add()传递一个字典列表,而不是值列表:

bar_descriptions.py
import pygal
from pygal.style import LightColorizedStyle as LCS, LightenStyle
as LS
my_style = LS('#333366', base_style=LCS)
chart = pygal.Bar(style=my_style, x_label_rotation=45,
show_legend=False)
chart.title = 'Python Projects'
chart.x_labels = ['httpie', 'django', 'flask']
plot_dicts = [ ❶
{'value': 16101, 'label': 'Description of httpie.'}, ❷
{'value': 15028, 'label': 'Description of django.'},
{'value': 14798, 'label': 'Description of flask.'},
]
chart.add('', plot_dicts) ❸
chart.render_to_file('bar_descriptions.svg')

在❶处,我们定义了一个名为plot_dicts的列表,其中包含三个字典,分别针对项目HTTPie、Django和Flask。每个字典都包含两个键:'value'和'label'。Pygal根据与键'value'相关联的数字来
确定条形的高度,并使用与'label'相关联的字符串给条形创建工具提示。例如,❷处的第一个字典将创建一个条形,用于表示一个获得了16 101颗星、工具提示为Description of httpie的项目。
方法add()接受一个字符串和一个列表。这里调用add()时,我们传入了一个由表示条形的字典组成的列表(plot_dicts)(见❸)。
图17-3显示了一个工具提示:除默认工具提示(获得的星数)外,Pygal还显示了我们传入的自定义提示。

图17-3 每个条形都有自定义的工具提示标签


17.2.3 根据数据绘图


为根据数据绘图,我们将自动生成plot_dicts,其中包含API调用返回的30个项目的信息。
完成这种工作的代码如下:

python_repos.py
--snip--
# 研究有关仓库的信息
repo_dicts = response_dict['items']
print("Number of items:", len(repo_dicts))
names, plot_dicts = [], [] ❶
for repo_dict in repo_dicts:
names.append(repo_dict['name'])
plot_dict = { ❷
'value': repo_dict['stargazers_count'],
'label': repo_dict['description'],
}
plot_dicts.append(plot_dict) ❸
# 可视化
my_style = LS('#333366', base_style=LCS)
--snip--
chart.add('', plot_dicts) ❹
chart.render_to_file('python_repos.svg')


在❶处,我们创建了两个空列表names和plot_dicts。为生成x轴上的标签,我们依然需要列表names。
在循环内部,对于每个项目,我们都创建了字典plot_dict(见❷)。在这个字典中,我们使用键'value'存储了星数,并使用键'label'存储了项目描述。接下来,我们将字典plot_dict附加
到plot_dicts末尾(见❸)。在❹处,我们将列表plot_dicts传递给了add()。图17-4显示了生成的图表。

  • 24
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

___Y1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值