二刷《Python编程 从入门到实践》(13):使用API

第十七章 使用API

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

17.1 使用 Web API

Web API 是网站的一部分,用于与使用非常具体的URL请求特定信息的程序交互。这种请求称为 API 调用。请求的数据将以易于处理的格式(如JSONCSV)返回。

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指定将项目按其获得的星级进行排序。

调用结果:

{
  "total_count": 5182955,
  "incomplete_results": true,
  "items": [
    {
      "id": 54346799,
      "node_id": "MDEwOlJlcG9zaXRvcnk1NDM0Njc5OQ==",
      "name": "public-apis",
      "full_name": "public-apis/public-apis",
      --snip--

17.1.3 安装 requests

书上没有细说。我的安装步骤是:
1、激活已经建立的 anaconda 环境。

>>> activate tensorflow

2、直接使用pip安装。

>>> pip install requests

17.1.4 处理 API 响应

找出GitHub上星级最高的Python项目:

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())

调用get()并将URL传递给它,再将响应对象储存在变量r中。响应对象包含一个名为status_code属性,它让我们知道请求是否成功了(状态码200表示请求成功)。这个API返回JSON格式的信息,因此使用方法json()将这些信息转换为一个Python字典。

书上的结果:

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

我调用的结果:

Traceback (most recent call last):
  --snip--
requests.exceptions.ConnectionError: ('Connection aborted.', ConnectionResetError(10054, '远程主机强迫关闭了一个现有的连接。', None, 10054, None))

被服务器拒绝了。

17.1.5 处理响应字典

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

上述代码中,使用owner来访问表示所有者的字典,再使用key来获取所有者的登录名。

17.1.6 概述最受欢迎的仓库

17.1.7 监视 API 的速率限制

大多数API都存在速率限制,即在特定时间内可执行的请求数存在限制。要获悉GitHub的限制,可以在浏览器中输入https://api.github.com/rate_limit

{
  "resources":{
    "core":{
      "limit":60,
      "remaining":60,
      "reset":1591064977
    },
    "graphql":{
      "limit":0,
      "remaining":0,
      "reset":1591064977
    },
    "integration_manifest":{
      "limit":5000,
      "remaining":5000,
      "reset":1591064977
    },
    "search":{
      "limit":10,
      "remaining":10
      "reset":1591061437
     }
   },
   "rate":{
     "limit":60,
     "remaining":60,
     "reset":1591064977
   }
}

17.2 使用 Pygal 可视化仓库

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.Bar()创建条形图时,将样式my_style传递给style,将标签绕 x 轴旋转45°(x_label_rotation=45),并隐藏图例(show_legend=False)。由于不需要给这个数据系列添加标签,所以调用add()时,传递的第一个实参为空字符串。

17.2.1 改进 Pygal 图表

可以先创建一个配置对象my_config,再将要传递给Bar()的所有定制都放在里面。

--snip--

# 可视化
my_style = LS('#333366', base_style=LCS)

my_config = pygal.Config()             # 创建 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          # x 轴上项目名只显示前15个字
my_config.show_y_guides = False        # 隐藏图表中的 y 轴水平线
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')

17.2.2 添加自定义工具提示

在 Pygal 中,将鼠标指向条形将显示它表示的信息,这通常称为 工具提示

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

Pygal 根据与键value相关联的数字来确定条形的高度,并使用与label 相关联的字符串给条形创建工具提示

17.2.3 根据数据绘图

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

17.2.4 在图表中添加可单击的链接

Pygal 允许将图表中的每个条形用作网站的链接,只需在字典中添加一个键为'xlink' 的键—值对:

--snip--
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'], 
        'xlink': repo_dict['html_url'], 
        } 
    plot_dicts.append(plot_dict)
--snip--

17.3 Hacker News API

import requests
from operator import itemgetter

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

# 处理有关每篇文章的信息
submission_ids = r.json()
submission_dicts = []                        # 包含所以文章信息的字典列表
for submission_id in submission_ids[:30]:    # 遍历前30篇文章信息
    # 对于每篇文章,都执行一个API调用
    url = ('https://hacker-news.firebaseio.com/v0/item/' + 
            str(submission_id) + '.json')
    submission_r = requests.get(url)
    print(submission_r.status_code)
    response_dict = submission_r.json()
    
    submission_dict = { 
        'title': response_dict['title'], 
        'link': 'http://news.ycombinator.com/item?id=' + str(submission_id), 
        'comments': response_dict.get('descendants', 0) 
        }
    submission_dicts.append(submission_dict)

submission_dicts = sorted(submission_dicts, key=itemgetter('comments'), 
                            reverse=True)     # 按评论数倒序

for submission_dict in submission_dicts:
    print("\nTitle:", submission_dict['title'])
    print("Discussion link:", submission_dict['link'])
    print("Comments:", submission_dict['comments'])

在字典中response_dict存储了评论数。如果文章还没有评论,响应字典中将没有键descendants。不确定某个键是否包含在字典中时,可使用方法dict.get()它在指定的键存在时返回与之相关联的值,并在指定的键不存在时返回你指定的值(这里是0)

根据评论数对字典列表submission_dicts进行排序,为此,使用了模块operator中的函数itemgetter(),向其传递键comments,这样它将从这个列表的每个字典中提取与键comments相关联的值。reverse=True表示倒叙。

小结

1、利用模块requests中的get()函数调用URL,例如 r = requests.get(url)
2、使用方法json()将API 调用获得的信息转换为一个Python字典,例如 response_dict = r.json()
3、使用owner来访问表示所有者的字典,再使用key来获取所有者的登录名,例如 print('Owner:', repo_dict['owner']['login'])
4、调用pygal.Bar()创建条形图时,将样式my_style传递给style,将标签绕 x 轴旋转45°(x_label_rotation=45),并隐藏图例show_legend=False),例如 chart = pygal.Bar(style=my_style, x_label_rotation=45, show_legend=False)
5、不需要给这个数据系列添加标签时,调用函数add()传递的第一个实参为空字符串,例如 chart.add('', stars)
6、可以先创建一个配置对象my_config,再将要传递给Bar()的所有定制都放在里面,例如 chart = pygal.Bar(my_config, style=my_style)
7、Pygal 根据与键value相关联的数字来确定条形的高度,并使用与label 相关联的字符串给条形创建工具提示,例如 plot_dicts = [{'value': 16101, 'label': 'Description of httpie.'}, ...]
8、Pygal 允许将图表中的每个条形用作网站的链接,只需在字典中添加一个键为'xlink'的键—值对,例如 plot_dict = { 'value': repo_dict['stargazers_count'], 'label': repo_dict['description'], 'xlink': repo_dict['html_url'], }
9、不确定某个键是否包含在字典中时,可使用方法dict.get()它在指定的键存在时返回与之相关联的值,并在指定的键不存在时返回你指定的值, 例如 submission_dict = { ..., 'comments': response_dict.get('descendants', 0)}
10、使用了模块operator中的函数itemgetter(),向其传递键comments,可以根据评论数对字典列表submission_dicts进行排序,例如 submission_dicts = sorted(submission_dicts, key=itemgetter('comments'), reverse=True)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

猎猫骑巨兽

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

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

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

打赏作者

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

抵扣说明:

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

余额充值