【问题标题】:How to get data from all pages in Github API with Python?如何使用 Python 从 Github API 中的所有页面获取数据?
【发布时间】:2016-02-25 23:18:25
【问题描述】:

我正在尝试导出一个 repo 列表,它总是返回有关第一页的信息。我可以使用 URL+"?per_page=100" 扩展每页的项目数,但这还不足以获取整个列表。 我需要知道如何获取从第 1、2、...、N 页中提取数据的列表。 我正在使用请求模块,如下所示:

while i <= 2:
      r = requests.get('https://api.github.com/orgs/xxxxxxx/repos?page{0}&per_page=100'.format(i), auth=('My_user', 'My_passwd'))
      repo = r.json()
      j = 0
      while j < len(repo):
            print repo[j][u'full_name']
            j = j+1
      i = i + 1

我使用 while 条件,因为我知道有 2 页,我尝试以这种方式增加它,但它不起作用

【问题讨论】:

  • 打印每次迭代生成的url,检查是否正确
  • 你有这行:repo=p.json() 这是一个错字吗?它应该读成r.json()吗?

标签: python api github pagination python-requests


【解决方案1】:
import requests

url = "https://api.github.com/XXXX?simple=yes&per_page=100&page=1"
res=requests.get(url,headers={"Authorization": git_token})
repos=res.json()
while 'next' in res.links.keys():
  res=requests.get(res.links['next']['url'],headers={"Authorization": git_token})
  repos.extend(res.json())

如果您没有制作完整的应用程序,请使用“个人访问令牌”

https://github.com/settings/tokens

【讨论】:

  • 谢谢!我不知道有 response.links 属性。这个答案需要被选为最佳答案。其他所有解决方案都是 hack!
【解决方案2】:
        link = res.headers.get('link', None)

        if link is not None:
            link_next = [l for l in link.split(',') if 'rel="next"' in l]
            if len(link_next) > 0:
                return int(link_next[0][link_next[0].find("page=")+5:link_next[0].find(">")])

【讨论】:

    【解决方案3】:

    首先你使用

    print(a.headers.get('link'))
    

    这将为您提供存储库的页面数,类似于下面

    <https://api.github.com/organizations/xxxx/repos?page=2&type=all>; rel="next", 
    
    <https://api.github.com/organizations/xxxx/repos?page=8&type=all>; rel="last"
    

    从这里你可以看到当前我们在 repo 的第一页,rel='next' 表示下一页是 2,rel='last' 告诉我们你的最后一页是 8。

    知道要遍历的页数后,您只需要在获取请求时使用“=”作为页码,并将 while 循环更改到最后一个页码,而不是 len(repo),因为它会返回 100 个时间。 例如

    i=1
    while i <= 8:
          r = requests.get('https://api.github.com/orgs/xxxx/repos?page={0}&type=all'.format(i),
                             auth=('My_user', 'My_passwd'))
          repo = r.json()
          for j in repo:
            print(repo[j][u'full_name'])
          i = i + 1
    

    【讨论】:

      【解决方案4】:

      扩展上面的答案,这里有一个递归函数来处理 GitHub 分页,它将遍历所有页面,将列表与每个递归调用连接起来,最后在没有更多页面要检索时返回完整列表,除非当项目超过 500 个时,可选的故障保护返回列表。

      import requests
      
      api_get_users = 'https://api.github.com/users'
      
      
      def call_api(apicall, **kwargs):
      
          data = kwargs.get('page', [])
      
          resp = requests.get(apicall)
          data += resp.json()
      
          # failsafe
          if len(data) > 500:
              return (data)
      
          if 'next' in resp.links.keys():
              return (call_api(resp.links['next']['url'], page=data))
      
          return (data)
      
      
      data = call_api(api_get_users)
      

      【讨论】:

      • 如果它能够适应类似的东西会更好:data = call_api(...); while data: # do something with the data; data = call_api(...)。基本上有某种迭代器,它允许您分批检索数据,一次一页:)
      【解决方案5】:

      据我了解,如果只返回一页数据,则链接将为无,否则即使超出最后一页,链接也会出现。在这种情况下,链接将包含先前和第一个链接。

      这里有一些示例 python,它旨在简单地返回下一页的链接,如果没有下一页,则返回 None。所以可以合并到一个循环中。

      link = r.headers['link']
      if link is None:
          return None
      
      # Should be a comma separated string of links
      links = link.split(',')
      
      for link in links:
          # If there is a 'next' link return the URL between the angle brackets, or None
          if 'rel="next"' in link:
              return link[link.find("<")+1:link.find(">")]
      return None
      

      【讨论】:

      • 帮助接受的答案是否经过更好的测试。这解决了两种不同的情况。
      【解决方案6】:

      来自github docs

      回复:

      Status: 200 OK
      Link: <https://api.github.com/resource?page=2>; rel="next",
            <https://api.github.com/resource?page=5>; rel="last"
      X-RateLimit-Limit: 5000
      X-RateLimit-Remaining: 4999
      

      您将获得指向该组织的下一页和最后一页的链接。只需检查标题。

      在 Python 请求中,您可以通过以下方式访问您的标头:

      response.headers
      

      它是一个包含响应头的字典。如果 link 存在,那么页面会更多,并且会包含相关信息。建议使用这些链接进行遍历,而不是自己构建。

      你可以试试这样的:

      import requests
      url = 'https://api.github.com/orgs/xxxxxxx/repos?page{0}&per_page=100'
      response = requests.get(url)
      link = response.headers.get('link', None)
      if link is not None:
          print link
      

      如果链接不是无,它将是一个包含资源相关链接的字符串。

      【讨论】:

      • 感谢您的回答,但我已经在 github 文档上找到了,我不知道它是如何工作的。我找不到使用python实现它的方法。你能帮帮我吗?
      • 是的,我现在正在检查。您的组织有很多页面吗?
      • 我是使用 API 和 Python 的初学者,非常感谢您的帮助。我有一个拥有 44 个用户和 190 个 repos 的组织,因此不可能一次性下载它们,因为最多 100 个项目。
      • 只需检查 headers dict 是否包含关键链接,在这种情况下,您可以找到下一个请求并执行此操作,直到它不显示为止。
      • 我不知道该怎么做。我可以联系你以学习一些东西吗?我想我会很快通过聊天
      猜你喜欢
      • 2020-12-17
      • 2020-11-18
      • 1970-01-01
      • 2019-12-15
      • 1970-01-01
      • 1970-01-01
      • 2020-02-09
      • 2015-12-02
      • 2013-11-24
      相关资源
      最近更新 更多