文章目录
一.使用api
在博客中,你将学习如何编写一个独立的程序,并对其获取的数据进行可视化。这个程序将使用Web应用编程接口 (API)自动请求网站的特定信息而不是整个网页,再对这些信息进行可视化。由于这样编写的程序始终使用最新的数据来生成可视化,因此即便数据瞬息万变,它呈现的信息也都是最新的。
1.1 使用 Web API
Web API是网站的一部分,用于与使用非常具体的URL请求特定信息的程序交互。这种请求称为API调用。请求的数据将以易于处理的格式(如JSON或CSV)返回。依赖于外部数据源的大多数应用程序都依赖于API调用,如集成社交媒体网站的应用程序。
1.1.1 Git和GitHub
本博客的可视化将基于来自GitHub的信息,这是一个让程序员能够协作开发项目的网站。我们将使用GitHub的API来请求有关该网站中Python项目的信息,然后使用Pygal生成交互式可视化,以呈现这些项目的受欢迎程度。
GitHub(https://github.com/ )的名字源自Git,Git是一个分布式版本控制系统,让程序员团队能够协作开发项目。Git帮助大家管理为项目所做的工作,避免一个人所做的修改影响其他人所做的修改。你在项目中实现新功能时,Git将跟踪你对每个文件所做的修改。确定代码可行后,你提交所做的修改,而Git将记录项目最新的状态。如果你犯了错,想撤销所做的修改,可轻松地返回以前的任何可行状态。GitHub上的项目都存储在仓库中,后者包含与项目相关联的一切:代码、项目参与者的信息、问题或bug报告等。
对于喜欢的项目,GitHub用户可给它加星(star)以表示支持,用户还可跟踪他可能想使用的项目。在本章中,我们将编写一个程序,它自动下载GitHub上星级最高的Python项目的信息,并对这些信息进行可视化。
1.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": 6568600,
"incomplete_results": false,
"items": [
{
"id": 3544424,
"name": "httpie",
"full_name": "jkbrzt/httpie",
--snip--
从第二行输出可知,编写本书时,GitHub总共有6568600个Python项目。“incomplete_results” 的值为false ,据此我们知道请求是成功的(它并非不完整的)。倘若GitHub无法全面处理该API,它返回的这个值将为true 。接下来的列表中显示了返回的"items" ,其中包含GitHub上最受欢迎的Python项目的详细信息。
1.1.3 安装requests
requests包让Python程序能够轻松地向网站请求信,息以及检查返回的响应。要安装requests,请执行类似于下面的命令
C:\>pip install requests
Collecting requests
Using cached requests-2.25.1-py2.py3-none-any.whl (61 kB)
Requirement already satisfied: urllib3<1.27,>=1.21.1 in c:\users\administrator\appdata\local\programs\python\python36\lib\site-packages (from requests) (1.25.3)
Requirement already satisfied: idna<3,>=2.5 in c:\users\administrator\appdata\local\programs\python\python36\lib\site-packages (from requests) (2.8)
Requirement already satisfied: certifi>=2017.4.17 in c:\users\administrator\appdata\local\programs\python\python36\lib\site-packages (from requests) (2019.6.16)
Requirement already satisfied: chardet<5,>=3.0.2 in c:\users\administrator\appdata\local\programs\python\python36\lib\site-packages (from requests) (3.0.4)
Installing collected packages: requests
Successfully installed requests-2.25.1
1.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())
测试记录:
E:\python\learn_python1\venv\Scripts\python.exe E:/python/learn_python1/数据可视化/python_repos.py
Status code: 200
dict_keys(['total_count', 'incomplete_results', 'items'])
Process finished with exit code 0
状态码为200,因此我们知道请求成功了。响应字典只包含三个键:‘items’ 、‘total_count’ 和’incomplete_results’ 。
1.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)
测试记录:
E:\python\learn_python1\venv\Scripts\python.exe E:/python/learn_python1/数据可视化/python_repos.py
Status code: 200
Total repositories: 6921001
Repositories returned: 30
Keys: 74
archive_url
archived
assignees_url
blobs_url
branches_url
clone_url
collaborators_url
comments_url
commits_url
compare_url
contents_url
contributors_url
created_at
default_branch
deployments_url
description
disabled
downloads_url
events_url
fork
forks
forks_count
forks_url
full_name
git_commits_url
git_refs_url
git_tags_url
git_url
has_downloads
has_issues
has_pages
has_projects
has_wiki
homepage
hooks_url
html_url
id
issue_comment_url
issue_events_url
issues_url
keys_url
labels_url
language
languages_url
license
merges_url
milestones_url
mirror_url
name
node_id
notifications_url
open_issues
open_issues_count
owner
private
pulls_url
pushed_at
releases_url
score
size
ssh_url
stargazers_count
stargazers_url
statuses_url
subscribers_url
subscription_url
svn_url
tags_url
teams_url
trees_url
updated_at
url
watchers
watchers_count
Process finished with exit code 0
我们打印了与’total_count’ 相关联的值,它指出了GitHub总共包含多少个Python仓库。与’items’ 相关联的值是一个列表,其中包含很多字典,而每个字典都包含有关一个Python仓库的信息,我们将这个字典列表存储在repo_dicts 中。接下来,我们打印repo_dicts 的长度,以获悉我们获得了多少个仓库的信息。
为更深入地了解返回的有关每个仓库的信息,我们提取了repo_dicts 中的第一个字典,并将其存储在repo_dict 中。接下来,我们打印这个字典包含的键数,看看其中有多少信息。在们打印这个字典的所有键,看看其中包含哪些信息。
GitHub的API返回有关每个仓库的大量信息:repo_dict 包含74个键。通过仔细查看这些键,可大致知道可提取有关项目的哪些信息(要准确地获悉API将返回哪些信息,要么阅读文档,要么像此处这样使用代码来查看这些信息)。
下面来提取repo_dict 中与一些键相关联的值:
代码:
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("\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'])
测试记录:
E:\python\learn_python1\venv\Scripts\python.exe E:/python/learn_python1/数据可视化/python_repos.py
Status code: 200
Total repositories: 6940014
Repositories returned: 30
Selected information about first repository:
Name: system-design-primer
Owner: donnemartin
Stars: 125159
Repository: https://github.com/donnemartin/system-design-primer
Created: 2017-02-26T16:15:28Z
Updated: 2021-03-31T09:34:13Z
Description: Learn how to design large-scale systems. Prep for the system design interview. Includes Anki flashcards.
Process finished with exit code 0
从上述输出可知,编写本书时,GitHub上星级最高的Python项目为system-design-primer,其所有者为用户donnemartin,有125159多个GitHub用户给这个项目加星。我们可以看到这个项目的仓库的
URL,其创建时间为2017年2月,且最近更新了。
1.1.6 概述最受欢迎的仓库
对这些数据进行可视化时,我们需要涵盖多个仓库。下面就来编写一个循环,打印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))
print("\nSelected information about first 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('Created:', repo_dict['created_at'])
print('Updated:', repo_dict['updated_at'])
print('Description:', repo_dict['description'])
测试记录:
E:\python\learn_python1\venv\Scripts\python.exe E:/python/learn_python1/数据可视化/python_repos.py
Status code: 200
Total repositories: 6781315
Repositories returned: 30
Selected information about first repository:
Name: system-design-primer
Owner: donnemartin
Stars: 125206
Repository: https://github.com/donnemartin/system-design-primer
Created: 2017-02-26T16:15:28Z
Updated: 2021-04-01T01:21:20Z
Description: Learn how to design large-scale systems. Prep for the system design interview. Includes Anki flashcards.
Name: public-apis
Owner: public-apis
Stars: 115703
Repository: https://github.com/public-apis/public-apis
Created: 2016-03-20T23:49:42Z
Updated: 2021-04-01T01:30:02Z
Description: A collective list of free APIs
Name: Python
Owner: TheAlgorithms
Stars: 101613
Repository: https://github.com/TheAlgorithms/Python
Created: 2016-07-16T09:44:01Z
Updated: 2021-04-01T01:19:17Z
Description: All Algorithms implemented in Python
Name: Python-100-Days
Owner: jackfrued
Stars: 101195
Repository: https://github.com/jackfrued/Python-100-Days
Created: 2018-03-01T16:05:52Z
Updated: 2021-04-01T01:19:24Z
Description: Python - 100天从新手到大师
--snip--
Name: Deep-Learning-Papers-Reading-Roadmap
Owner: floodsung
Stars: 29571
Repository: https://github.com/floodsung/Deep-Learning-Papers-Reading-Roadmap
Created: 2016-10-14T11:49:48Z
Updated: 2021-03-31T22:26:52Z
Description: Deep Learning papers reading roadmap for anyone who are eager to learn this amazing tech!
Process finished with exit code 0
1.1.7 监视API的速率限制
大多数API都存在速率限制,即你在特定时间内可执行的请求数存在限制。要获悉你是否接近了GitHub的限制,请在浏览器中输入https://api.github.com/rate_limit ,你将看到类似于下面的响应
{
"resources": {
"core": {
"limit": 60,
"remaining": 60,
"reset": 1617245499,
"used": 0
},
"graphql": {
"limit": 0,
"remaining": 0,
"reset": 1617245499,
"used": 0
},
"integration_manifest": {
"limit": 5000,
"remaining": 5000,
"reset": 1617245499,
"used": 0
},
"search": {
"limit": 10,
"remaining": 10,
"reset": 1617241959,
"used": 0
}
},
"rate": {
"limit": 60,
"remaining": 60,
"reset": 1617245499,
"used": 0
}
}
我们关心的信息是搜索API的速率限制。限为每分钟10个请求,而在当前这一分钟内,我们还可执行10个请求。reset 值指的是配额将重置的Unix时间或新纪元时间 (1970年1月1日午夜后多少秒)。用完配额后,你将收到一条简单的响应,由此知道已到达API极限。到达极限后,你必须等待配额重置。
注意 很多API都要求你注册获得API密钥后才能执行API调用。目前,GitHub没有这样的要求,但获得API密钥后,配额将高得多。
1.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=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']
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-Started Python Projects on Github'
chart.x_labels = names
chart.add('', stars)
chart.render_to_file('python_repos.svg')
测试记录:
1.2.1 改进Pygal图表
下面来改进这个图表的样式。我们将进行多个方面的定制,因此先来稍微调整代码的结构,创建一个配置对象,在其中包含要传递给Bar() 的所有定制
代码:
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=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']
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)
my_config = pygal.Config()
my_config.x_label_rotation = 45
my_config.show_legend = False
my_config.title_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-Started 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 做任意数量的样式和配置修改,代码行将保持不变。
1.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 = ['httpid', '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')
测试记录:
1.2.3 根据数据绘图
为根据数据绘图,我们将自动生成plot_dicts ,其中包含API调用返回的30个项目的信息。
完成这种工作的代码如下:
代码:
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=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("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': str(repo_dict['description']),
}
plot_dicts.append(plot_dict)
# 可视化
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 = 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-Started Python Projects on Github'
chart.x_labels = names
chart.add('', plot_dicts)
chart.render_to_file('python_repos.svg')
测试记录:
1.2.4 在图表中添加可单击的链接
Pygal还允许你将图表中的每个条形用作网站的链接。为此,只需添加一行代码,在为每个项目创建的字典中,添加一个键为’xlink’ 的键—值对
代码:
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=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("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': str(repo_dict['description']),
'xlink': repo_dict['html_url'],
}
plot_dicts.append(plot_dict)
# 可视化
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 = 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-Started Python Projects on Github'
chart.x_labels = names
chart.add('', plot_dicts)
chart.render_to_file('python_repos.svg')
测试记录:
1.3 Hacker News API
为探索如何使用其他网站的API调用,我们来看看Hacker News(http://news.ycombinator.com/ )。在Hacker News网站,用户分享编程和技术方面的文章,并就这些文章展开积极的讨论。Hacker News的API让你能够访问有关该网站所有文章和评论的信息,且不要求你通过注册获得密钥。
下面的调用返回本书编写时最热门的文章的信息:
https://hacker-news.firebaseio.com/v0/item/9884165.json
网站无法访问,这个案例暂时先不做。
参考
1.Python编程:从入门到实践