使用API

发布于 2022-04-07  491 次阅读


如何编写独立的程序,对获取的数据进行可视化,这个程序使用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

file
这个调用返回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())

file
最新的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)

file
与‘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']}")

file

概述最受欢迎的仓库

对这些数据进行可视化,想涵盖多个仓库。编写一个循环。

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

file

见识API的速率限制

大多数API存在速率限制,也就是说,在特定时间内可执行的请求数存在限制。要获悉是否接近了GitHub的限制。

https://api.github.com/rate_limit

file

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

file
导入了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},
    },
}

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

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

file

深入了解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']}")

file
Hacker News上的文章是根据总体得分排名的,而总体得分取决于很多因素,包含被推荐的次数、评论数和发表时间。根据评论数对字典列表submission_dicts进行排序,使用模块operator中的函数itemgetter().向这个函数传递了键‘comments’,因此它从该列表上的每个字典中提取与'comments'关联的值。这样,函数‘sorted()’将根据这个值对列表进行排序。将按照列表降序排列,评论最多的文章位于最前面。
无论使用哪个API来访问和分析信息,流程都与此类似。有了这些数据后,就可进行可视化,指出最近哪些文章引发了最激烈的讨论,基于这种方式,应用程序为用户提供网站的定制化阅读体验。

小结

使用API编写独立的程序。以自动化采集所需的数据并对其镜像可视化。


擦肩而过的概率