Python编程-数据可视化:第17章-使用Web API

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

github 官方参考链接

搜索 - GitHub Docs

使用API调用请求的数据

https://api.github.com/search/repositories?q=language:python&sort=stars

这个调用返回GitHub当前托管了多少个Python项目,以及有关最受欢迎的Python仓库的信息。
url 说明

部分 说明
https://api.github.com/ 将请求发送到GItHub网站中响应API调用的部分。
search/repositories 让API搜索Github上所有仓库。
?q= q表示查询,而等号(=)让我们能够开始指定查询。
language:python 表示只想获取主要语言为python 的仓库信息
&sort=stars 表示将项目按照星级排序。

调用后结果
json 的格式和说明请参见JSON

{
  "total_count": 8952515,
  "incomplete_results": true,
  "items": [
    {
      "id": 63476337,
      "node_id": "MDEwOlJlcG9zaXRvcnk2MzQ3NjMzNw==",
      "name": "Python",
      "full_name": "TheAlgorithms/Python",
输出 说明
"total_count": 8952515 GitHub 总共有8952515项目
"incomplete_results": true 请求是成功的,但是不完整
"items": 返回的items 就是github 最受欢迎的项目详细信息

安装Requests

使用IDE 下载包
PyCharm 2022.2.2|300
或者使用命令行

python -m pip install --user 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())

序号 说明
1 导入requests 包
2 存储API调用的URL
3 由于Github API 版本为第3版,所以要显示指定
4 使用requests.get 调用API
5 如果调用成功会返回一个status_code
6 API 返回JSON 格式的信息,所以需要使用json() 方法转为一个字典
7 打印字典

输出:

Status code: 200
dict_keys(['total_count', 'incomplete_results', 'items'])

状态为200, 说明请求成功了。 字典包含三个键:'total_count','incomplete_results,'items'

Warning

处理响应字典

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上python 项目的个数
print(f"Total repositories: {response_dict['total_count']}")
# 探索有关仓库的信息。
repo_dicts = response_dict['items']
print(f"Repositories returned: {len(repo_dicts)}")
# 研究第一个仓库。
#repo_dict = repo_dicts[0]
#print(f"\nKeys: {len(repo_dict)}")
for repo_dict in repo_dicts:
#    print(key)
    print(f"\nSelected information about first repository:")
    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"Updated: {repo_dict['updated_at']}")
    print(f"Description: {repo_dict['description']}")

监视API 的速率限制

{
  "resources": {
    "core": {
      "limit": 60,
      "remaining": 60,
      "reset": 1665731894,
      "used": 0,
      "resource": "core"
    },
    "graphql": {
      "limit": 0,
      "remaining": 0,
      "reset": 1665731894,
      "used": 0,
      "resource": "graphql"
    },
    "integration_manifest": {
      "limit": 5000,
      "remaining": 5000,
      "reset": 1665731894,
      "used": 0,
      "resource": "integration_manifest"
    },
    "search": {
      "limit": 10,
      "remaining": 10,
      "reset": 1665728354,
      "used": 0,
      "resource": "search"
    }
  },
  "rate": {
    "limit": 60,
    "remaining": 60,
    "reset": 1665731894,
    "used": 0,
    "resource": "core"
  }
}

Warning

这里关注一下search 的限制。limit : 每分钟10 个请求。在当前分钟内,还可以执行10 个请求。

使用Plotly 可视化仓库

import requests
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}")
# 处理结果。
response_dict = r.json()
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,
    # marker 设置条形设计.
    'marker': {
        # 设置柱状图的填充颜色。
        'color': 'rgb(60, 100, 150)',
        # 设置条形边框的颜色和粗细。
        'line': {'width': 1.5, 'color': 'rgb(25,25,25)'},
    },
    'opacity': 0.6,
}]
my_layout = {
    'title': 'GitHub上最受欢迎的Python项目。',
    'xaxis': {'title': 'Rrepository',
              # X轴标题大小。
              'titlefont': {'size': 24},
              # X 轴刻度字体大小。
              'tickfont': {'size': 14},
              },
    'yaxis': {'title': 'Stars',
              # y 轴标题大小。
              'titlefont': {'size': 24},
              # X 轴刻度字体大小。
              'tickfont': {'size': 14},
              },
}
fig = {'data': data, 'layout': my_layout}
offline.plot(fig, filename='python_repos.html')

添加自定义工具提示

当前显示的是项目获得了多少个星。下面来创建自定义工具提示,以显示项目的描述和所有者。

import requests
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}")
# 处理结果。
response_dict = r.json()
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']
    desciption = repo_dict['description']
    # 拼接成一个段落
    label = f"{owner}<br />{desciption}"
    # 添加到labels 列表中。
    labels.append(label)


# 可视化。
data = [{
    'type': 'bar',
    'x': repo_names,
    'y': stars,
    # 条形的自定义显示文本。
    'hovertext': labels,
    # marker 设置条形设计.
    'marker': {
        # 设置柱状图的填充颜色。
        'color': 'rgb(60, 100, 150)',
        # 设置条形边框的颜色和粗细。
        'line': {'width': 1.5, 'color': 'rgb(25,25,25)'},
    },
    'opacity': 0.6,
}]
my_layout = {
    'title': 'GitHub上最受欢迎的Python项目。',
    'xaxis': {'title': 'Rrepository',
              # X轴标题大小。
              'titlefont': {'size': 24},
              # X 轴刻度字体大小。
              'tickfont': {'size': 14},
              },
    'yaxis': {'title': 'Stars',
              # y 轴标题大小。
              'titlefont': {'size': 24},
              # X 轴刻度字体大小。
              'tickfont': {'size': 14},
              },
}
fig = {'data': data, 'layout': my_layout}
offline.plot(fig, filename='python_repos.html')

在图表中添加客单击的链接

import requests
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}")
# 处理结果。
response_dict = r.json()
repo_dicts = response_dict['items']
repo_names, stars, labels, repo_links = [], [], [], []
for repo_dict in repo_dicts:
    repo_names.append(repo_dict['name'])
    # 生成linkes 存入到repo_links 列表中。
    repo_name = repo_dict['name']
    repo_url = repo_dict['html_url']
    # 这里使用了HTML 语法,创建了一个HTML 链接,显示名称为repo_name ,指向 对应项目链接。
    repo_link = f"<a href='{repo_url}' > {repo_name} </a>"
    repo_links.append(repo_link)
    # stars
    stars.append(repo_dict['stargazers_count'])
    # 从每个项目中获取用户,和项目的描述信息。
    owner = repo_dict['owner']['login']
    desciption = repo_dict['description']
    # 拼接成一个段落
    label = f"{owner}<br />{desciption}"
    # 添加到labels 列表中。
    labels.append(label)


# 可视化。
data = [{
    'type': 'bar',
    'x': repo_links,
    'y': stars,
    # 条形的自定义显示文本。
    'hovertext': labels,
    # marker 设置条形设计.
    'marker': {
        # 设置柱状图的填充颜色。
        'color': 'rgb(60, 100, 150)',
        # 设置条形边框的颜色和粗细。
        'line': {'width': 1.5, 'color': 'rgb(25,25,25)'},
    },
    'opacity': 0.6,
}]
my_layout = {
    'title': 'GitHub上最受欢迎的Python项目。',
    'xaxis': {'title': 'Rrepository',
              # X轴标题大小。
              'titlefont': {'size': 24},
              # X 轴刻度字体大小。
              'tickfont': {'size': 14},
              },
    'yaxis': {'title': 'Stars',
              # y 轴标题大小。
              'titlefont': {'size': 24},
              # X 轴刻度字体大小。
              'tickfont': {'size': 14},
              },
}
fig = {'data': data, 'layout': my_layout}
offline.plot(fig, filename='python_repos.html')

深入了解Plotly he GitHub API

API#GITHUB API 说明链接
Getting started with plotly in Python

Hacker News API

分析Hacker News 网站的API

让返回的JSON 更好阅读

import requests
import json
# 执行API 调用并存储响应。
url = 'https://hacker-news.firebaseio.com/v0/item/19155826.json'
response = requests.get(url)
print(f"Status code: {response.status_code}")

# 探索数据的结构。
response_dict = response.json()
print(response_dict)
file_name = 'data/readable_hn_data.json'
with open(file_name,'w') as file_object:
    json.dump(response_dict, file_object, indent=4)

返回的信息

{
    "by": "jimktrains2",
    "descendants": 221,
    "id": 19155826,
    "kids": [
        19156572,
        19158857,
        19156773,
        19157251,
        19156415,
  --snip--
    ],
    "score": 728,
    "time": 1550085414,
    "title": "Nasa\u2019s Mars Rover Opportunity Concludes a 15-Year Mission",
    "type": "story",
    "url": "https://www.nytimes.com/2019/02/13/science/mars-opportunity-rover-dead.html"
}

key 说明
"by": "jimktrains2" 作者
"descendants": 221 评论数
"kids": 列表
"score": 728 评分
"time": 1550085414 时间
"title": 文章的标题
"type": 文章的类型
"url": 文章的链接

练习题

练习17-1:其他语言 修改python_repos.py中的API调用,使其在生成的图表中显示其他语言最受欢迎的项目。请尝试语言JavaScript、Ruby、C、Java、Perl、Haskell和Go。

import requests
from plotly import offline

language = 'JavaScript'
# 执行API 调用并存储响应。
url = f"https://api.github.com/search/repositories?q=language:{language}&sort=stars"
headers = {'Accept': 'application/vnd.github.v3+json'}
r = requests.get(url, headers=headers)
print(f"Status code: {r.status_code}")
# 处理结果。
response_dict = r.json()
repo_dicts = response_dict['items']
repo_names, stars, labels, repo_links = [], [], [], []
for repo_dict in repo_dicts:
    repo_names.append(repo_dict['name'])
    # 生成linkes 存入到repo_links 列表中。
    repo_name = repo_dict['name']
    repo_url = repo_dict['html_url']
    # 这里使用了HTML 语法,创建了一个HTML 链接,显示名称为repo_name ,指向 对应项目链接。
    repo_link = f"<a href='{repo_url}' > {repo_name} </a>"
    repo_links.append(repo_link)
    # stars
    stars.append(repo_dict['stargazers_count'])
    # 从每个项目中获取用户,和项目的描述信息。
    owner = repo_dict['owner']['login']
    desciption = repo_dict['description']
    # 拼接成一个段落
    label = f"{owner}<br />{desciption}"
    # 添加到labels 列表中。
    labels.append(label)


# 可视化。
data = [{
    'type': 'bar',
    'x': repo_links,
    'y': stars,
    # 条形的自定义显示文本。
    'hovertext': labels,
    # marker 设置条形设计.
    'marker': {
        # 设置柱状图的填充颜色。
        'color': 'rgb(60, 100, 150)',
        # 设置条形边框的颜色和粗细。
        'line': {'width': 1.5, 'color': 'rgb(25,25,25)'},
    },
    'opacity': 0.6,
}]
my_layout = {
    'title': f"GitHub上最受欢迎的{language}项目。",
    'xaxis': {'title': 'Rrepository',
              # X轴标题大小。
              'titlefont': {'size': 24},
              # X 轴刻度字体大小。
              'tickfont': {'size': 14},
              },
    'yaxis': {'title': 'Stars',
              # y 轴标题大小。
              'titlefont': {'size': 24},
              # X 轴刻度字体大小。
              'tickfont': {'size': 14},
              },
}
fig = {'data': data, 'layout': my_layout}
offline.plot(fig, filename='python_repos.html')

练习17-2:最活跃的讨论 使用hn_submissions.py中的数据,创建一个条形图,显示Hacker News上当前最活跃的讨论。条形的高度应对应于文章的评论数。条形的标签应包含文章的标题,并且充当到文章讨论页面的链接。

from operator import itemgetter
from plotly import offline

import requests

# 执行API 调用并存储响应。
url = 'https://hacker-news.firebaseio.com/v0/topstories.json'
response_top = requests.get(url)
print(f"Status code: {response_top.status_code}")

# 处理有关每篇文章的信息。
submission_ids = response_top.json()
submission_dicts = []
for submission_id in submission_ids[:30]:
    # 对于每篇文章,都执行一个API调用。
    url = f"https://hacker-news.firebaseio.com/v0/item/{submission_id}.json"
    response = requests.get(url)
    print(f"id: {submission_id}\tstatus: {response.status_code}")
    response_dict = response.json()

    # 对于每篇文章,都创建一部字典。

    submission_dict = {
        'by': response_dict['by'],
        'title': response_dict['title'],
        'hn_link': f"https://news.ycombinator.com/item?id={submission_id}",
        'comments': response_dict['descendants'],
    }
    submission_dicts.append(submission_dict)
submission_dicts = sorted(submission_dicts, key=itemgetter('comments'), reverse=True)

titles, comments, hn_links, bys, labels = [], [], [], [], []
for submission_dict in submission_dicts:
    titles.append(submission_dict['title'])
    hn_links.append(submission_dict['hn_link'])
    comments.append(submission_dict['comments'])
    bys.append(submission_dict['by'])
    # label setting
    title = submission_dict['title']
    hn_link = submission_dict['hn_link']
    label = f"{title}<br />{hn_link}"
    labels.append(label)

# 可视化。
data = [{
    'type': 'bar',
    'x': bys,
    'y': comments,
    # 条形的自定义显示文本。
    'hovertext': labels,
    # marker 设置条形设计.
    'marker': {
        # 设置柱状图的填充颜色。
        'color': 'rgb(60, 100, 150)',
        # 设置条形边框的颜色和粗细。
        'line': {'width': 1.5, 'color': 'rgb(25,25,25)'},
    },
    'opacity': 0.6,
}]
my_layout = {
    'title': 'hn news ',
    'xaxis': {'title': 'Rrepository',
              # X轴标题大小。
              'titlefont': {'size': 24},
              # X 轴刻度字体大小。
              'tickfont': {'size': 14},
              },
    'yaxis': {'title': 'Stars',
              # y 轴标题大小。
              'titlefont': {'size': 24},
              # X 轴刻度字体大小。
              'tickfont': {'size': 14},
              },
}
fig = {'data': data, 'layout': my_layout}
offline.plot(fig, filename='python_repos.html')