文章目录[隐藏]
如何编写独立的程序,对获取的数据进行可视化,这个程序使用Web应用程序编程接口(API)自动请求网站的特定信息而不整个网页。再对这些信息进行可视化,由于这样编写的程序始终使用最新的数据进行可视化,即便数据瞬息万变,它呈现的信息也是最新的。
使用Webapi
Web api是网站的一部分,用于使用具体URL请求特定信息的程序交互,这种请求称为API调用.请求的数据将以易于处理的格式(JSON或者CSV)返回。依赖于外部数据源的大多数应用程序依赖于API调用。如集成社交媒体网站的应用。
Git和GitHub
本章可视化基于GitHub的信息。使用GitHub的API来请求有关该网站中Python项目的信息。再使用Plotly生成交互式可视化图标,呈现这些项目的欢迎程度。
Git(分布式版本控制系统。)
编写一个程序,自动下载GitHub上星级最高的Python项目的信息,并对这些信息进行可视化。
使用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表示查询,而(=)让我们能够开始指定查询,使用language:python 指出只想获取主要语言为Python的仓库的信息。最后&sort=stars指定将项目按星级排序。
total_count:可知,在本文撰写的时候,该GitHub总共有8684364个Python项目。incomplete_results的值为true,由此我们可以发现我们的请求不是完成成功的。当然,我们也可以显示相应的items,其中包含了GitHUb中最受欢迎的Python项目的详细信息。
安装Requests
为了让Python程序能够轻松向网站请求信息并检查返回的响应。
pip install requests
处理API响应
下面编写一个程序,自动执行API调用并处理结果,以找出GitHub上星级最高的Python项目。
import requests
# 执行API调用并存储响应
url = 'https://api.github.com/search/repositories?q=language:python&sort=stars'
headers = {'Accept':'application/vnd.github.v3+json'}
r = requests.get(url,headers=headers)
print(f"Status code:{r.status_code}")
# 将API响应赋给一个变量。
response_dict = r.json()
# 处理结果
print(response_dict.keys())
最新的GitHub API版本为第三版。因此通过指定headers显式地要求使用这个版本的API。再使用requests调用api。
调用get()并将URL传递给它,再将响应对象赋值给变量r。响应对象包含一个名为status_code的属性,指示了请求是个否成功(200 OK).
这个API返回JSON格式的信息。因此使用方法json()将这些信息转换为一个Python字典。并将结果存储再response_dict中。
最后打印response_dict中的键。
这样简单的调用应该会返回完整的结果集,可以忽略'incomplete_results'关联的值。但在执行更复杂的API调用时,应检查。
处理响应字典
将API调用返回的信息储存到字典后,就可以处理其中的数据了。我们来生成一些概述这些信息的输出,可确认收到了期望的信息。
import requests
# 执行API调用并存储响应
url = 'https://api.github.com/search/repositories?q=language:python&sort=stars'
headers = {'Accept':'application/vnd.github.v3+json'}
r = requests.get(url,headers=headers)
print(f"Status code:{r.status_code}")
# 将API响应赋给一个变量。
response_dict = r.json()
# 处理结果
# print(response_dict.keys())
print(f"Total repositories:{response_dict['total_count']}")
# 探索有关仓库的信息
repo_dicts = response_dict['items']
print(f"Respositories returned: {len(repo_dicts)}")
# 研究第一个仓库
repo_dict = repo_dicts[0]
print(f"\nKeys:{len(repo_dict)}")
for key in sorted(repo_dict.keys()):
print(key)
与‘items’关联的值是一个列表。其中包含很多字典。而每个字典都包含一个有关Python仓库的信息。
将这个字典列表存入repo_dicts中。接下来打印repo_dicts长度,以获悉获得了多少仓库的信息。
为了更深入了解每个仓库的信息,提取repo_dicts中第一个字典。
下面来提取repo_dict中一些相关联的值:
import requests
# 执行API调用并存储响应
url = 'https://api.github.com/search/repositories?q=language:python&sort=stars'
headers = {'Accept':'application/vnd.github.v3+json'}
r = requests.get(url,headers=headers)
print(f"Status code:{r.status_code}")
# 将API响应赋给一个变量。
response_dict = r.json()
# 处理结果
# print(response_dict.keys())
print(f"Total repositories:{response_dict['total_count']}")
# 探索有关仓库的信息
repo_dicts = response_dict['items']
print(f"Respositories returned: {len(repo_dicts)}")
# 研究第一个仓库
repo_dict = repo_dicts[0]
# 查看键
# print(f"\nKeys:{len(repo_dict)}")
# for key in sorted(repo_dict.keys()):
# print(key)
print("\nSelected information about first respository:")
print(f"Name: {repo_dict['name']}")
print(f"Owner: {repo_dict['owner']['login']}")
print(f"Stars: {repo_dict['stargazers_count']}")
print(f"Repository: {repo_dict['html_url']}")
print(f"Created: {repo_dict['created_at']}")
print(f"Updated: {repo_dict['updated_at']}")
print(f"Description: {repo_dict['description']}")
概述最受欢迎的仓库
对这些数据进行可视化,想涵盖多个仓库。编写一个循环。
import requests
# 执行API调用并存储响应
url = 'https://api.github.com/search/repositories?q=language:python&sort=stars'
headers = {'Accept':'application/vnd.github.v3+json'}
r = requests.get(url,headers=headers)
print(f"Status code:{r.status_code}")
# 将API响应赋给一个变量。
response_dict = r.json()
# 处理结果
# print(response_dict.keys())
print(f"Total repositories:{response_dict['total_count']}")
# 探索有关仓库的信息
repo_dicts = response_dict['items']
print(f"Respositories returned: {len(repo_dicts)}")
# 研究第一个仓库
# repo_dict = repo_dicts[0]
# 查看键
# print(f"\nKeys:{len(repo_dict)}")
# for key in sorted(repo_dict.keys()):
# print(key)
print("\nSelected information about each repository:")
for repo_dict in repo_dicts:
print("\nSelected information about first respository:")
print(f"Name: {repo_dict['name']}")
print(f"Owner: {repo_dict['owner']['login']}")
print(f"Stars: {repo_dict['stargazers_count']}")
print(f"Repository: {repo_dict['html_url']}")
print(f"Created: {repo_dict['created_at']}")
print(f"Updated: {repo_dict['updated_at']}")
print(f"Description: {repo_dict['description']}")
见识API的速率限制
大多数API存在速率限制,也就是说,在特定时间内可执行的请求数存在限制。要获悉是否接近了GitHub的限制。
https://api.github.com/rate_limit
{
"resources": {
"core": {
"limit": 60,
"remaining": 58,
"reset": 1649346778,
"used": 2,
"resource": "core"
},
"graphql": {
"limit": 0,
"remaining": 0,
"reset": 1649349754,
"used": 0,
"resource": "graphql"
},
"integration_manifest": {
"limit": 5000,
"remaining": 5000,
"reset": 1649349754,
"used": 0,
"resource": "integration_manifest"
},
"search": {
"limit": 10,
"remaining": 10,
"reset": 1649346214,
"used": 0,
"resource": "search"
}
},
"rate": {
"limit": 60,
"remaining": 58,
"reset": 1649346778,
"used": 2,
"resource": "core"
}
}
使用Plotly可视化仓库
创建一个交互式条行图,条行图的高度表示了项目获得了多少颗星,单机条行将带你进入项目在GitHub上的主页。
import requests
from plotly.graph_objs import Bar
from plotly import offline
# 执行API调用并存储响应
url = 'https://api.github.com/search/repositories?q=language:python&sort=stars'
headers = {'Accept':'application/vnd.github.v3+json'}
r = requests.get(url,headers=headers)
print(f"Status code:{r.status_code}")
# 将API响应赋给一个变量。
response_dict = r.json()
# 处理结果
# print(response_dict.keys())
print(f"Total repositories:{response_dict['total_count']}")
# 探索有关仓库的信息
repo_dicts = response_dict['items']
repo_names,stars = [],[]
for repo_dict in repo_dicts:
repo_names.append(repo_dict['name'])
stars.append(repo_dict['stargazers_count'])
# 可视化
data = [{
'type':'bar',
'x':repo_names,
'y':stars,
}]
my_layout = {
'title':'GitHub上最受欢迎的Python项目',
'xaxis':{'title':'Repository'},
'yaxis':{'title':'Stars'},
}
fig = {'data':data,'layout':my_layout}
offline.plot(fig,filename='python_repos.html')
导入了Plotly中的Bar类和模块offline。
改进Plotly图表
通过修改data,可定制条行。下面是修改后的data,给条行指定了颜色和边框。
'masker':{
'color':'rgb(60,100,150)',
'line':{'width':1.5,'color':'rgb(25,25,25)'}
},
'opacity':0.6,
marker设置影响条行设计,给条形制定了一种自定义的蓝色。加上宽1.5像素的深灰色轮廓,将条行的不透明设置为0.6.
my_layout = {
'title':'GitHub上最受欢迎的Python项目',
'titlefont':{'size':28},
'xaxis':{
'title':'Repository',
'titlefont':{'size':24},
'tickfont':{'size':14},
},
'yaxis':{
'title':'Stars',
'titlefont':{'size':24},
'tickfont':{'size':14},
},
}
‘titlefont’指定图标名称的资好。
x轴标签资好‘titlefont’
和刻度标签字号的设置‘tickfont’
类比,可以以此设置颜色等。
添加自定义工具提示
在Plotly中,将鼠标指向条形显示其表示的信息。这通常称为工具提示。
import requests
from plotly.graph_objs import Bar
from plotly import offline
# 执行API调用并存储响应
url = 'https://api.github.com/search/repositories?q=language:python&sort=stars'
headers = {'Accept':'application/vnd.github.v3+json'}
r = requests.get(url,headers=headers)
print(f"Status code:{r.status_code}")
# 将API响应赋给一个变量。
response_dict = r.json()
# 处理结果
# print(response_dict.keys())
print(f"Total repositories:{response_dict['total_count']}")
# 探索有关仓库的信息
repo_dicts = response_dict['items']
repo_names,stars,labels = [],[],[]
for repo_dict in repo_dicts:
repo_names.append(repo_dict['name'])
stars.append(repo_dict['stargazers_count'])
owner = repo_dict['owner']['login']
description = repo_dict['description']
label = f"{owner}<br />{description}"
labels.append(label)
# 可视化
data = [{
'type':'bar',
'x':repo_names,
'y':stars,
'hovertext':labels,
'marker':{
'color':'rgb(60,100,150)',
'line':{'width':1.5,'color':'rgb(25,25,25)'}
},
'opacity':0.6,
}]
my_layout = {
'title':'GitHub上最受欢迎的Python项目',
'titlefont':{'size':28},
'xaxis':{
'title':'Repository',
'titlefont':{'size':24},
'tickfont':{'size':14},
},
'yaxis':{
'title':'Stars',
'titlefont':{'size':24},
'tickfont':{'size':14},
},
}
fig = {'data':data,'layout':my_layout}
offline.plot(fig,filename='python_repos.html')
Plotly允许在文本元素中使用HTML代码,因此,在创建由项目所有者和描述组成的字符串时,能够在两部分之间添加换行符(
),然后将这个字符串附加到labels末尾。
在图表中添加可单机的链接
Plotly允许在文本元素中使用HTML代码,能够轻松的在图表中添加链接,将x轴标签作为连接。
import requests
from plotly.graph_objs import Bar
from plotly import offline
# 执行API调用并存储响应
url = 'https://api.github.com/search/repositories?q=language:python&sort=stars'
headers = {'Accept':'application/vnd.github.v3+json'}
r = requests.get(url,headers=headers)
print(f"Status code:{r.status_code}")
# 将API响应赋给一个变量。
response_dict = r.json()
# 处理结果
# print(response_dict.keys())
print(f"Total repositories:{response_dict['total_count']}")
# 探索有关仓库的信息
repo_dicts = response_dict['items']
repo_names,stars,labels,repo_links = [],[],[],[]
for repo_dict in repo_dicts:
# repo_names.append(repo_dict['name'])
repo_name = repo_dict['name']
repo_url = repo_dict['html_url']
repo_link = f"<a href='{repo_url}'>{repo_name}</a>"
repo_links.append(repo_link)
stars.append(repo_dict['stargazers_count'])
owner = repo_dict['owner']['login']
description = repo_dict['description']
label = f"{owner}<br />{description}"
labels.append(label)
# 可视化
data = [{
'type':'bar',
'x':repo_links,
'y':stars,
'hovertext':labels,
'marker':{
'color':'rgb(60,100,150)',
'line':{'width':1.5,'color':'rgb(25,25,25)'}
},
'opacity':0.6,
}]
my_layout = {
'title':'GitHub上最受欢迎的Python项目',
'titlefont':{'size':28},
'xaxis':{
'title':'Repository',
'titlefont':{'size':24},
'tickfont':{'size':14},
},
'yaxis':{
'title':'Stars',
'titlefont':{'size':24},
'tickfont':{'size':14},
},
}
fig = {'data':data,'layout':my_layout}
offline.plot(fig,filename='python_repos.html')
深入了解Plotly和GitHub API
要更深入了解如何生成Plotly图标,可在Plotly User Guide in Python(深入了解Plotly是如何使用数据生成可视化图表的,以及它采取这种做法的原因)
Plotly网站中的Python Figure Reference,其中列出了可用来配置Plotly可视化的所有设置,还列出了所有的图标类型,以及在各个配置选项中可设置的属性。
Hacker News API
Hacker News的API能够让访问有关该网站所有文章和评论的信息,且不要求通过注册获得密钥。
下面调用返回最热门的文章的信息:
https://hacker-news.firebaseio.com/v0/item/8863.json?print=pretty
import requests
import json
# 执行API调用并存储响应
url = 'https://hacker-news.firebaseio.com/v0/item/8863.json?print=pretty'
r = requests.get(url)
print(f"Status code:{r.status_code}")
# 探索数据的结构
response_dict = r.json()
readable_file = 'readable_hn_data.json'
with open(readable_file,'w') as f:
json.dump(response_dict,f,indent=4)
{
"by": "dhouston",
"descendants": 71,
"id": 8863,
"kids": [
9224,
8917,
8952,
8958,
8884,
8887,
8869,
8873,
8940,
8908,
9005,
9671,
9067,
9055,
8865,
8881,
8872,
8955,
10403,
8903,
8928,
9125,
8998,
8901,
8902,
8907,
8894,
8870,
8878,
8980,
8934,
8943,
8876
],
"score": 104,
"time": 1175714200,
"title": "My YC app: Dropbox - Throw away your USB drive",
"type": "story",
"url": "http://www.getdropbox.com/u/2/screencast.html"
}
'descendants'相关联的值是文章被评论的次数,与键‘kids’相关联的值包含文章所有评论ID,
https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty
上述api返回热门文章。
组合起来
from operator import itemgetter
import requests
import json
# 执行API调用并存储响应
url = 'https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty'
r = requests.get(url)
print(f"Status code:{r.status_code}")
# 处理有关每篇文章的信息
submission_ids = r.json()
submission_dicts = []
for submission_id in submission_ids[:5]:
# 对每篇文章都,都执行一个API调用
url = f"https://hacker-news.firebaseio.com/v0/item/{submission_id}.json?print=pretty"
r = requests.get(url)
print(f"id:{submission_id}\tstatus:{r.status_code}")
response_dict = r.json()
# 对每篇文章,都创建一个字典
submission_dict = {
'title': response_dict['title'],
'hn_link':f"https://hacker-news.firebaseio.com/v0/item/{submission_id}.json?print=pretty",
'comments':response_dict['descendants'],
}
submission_dicts.append(submission_dict)
submission_dicts = sorted(submission_dicts,key=itemgetter('comments'),reverse=True)
for submission_dict in submission_dicts:
print(f"\nTitle:{submission_dict['title']}")
print(f"Discussion link:{submission_dict['hn_link']}")
print(f"Coments:{submission_dict['comments']}")
Hacker News上的文章是根据总体得分排名的,而总体得分取决于很多因素,包含被推荐的次数、评论数和发表时间。根据评论数对字典列表submission_dicts进行排序,使用模块operator中的函数itemgetter().向这个函数传递了键‘comments’,因此它从该列表上的每个字典中提取与'comments'关联的值。这样,函数‘sorted()’将根据这个值对列表进行排序。将按照列表降序排列,评论最多的文章位于最前面。
无论使用哪个API来访问和分析信息,流程都与此类似。有了这些数据后,就可进行可视化,指出最近哪些文章引发了最激烈的讨论,基于这种方式,应用程序为用户提供网站的定制化阅读体验。
小结
使用API编写独立的程序。以自动化采集所需的数据并对其镜像可视化。
叨叨几句... NOTHING