【问题标题】:What is a proper way to use next_link for pagination in Python?在 Python 中使用 next_link 进行分页的正确方法是什么?
【发布时间】:2020-12-19 09:39:14
【问题描述】:

我正在尝试为每个“切片”收集 250 条记录。我总共有 1429 条记录,所以 6 片 250 应该足以收集我所有的记录。我尝试使用以下代码执行此操作,但是当我运行它时,它只返回记录 251 到 500。我的预期结果是收到记录 1 到 1429。有人可以告诉我我做错了什么吗?

   import requests
   import json
   import math
       
    res = r.json()
    token = res['access_token']
    headers = {'Authorization': 'Bearer ' + token}
    proxies = {'https': 'proxy.***.***.com:8080'}
    mod_date =  'ModifiedOn gt 2020-01-31'
    col = 'Field1, Field2, Field3, Field4'
    
    params1 = (('$count', 'true'),)       
    response1 = requests.get('https://***-***-***.***.nl/odata/***', headers=headers, params=params1, proxies=proxies)
   
    data = response1.json()
            
    next_link = data['@odata.nextLink'] #<--- this is my 'next_link' link.
    total_records = data['@odata.count'] #<--- this are the total records '1429'
    records_per_page = next_link[313:] #<--- this are the records per page '250'
    
    total_pages = total_records / int(records_per_page)  #<--- these are the total pages '5.7'
    
    list_to_store_all_sclices = []
    list_pages = [i for i in range(1, math.ceil(total_pages) +1)] #<--- '5,7' is rounded to 6 and placed in list.
   
    
    for x in list_pages:
        response2 = requests.get(next_link.format(x), headers=headers,  proxies=proxies)
        data = response2.json()
        list_to_store_all_sclices.append(data)
        print(list_to_store_all_sclices)

【问题讨论】:

  • next_link.format(x) 暗示next_link 中有{},我对此表示怀疑。
  • @Chillie 即使我remove .format(x) 我仍然只得到251500 的记录
  • 这正是我的观点。您实际上并没有请求任何新页面。由于您没有更改next_link,因此您一直在请求第一个响应中的相同链接。
  • 如何更改?我建议它自动继续使用 next_link。

标签: python loops pagination python-requests


【解决方案1】:

如果您一次只能获得 250 个项目,并且只使用一次下一页,那么您将只能获得接下来的 250 个元素,因此是 500 个。虽然这通常不被认为是好的做法,因为您一般不知道先验可以得到多少元素,我最近用这种结构解决了这个问题

    json_dict, links = self._retrieve_transactions_json()
    output_list = parse_json_list(json_dict) # this is my function dont
    while links['next'] and ctr < num_transactions: # if there is a next link keep going, get all accounts
         json_dict, links = self._retrieve_transactions_json(links['next']) # ditto my class 
         output_list.extend(parse_json_list(json_dict)) # ditto above

在我获得一定数量的交易之前,我会不断地获得下一个。希望此 Code Pattern 有所帮助。这里的要点是,每次你得到data,你都会得到一个data['next'] #next page,你需要遍历它,直到它为空或根据你的API规范返回任何最终页面

【讨论】:

  • 我确定您的代码可能适用,但我不明白您到底在做什么。我们可以在聊天中进一步讨论吗?
  • 当然,说实话不完全确定如何聊天:/,你有链接吗?
  • 哈哈 哈哈 需要弄清楚如何聊天,你知道我们可以聊天的其他方式吗?
  • us20.chatzy.com/27657929949345 这应该对我们有用
【解决方案2】:

您似乎在这里犯了两个错误:

  1. 您创建了一个列表来填充list_to_store_all_sclices = [] 但您没有append 成为该列表的第一个结果。

您仅在发出第二个请求后附加数据。

  1. 您从第一个结果中获得了下一个链接。但后来你尝试在上面使用format。当您尝试格式化没有方括号的字符串时,没有任何反应。自己试试吧:
link = 'this is a string'
link2 = 'this is {}'
insert = 'some insertion'
print(link.format(insert))
print(link2.format(insert))

查看formatting synthax 上的文档以了解格式化的工作原理。

由于您没有提供更多关于next_link 的示例以及服务器响应的实际样子,因此我们无法为您提供确切的说明。但是我们可以假设服务器为每个响应提供了一个新链接。因此,您需要在收到每个响应后捕获它并在您的请求中使用它。否则你只是在你提供的代码中一遍又一遍地使用相同的链接。

您的代码可能如下所示:

while next_link:
    new_response = requests.get(next_link, headers=headers,  proxies=proxies)
    new_data = new_response.json()
    list_to_store_all_sclices.append(new_data)
    print(list_to_store_all_sclices)
    next_link = new_data.get('@odata.nextLink', None)

但是您需要查看next_link 的确切外观,以便了解是否/如何修改它以发出正确的请求。交互式 shell 是一个很好的工具。

编辑以回答您的问题:

  1. 现在我们只讨论 1429 条记录,如果我有数百万条记录,python 处理的不是很多吗?

这实际上取决于您的记录的大小。例如,如果每个字符串都是 10 个字符的字符串,那么在内存中存储大量字符串应该不会有问题。如果它们很大,您需要开始考虑一种将数据存储在内存之外(在文件或数据库中)的方法。

  1. 最后两行代码在做什么?(不是打印出来的)

既然你有next_link = data['@odata.nextLink'],我假设数据是一本字典。字典有一个get method。它返回提供的键的值。

如果字典中没有这样的键,则默认返回None,而不是使用方括号表示法来获取键的值,如果键不在字典中,则会引发KeyError

如果请求的键不在字典中,您还可以指定要返回的值。我在示例中明确使用了None,但您不必这样做。

  1. 你的 None 在做什么?

只要表达式为真,while 语句就会重复执行代码块。

FalseNone、空字符串、空字典等都是“假”的,这意味着当服务器没有提供next_link而我们的next_link变量是None时,循环中断。

您可以阅读更多关于真值测试的信息in the docs

使用您的代码,我收到了 251 到 1429 的记录。我错过了 前 250 条记录。

正如我在 1. 中所说,在您的代码中,您不会将第一个响应中的数据附加到 list_to_store_all_sclices

因此您需要创建列表,将第一个响应数据附加到它,然后继续下一个请求。它应该看起来像这样:

data = response1.json()
list_to_store_all_sclices = []
list_to_store_all_sclices.append(data)

您还需要考虑的是,您正在使用您的代码创建一个字典列表。您可能需要考虑结果数据的结构以及它如何影响您未来的需求和结果的使用。

【讨论】:

  • 您的代码完全符合它的要求,但如果您愿意,我可以得到 3 个 cmets。 1.现在我们只是在谈论1429条记录,如果我有几百万条,python处理的不是很多吗? 2. 你最后两行代码在做什么?(不是打印) 3. 你的 None 在做什么?
  • 回答这些,1. 可以像 while next_link 和 len(list_to_store_all_slices)
  • 好的,还有 1 个问题。使用您的代码,我收到了 251 到 1429 条记录。我缺少前 250 条记录。
  • @Chillie。最后一个问题,如果我想将所有内容(所以 data + newdata 放在 1 个字典中并在循环之外使用它呢?
  • @Mediterráneo 因为我不知道data 内部的数据是如何组织的,所以我无法给你一个准确的答案。如果您只需要遍历记录,请将其设为列表。如果要通过键访问数据,请将其设为字典。这实际上取决于希望您的数据组织的方式。如果您在响应中提供数据模型,我可能会提出一些不那么抽象的建议。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-16
  • 1970-01-01
  • 1970-01-01
  • 2015-12-17
  • 2017-05-20
  • 1970-01-01
  • 2011-08-13
相关资源
最近更新 更多