如何在Python中使用Web API 3

API或应用程序接口使开发人员可以轻松地将一个应用程序与另一个程序集成。他们以有限的方式暴露了一些程序的内部工作。您可以使用API​​从其他程序获取信息,或自动化您通常在...中执行的操作

介绍

API或应用程序接口使开发人员可以轻松地将一个应用程序与另一个程序集成。 他们以有限的方式暴露了一些程序的内部工作。

您可以使用API​​从其他程序获取信息,或自动执行通常在Web浏览器中执行的操作。 有时你可以使用API​​来做任何你不能做的事情。 令人惊讶的网络媒体资源提供基于Web的API,以及更熟悉的网站或移动应用程序,包括Twitter,Facebook,GitHub和DigitalOcean。

如果您已经完成了有关如何在Python 3中编写代码的教程,并且您对Python的语法,结构和一些内置函数感到满意,则可以编写利用您最喜欢的API的Python程序。

在本指南中,您将学习如何使用Python与DigitalOcean API来检索有关DigitalOcean帐户的信息。 然后,我们将介绍如何将您学到的内容应用于GitHub的API

完成后,您将了解Web API中常见的概念,您将有一个分步过程和工作代码示例,您可以使用它们来尝试其他服务的API。

先决条件

在开始本指南之前,您将需要以下信息:

第1步 - 熟悉API

使用新API的第一步是找到文档,并得到您的支持。 DigitalOcean API文档从https://developers.digitalocean.com/开始。 要查找其他服务的API,请搜索站点名称和“API” - 并不是所有的服务都会在其首页上宣传。

一些服务有API包装 API包装器是您在系统上安装的代码,可以使您的API更容易在您选择的编程语言中使用。 本指南不使用任何包装器,因为它们隐藏了API的大部分内部工作,并且通常不会暴露API可以执行的所有操作。 当您想快速完成某些工作时,包装器可能会很棒,但是对API本身可以做的事情有一个很好的了解,可以帮助您确定包装器是否符合您的目标。

首先,请访问https://developers.digitalocean.com/documentation/v2/查看DigitalOcean API简介,并尝试仅了解有关如何发送请求的基本知识以及响应中期望的内容。 在这一点上,您只想学习三件事情:

  1. 请求是什么样的? 他们都只是URL吗? 对于更详细的请求,数据格式如何? 通常像Web浏览器使用的JSON或querystring参数,但有些则使用XML或自定义格式。
  2. 响应是什么样的? API文档将显示示例请求和响应。 你会得到JSON,XML或其他一些响应吗?
  3. 进入请求或响应头? 通常,请求标头包括您的身份验证令牌,响应标头提供有关您使用服务的最新信息,例如您的速度限制有多接近。

DigitalOcean API使用HTTP 方法 (有时称为动词 )来指示是否尝试读取现有信息,创建新信息或删除某些内容。 这部分文档解释了使用哪些方法,以及为什么使用。 一般来说,GET请求比POST简单,但是当你完成这个任务之后,你将不会注意到很大的区别。

API文档的下一部分将讨论服务器如何响应您的请求。 一般来说,请求成功或失败。 当它失败时,原因与请求有关,或服务器上的问题。 所有这些信息都使用HTTP状态代码进行传送,这是3位数字,分为几类。

  • 200系列意味着“成功” - 您的请求是有效的,响应是逻辑上遵循的。
  • 400系列意味着“不好的请求 - 请求有问题,所以服务器没有按需要处理它。HTTP 400级错误的常见原因是格式错误的请求和身份验证问题。
  • 500系列意味着“服务器错误” - 您的请求可能已经可以,但由于您的控制原因,服务器现在无法给您很好的响应。 这些应该是罕见的,但是您需要注意可能性,以便您可以在代码中处理它们。

在尝试执行任何操作之前,您的代码应始终检查任何响应的HTTP状态代码。 如果您不这样做,您会发现自己在不完整的信息中浪费时间排查故障。

现在你有一个一般的想法,如何发送请求,以及在响应中寻找什么,是时候发送第一个请求。

第2步 - 从Web API获取信息

您的DigitalOcean帐户包含您可能没有在Web UI中看到的一些管理信息。 API可以为您提供不同的熟悉信息视图。 看到这个备用视图有时会引发关于您可能想要使用API​​的想法,或者显示您不了解的服务和选项。

我们首先为我们的脚本创建一个项目。 为名为apis的项目创建一个新目录:

mkdir apis

然后导航到这个新的目录:

cd apis

为此项目创建一个新的virtualenv:

python3 -m venv apis

激活virtualenv:

source apis/bin/activate

然后安装请求库,我们将在脚本中使用我们的脚本中的HTTP请求:

pip install requests

配置环境后,创建一个名为do_get_account.py的新Python文件,并在文本编辑器中打开它。 通过导入使用JSON和HTTP请求的来关闭此程序。

do_get_account.py
import json
import requests

这些import语句加载了Python代码,可以更容易地处理JSON数据格式和HTTP协议。 我们正在使用这些库,因为我们对如何发送HTTP请求或如何解析和创建有效的JSON的细节不感兴趣 我们只想使用它们完成这些任务。 本教程中的所有脚本将以此开始。

接下来,我们要设置一些变量来保存每个请求中相同的信息。 这样可以使我们不必一遍又一遍地输入它,并给我们一个地方进行更新,以防任何变化。 import语句之后, import这些行添加到文件中。

do_get_account.py
...
api_token = 'your_api_token'
api_url_base = 'https://api.digitalocean.com/v2/'

api_token变量是一个保存您的DigitalOcean API令牌的字符串。 用自己的令牌替换示例中的值。 api_url_base变量是从DigitalOcean API中的每个URL开始的字符串。 我们将在后面的代码中附加它。

接下来,我们需要以API文档描述的方式设置HTTP请求头。 将这些行添加到文件中以设置包含请求标头的字典

do_get_account.py
...
headers = {'Content-Type': 'application/json',
           'Authorization': 'Bearer {0}'.format(api_token)}

一次设置两个标题。 Content-Type标头告诉服务器在请求正文中期望JSON格式的数据。 Authorization标头需要包含我们的令牌,所以我们使用Python的字符串格式化逻辑在我们创建字符串时将我们的api_token变量插入到字符串中。 我们可以将这个标记放在这里作为一个字面的字符串,但分离它使得几件事情更容易在路上:

  • 如果您需要替换令牌,当它是一个单独的变量时,更容易看到在哪里做。
  • 如果您想与某人分享您的代码,那么删除您的API令牌更容易,您的朋友更容易看到放置他们的代码。
  • 它是自我记录的。 如果API令牌仅用作字符串文字,那么阅读代码的人可能不了解他们正在查看的内容。

现在我们已经覆盖了这些设置的详细信息,现在是实际发送请求的时候了。 您的倾向可能只是开始创建和发送请求,但有一个更好的方法。 如果把这个逻辑放在处理发送请求并读取响应的函数中,那么你必须更清楚地看一下你在做什么。 您还将最终使用易于测试和易于重用的代码。 这就是我们要做的

此函数将使用您创建的变量发送请求并将其返回到Python字典中。

为了在这个早期的阶段保持逻辑清晰,我们不会做任何详细的错误处理,但是我们将尽快补充说。

定义获取帐户信息的功能。 在执行任务后,总是一个好主意:这个功能可以获取帐户信息,所以我们称之为get_account_info

do_get_account.py
...
def get_account_info():

    api_url = '{0}account'.format(api_url_base)

    response = requests.get(api_url, headers=headers)

    if response.status_code == 200:
        return json.loads(response.content.decode('utf-8'))
    else:
        return None

我们使用Python的字符串格式化方法来构建api_url的值,类似于我们如何在标题中使用它; 我们将API的基本URL附加到字符串account前面,以获取URL https://api.digitalocean.com/v2/account的URL,该URL应返回帐户信息。

response变量包含由Python requests模块创建的对象。 该行将请求发送到我们使用我们在脚本开始处定义的标头的URL,并从API返回响应。

接下来,我们来看一下响应的HTTP状态代码。

如果是200 ,一个成功的响应,那么我们使用json模块的loads函数来加载一个字符串作为JSON。 我们加载的字符串是response对象的内容response.content .decode('utf-8')部分告诉Python,这个内容是使用UTF-8字符集进行编码的,因为DigitalOcean API的所有响应都将是。 json模块创建一个对象,我们用它作为这个函数的返回值。

如果响应不是 200 ,那么我们返回None ,这是Python中的一个特殊值,我们可以在调用此函数时检查它。 你会注意到,我们现在只是忽略任何错误。 这是为了保持“成功”逻辑的清晰。 我们将尽快添加更全面的错误检查。

现在调用此函数,检查以确保它有一个很好的响应,并打印出API返回的详细信息:

do_get_account.py
...
account_info = get_account_info()

if account_info is not None:
    print("Here's your info: ")
    for k, v in account_info['account'].items():
        print('{0}:{1}'.format(k, v))

else:
    print('[!] Request Failed')

account_info = get_account_info()account_info变量设置为从get_account_info()的调用返回的任何值,因此它将是特殊值None ,也可以是关于该帐户的信息的集合。

如果它不是None ,那么我们使用所有Python字典具有的items()方法打印出自己的一行信息。

否则(即,如果account_infoNone ),我们会打印一条错误消息。

我们暂停一下这里。 这个if语句中双重否定首先可能会感到尴尬,但它是普通的Python成语。 它的优点是保持成功的代码非常接近条件,而不是处理错误的情况。

如果你愿意,你可以用另一种方法来实现,而自己编写代码可能是一个很好的练习。 而不是if account_info is not None:您可以从if account_info is None:开始,并查看其余的如何。

保存脚本并尝试:

python do_get_account.py

输出将如下所示:

Here's your info: 
droplet_limit:25
email:sammy@digitalocean.com
status:active
floating_ip_limit:3
email_verified:True
uuid:123e4567e89b12d3a456426655440000
status_message:

您现在知道如何从API中检索数据。 接下来,我们将继续讨论一些有趣的事情 - 使用API​​来更改数据。

第3步 - 修改服务器上的信息

在以只读请求进行练习之后,现在是开始进行更改的时候了。 让我们通过使用Python和DigitalOcean API来为您的DigitalOcean帐户添加一个SSH密钥。

首先,请查看SSH密钥的API文档, 网址https://developers.digitalocean.com/documentation/v2/#ssh-keys

该API可让您列出帐户中的当前SSH密钥,还可以添加新的密钥。 获取SSH密钥列表的请求很像获取帐户信息。 尽管如此,响应是不同的:与帐户不同,您可以拥有零个,一个或多个SSH密钥。

为此脚本创建一个名为do_ssh_keys.py的新文件,并将其完全像最后一个文件一样启动。 导入jsonrequests模块,以便您不必担心JSON或HTTP协议的细节。 然后将您的DigitalOcean API令牌添加为变量,并在字典中设置请求标头。

do_ssh_keys.py
import json
import requests

api_token = 'your_api_token'
api_url_base = 'https://api.digitalocean.com/v2/'
headers = {'Content-Type': 'application/json',
           'Authorization': 'Bearer {0}'.format(api_token)}

我们将创建的用于获取SSH密钥的功能类似于我们用于获取帐户信息的功能,但是这次我们将更直接地处理错误。

首先,我们将API调用并将响应存储在response响应变量中。 api_url不会和以前的脚本一样; 这一次需要指向https://api.digitalocean.com/v2/account/keys

将此代码添加到脚本中:

do_ssh_keys.py
...
def get_ssh_keys():

    api_url = '{0}account/keys'.format(api_url_base)

    response = requests.get(api_url, headers=headers)

现在我们通过查看响应中的HTTP状态代码来添加一些错误处理。 如果是200 ,我们将作为字典返回响应的内容,就像我们以前一样。 如果还有其他事情,我们会打印一个与状态代码类型相关联的有用的错误消息,然后返回None

将这些行添加到get_ssh_keys函数中:

do_ssh_keys.py
...

    if response.status_code >= 500:
        print('[!] [{0}] Server Error'.format(response.status_code))
        return None
    elif response.status_code == 404:
        print('[!] [{0}] URL not found: [{1}]'.format(response.status_code,api_url))
        return None  
    elif response.status_code == 401:
        print('[!] [{0}] Authentication Failed'.format(response.status_code))
        return None
    elif response.status_code == 400:
        print('[!] [{0}] Bad Request'.format(response.status_code))
        return None
    elif response.status_code >= 300:
        print('[!] [{0}] Unexpected Redirect'.format(response.status_code))
        return None
    elif response.status_code == 200:
        ssh_keys = json.loads(response.content.decode('utf-8'))
        return ssh_keys
    else:
        print('[?] Unexpected Error: [HTTP {0}]: Content: {1}'.format(response.status_code, response.content))
    return None

该代码通过查看响应中的HTTP状态代码来处理六个不同的错误条件。

  • 500或更高的代码表示服务器上的问题。 这些应该是罕见的,它们不是由请求的问题引起的,所以我们只打印状态代码。
  • 404的代码意味着“未找到”,这可能源于URL中的打字错误。 对于此错误,我们打印状态代码和导致它的URL,以便您可以看到它为什么失败。
  • 401的代码意味着认证失败。 最可能的原因是api_key不正确或丢失。
  • 300范围内的代码表示重定向。 DigitalOcean API不使用重定向,所以这不应该发生,但是当我们处理错误时,它不会对检查造成伤害。 许多错误是程序员认为不应该发生的事情引起的。
  • 代码200表示请求被成功处理。 为此,我们不打印任何东西。 我们将ssh键作为JSON对象返回,使用与上一个脚本中使用的相同的语法。
  • 如果响应代码是其他任何事情,我们将状态代码打印为“意外错误”。

这应该可以处理我们可能从调用API获得的任何错误。 在这一点上,我们有一个错误消息和None对象,或者我们有成功和一个包含零个或多个SSH密钥的JSON对象。 我们的下一步是打印出来:

do_ssh_keys.py
...

ssh_keys = get_ssh_keys()

if ssh_keys is not None:
    print('Here are your keys: ')
    for key, details in enumerate(ssh_keys['ssh_keys']):
        print('Key {}:'.format(key))
        for k, v in details.items():
            print('  {0}:{1}'.format(k, v))
else:
    print('[!] Request Failed')

因为响应包含一个SSH密钥的列表(或数组),我们想遍历整个列表以查看所有的密钥。 我们使用Python的enumerate方法。 这类似于可用于词典的items方法,但它可以替代列表。

我们使用enumerate而不仅仅是一个for循环,因为我们希望能够告诉我们任何给定键的列表中有多远。

每个密钥的信息都作为一个字典返回,所以我们使用相同for k,v in details.items():我们在前面的脚本中的帐户信息字典中使用的代码。

运行此脚本,您将得到一个您帐户中已经存在的SSH密钥列表。

python get_ssh_keys.py

输出将看起来像这样,这取决于您的帐户上已有多少个SSH密钥。

Here are your keys: 
Kcy 0:
  id:280518
  name:work
  fingerprint:96:f7:fb:9f:60:9c:9b:f9:a9:95:01:5c:5c:2c:d5:a0
  public_key:ssh-rsa AAAAB5NzaC1yc2cAAAADAQABAAABAQCwgr9Fzc/YTD/V2Ka5I52Rx4I+V2Ka5I52Rx4Ir5LKSCqkQ1Cub+... sammy@work
Kcy 1:
  id:290536
  name:home
  fingerprint:90:1c:0b:ac:fa:b0:25:7c:af:ab:c5:94:a5:91:72:54
  public_key:ssh-rsa AAAAB5NzaC1yc2cAAAABJQAAAQcAtTZPZmV96P9ziwyr5LKSCqkQ1CubarKfK5r7iNx0RNnlJcqRUqWqSt... sammy@home

现在您可以在帐户中列出SSH密钥,这里的最后一个脚本将是添加新列表的新密钥。

在添加新的SSH密钥之前,我们需要生成一个。 要更全面地处理此步骤,请查看教程如何设置SSH密钥

为了我们的目的,我们只需要一个简单的键。 执行此命令在Linux,BSD或MacOS上生成一个新的命令。 如果你喜欢,你可以在现有的Droplet上做到这一点。

ssh-keygen -t rsa

出现提示时,输入文件以保存密钥,并且不提供密码。

Generating public/private rsa key pair.
Enter file in which to save the key (/home/sammy/.ssh/id_rsa): /home/sammy/.ssh/sammy 
Created directory '/home/sammy/.ssh'.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/sammy/.ssh/sammy.
Your public key has been saved in /home/sammy/.ssh/sammy.pub.
...

记下公钥文件的保存位置,因为您需要使用该脚本。

启动一个新的Python脚本,并将其称为add_ssh_key.py ,并像其他脚本一样启动它:

add_ssh_key.py
import json
import requests

api_token = 'your_api_token'
api_url_base = 'https://api.digitalocean.com/v2/'
headers = {'Content-Type': 'application/json',
           'Authorization': 'Bearer {0}'.format(api_token)}

我们将使用一个函数来提出我们的要求,但是这个函数会稍有不同。

创建一个名为add_ssh_key的函数,该函数将接受两个参数:用于新SSH密钥的名称以及本地系统上密钥本身的文件名。 该函数将读取该文件 ,并进行HTTP POST请求,而不是GET

add_ssh_key.py
...

def add_ssh_key(name, filename):

    api_url = '{0}account/keys'.format(api_url_base)

    with open(filename, 'r') as f:
        ssh_key = f.readline()

    ssh_key = {'name': name, 'public_key': ssh_key}

    response = requests.post(api_url, headers=headers, json=ssh_key)

with open(filename, 'r') as f:的行以只读模式打开文件, ssh_key行从文件中读取第一行(仅)行,将其存储在ssh_key变量中。

接下来,我们制作一个名为ssh_key的Python字典,其中包含API所期望的名称和值。

当我们发送请求时,还有一点是新的。 它是一个POST而不是一个GET ,我们需要将ssh_key发送到POST请求的正文中,编码为JSON。 requests模块将处理我们的细节; json=ssh_key告诉它使用POST方法,并且包括json=ssh_key它将ssh_key变量发送到请求的正文中,以JSON编码。

根据API,响应将成为HTTP 201 ,而不是200 ,响应的主体将包含我们刚添加的密钥的详细信息。

将以下错误处理代码添加到add_ssh_key函数。 它类似于以前的脚本,除了这一次,我们必须寻找代码201而不是成功的200

add_ssh_key.py
...
  if response.status_code >= 500:
      print('[!] [{0}] Server Error'.format(response.status_code))
      return None
  elif response.status_code == 404:
      print('[!] [{0}] URL not found: [{1}]'.format(response.status_code,api_url))
      return None
  elif response.status_code == 401:
      print('[!] [{0}] Authentication Failed'.format(response.status_code))
      return None
  elif response.status_code >= 400:
      print('[!] [{0}] Bad Request'.format(response.status_code))
      print(ssh_key )
      print(response.content )
      return None
  elif response.status_code >= 300:
      print('[!] [{0}] Unexpected redirect.'.format(response.status_code))
      return None
  elif response.status_code == 201:
      added_key = json.loads(response.content)
      return added_key
  else:
      print('[?] Unexpected Error: [HTTP {0}]: Content: {1}'.format(response.status_code, response.content))
      return None

此功能与以前的功能一样返回None或响应内容,因此我们使用与之前相同的方法来检查结果。

接下来,调用函数并处理结果。 将路径传递到您新创建的SSH密钥作为第二个参数:

add_ssh_key.py
...
add_response = add_ssh_key('tutorial_key', '/home/sammy/.ssh/sammy.pub')

if add_response is not None:
    print('Your key was added: ' )
    for k, v in add_response.items():
        print('  {0}:{1}'.format(k, v))
else:
    print('[!] Request Failed')

运行这个脚本,你会得到一个回应,告诉你你的新密钥已被添加。

python add_ssh_key.py 

输出将如下所示:

Your key was added: 
  ssh_key:{'id': 9458326, 'name': 'tutorial_key', 'fingerprint': '64:76:37:77:c8:c7:26:05:f5:7b:6b:e1:bb:d6:80:da', 'public_key': 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCUtY9aizEcVJ65/O5CE6tY8Xodrkkdh9BB0GwEUE7eDKtTh4NAxVjXc8XdzCLKtdMwfSg9xwxSi3axsVWYWBUhiws0YRxxMNTHCBDsLFTJgCFC0JCmSLB5ZEnKl+Wijbqnu2r8k2NoXW5GUxNVwhYztXZkkzEMNT78TgWBjPu2Tp1qKREqLuwOsMIKt4bqozL/1tu6oociNMdLOGUqXNrXCsOIvTylt6ROF3a5UnVPXhgz0qGbQrSHvCEfuKGZ1kw8PtWgeIe7VIHbS2zTuSDCmyj1Nw1yOTHSAqZLpm6gnDo0Lo9OEA7BSFr9W/VURmTVsfE1CNGSb6c6SPx0NpoN sammy@tutorial-test'}

如果您忘记更改“成功”条件以查找HTTP 201而不是200 ,则会看到报告错误,但仍将添加密钥。 您的错误处理会告诉您状态代码为201 你应该认识到,作为200系列的成员,这表明成功。 这是一个基本错误处理如何简化故障排除的示例。

使用此脚本成功添加密钥后,再次运行它,以查看当您尝试添加已存在的密钥时会发生什么。

API将发送一个HTTP 422响应,您的脚本将转换为一条消息,指出“SSH密钥已在您的帐户中使用”。:

[!] [422] Bad Request
{'name': 'tutorial_key', 'public_key': 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCUtY9aizEcVJ65/O5CE6tY8Xodrkkdh9BB0GwEUE7eDKtTh4NAxVjXc8XdzCLKtdMwfSg9xwxSi3axsVWYWBUhiws0YRxxMNTHCBDsLFTJgCFC0JCmSLB5ZEnKl+Wijbqnu2r8k2NoXW5GUxNVwhYztXZkkzEMNT78TgWBjPu2Tp1qKREqLuwOsMIKt4bqozL/1tu6oociNMdLOGUqXNrXCsOIvTylt6ROF3a5UnVPXhgz0qGbQrSHvCEfuKGZ1kw8PtWgeIe7VIHbS2zTuSDCmyj1Nw1yOTHSAqZLpm6gnDo0Lo9OEA7BSFr9W/VURmTVsfE1CNGSb6c6SPx0NpoN sammy@tutorial-test'}
b'{"id":"unprocessable_entity","message":"SSH Key is already in use on your account"}'
[!] Request Failed

现在再次运行您的get_ssh_keys.py脚本,您将在列表中看到您新添加的密钥。

通过小的修改,这两个脚本可能是一个快速的方法来添加新的SSH密钥到您的DigitalOcean帐户,只要你需要。 该API中的相关功能允许您通过使用其唯一的密钥ID或指纹来重命名或删除特定密钥。

我们来看看另一个API,看看你刚刚学到的技能如何翻译。

第4步 - 使用不同的API

GitHub也有一个API。 您使用DigitalOcean API了解的一切都直接适用于使用GitHub API。

了解GitHub API的方式与DigitalOcean相同。 搜索API文档 ,然后浏览“ 概述”部分。 您会看到GitHub API和DigitalOcean API有一些相似之处。

首先,您会注意到所有API网址都有一个共同根源: https://api.github.com/https://api.github.com/ 您知道如何使用它作为代码中的变量来简化并减少错误的可能性。

GitHub的API使用JSON作为其请求和响应格式,就像DigitalOcean一样,所以你知道如何进行这些请求并处理响应。

响应包括有关HTTP响应头中速率限制的信息,使用与DigitalOcean几乎相同的名称和完全相同的值。

GitHub使用OAuth进行身份验证,您可以在请求标头中发送令牌。 该令牌的细节有所不同,但使用的方式与DigitalOcean的API相同。

也有一些差异。 GitHub鼓励使用请求标头来指示要使用的API的版本。 你知道如何在Python中为请求添加标题。

GitHub还希望您在请求中使用唯一的User-Agent字符串,因此如果您的代码导致问题,他们可以更轻松地找到您。 你也可以用标题处理。

GitHub API使用相同的HTTP请求方法,但是对于某些操作也使用了一个新的称为PATCH的方法。 GitHub API使用GET来读取信息, POST以添加新项目,以及PATCH修改现有项目。 这个PATCH请求是你想要在API文档中寻找的东西。

并不是所有的GitHub API调用都需要身份验证。 例如,您可以获取用户存储库的列表,而不需要访问令牌。 让我们创建一个脚本来提出请求并显示结果。

我们将简化此脚本中的错误处理,并只使用一个语句来处理所有可能的错误。 你并不总是需要代码来分别处理各种错误,但是如果只是提醒自己,事情并不总是按照你所期望的方式进行,那么做错误的事情是一个很好的习惯。

在您的编辑器中创建一个名为github_list_repos.py的新文件,并添加以下内容,这些内容应该很熟悉:

github_list_repos.py
import json
import requests

api_url_base = 'https://api.github.com/'
headers = {'Content-Type': 'application/json',
           'User-Agent': 'Python Student',
           'Accept': 'application/vnd.github.v3+json'}

进口是我们一直在使用的。 api_url_base是所有GitHub API开始的地方。

标题包括GitHub在其概述中提到的两个可选选项,以及我们在我们的请求中发送JSON格式数据的标题。

即使这是一个小脚本,我们仍然会定义一个函数,以保持我们的逻辑模块化并封装提出请求的逻辑。 通常,你的小脚本会变成更大的脚本,所以要勤奋地工作很有帮助。 添加一个名为get_repos的函数,该函数接受用户名作为参数:

github_list_repos.py

...
def get_repos(username):

    api_url = '{}orgs/{}/repos'.format(api_url_base, username)

    response = requests.get(api_url, headers=headers)

    if response.status_code == 200:
        return (response.content)
    else:
        print('[!] HTTP {0} calling [{1}]'.format(response.status_code, api_url))
        return None

在函数内部,我们构建了api_url_base的URL,我们感兴趣的用户的名称,以及告诉GitHub我们想要存储库列表的URL的静态部分。 然后我们检查响应的HTTP状态代码,以确保它是200 (成功)。 如果成功,我们返回响应内容。 如果没有,那么我们打印出实际的状态代码和我们构建的URL,所以我们会有一个想法,我们可能会出错。

现在,调用该函数并传入您要使用的GitHub用户名。 我们将在这个例子中使用octokit 然后将结果打印到屏幕上:

github_list_repos.py

...
repo_list = get_repos('octokit')

if repo_list is not None:
    print(repo_list)
else:
    print('No Repo List Found')

保存文件并运行脚本以查看您指定的用户的存储库。

python github_list_repos.py

您将在输出中看到很多数据,因为在本示例中我们尚未将响应解析为JSON,也没有将结果过滤到特定的键。 使用你在其他脚本中学到的东西来做到这一点。 看看你得到的结果,看看是否可以打印存储库名称。

一旦这些GitHub API的好处就是您可以直接在Web浏览器中访问不需要身份验证的请求,这样可以将响应与您在脚本中看到的内容进行比较。 请尝试访问浏览器中的https://api.github.com/orgs/octokit/repos以查看那里的响应。

现在,您将了解如何阅读文档,并编写必要的代码,以便使用GitHub API发送更多具体的请求来支持您自己的目标。

您可以在GitHub的这个存储库中找到本教程中所有示例的完整代码。

结论

在本教程中,您学习了如何将Web API用于具有稍微不同样式的两种不同的服务。 您看到包含错误处理代码使调试更容易,脚本更强大的重要性。 您使用Python模块requestsjson将这些技术的细节与您的工作完全隔离,并完成工作,并将请求和响应处理封装在一个函数中,使您的脚本更加模块化。

而且,当您学习任何新的Web API时,您现在都可以重复的过程:

  1. 查找文档并阅读介绍,了解如何与API进行交互的基础知识。
  2. 如果需要,请获取身份验证令牌,并编写具有基本错误处理的模块化脚本以发送简单请求,响应错误并处理响应。
  3. 创建将从服务中获取您想要的信息的请求。

现在,粘贴这个新获得的知识,并找到使用的另一个API,或甚至您在这里使用的其中一个API的另一个功能。 你自己的项目将有助于巩固你在这里学到的东西。