【问题标题】:Unable to loop through paged API responses with Python无法使用 Python 循环遍历分页 API 响应
【发布时间】:2016-07-08 23:36:12
【问题描述】:

所以,我正在为这个挠头。使用 HubSpot 的 API,我需要获取客户“门户”(帐户)中所有公司的列表。遗憾的是,标准 API 调用一次只返回 100 家公司。当它返回一个响应时,它包含两个参数,这使得对响应进行分页成为可能。

其中一个是"has-more": True(这让您知道是否可以期待更多页面),另一个是"offset":12345678(抵消请求的时间戳。)

这两个参数是您可以传递回下一个 API 调用以获取下一页的内容。例如,初始 API 调用可能如下所示:

"https://api.hubapi.com/companies/v2/companies/?hapikey={hapikey}".format(hapikey=wta_hubspot_api_key)

而后续电话可能如下所示:

"https://api.hubapi.com/companies/v2/companies/?hapikey={hapikey}&offset={offset}".format(hapikey=wta_hubspot_api_key, offset=offset)

所以这是我迄今为止尝试过的:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys
import os.path
import requests
import json
import csv
import glob2
import shutil
import time
import time as howLong
from time import sleep
from time import gmtime, strftime

HubSpot_Customer_Portal_ID = "XXXXXX"

wta_hubspot_api_key = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"

findCSV = glob2.glob('*contact*.csv')

theDate = time=strftime("%Y-%m-%d", gmtime())
theTime = time=strftime("%H:%M:%S", gmtime())

try:
    testData = findCSV[0]
except IndexError:
    print ("\nSyncronisation attempted on {date} at {time}: There are no \"contact\" CSVs, please upload one and try again.\n").format(date=theDate, time=theTime)
    print("====================================================================================================================\n")
    sys.exit()

for theCSV in findCSV:

    def get_companies():
        create_get_recent_companies_call = "https://api.hubapi.com/companies/v2/companies/?hapikey={hapikey}".format(hapikey=wta_hubspot_api_key)
        headers = {'content-type': 'application/json'}
        create_get_recent_companies_response = requests.get(create_get_recent_companies_call, headers=headers)
        if create_get_recent_companies_response.status_code == 200:

            offset = create_get_recent_companies_response.json()[u'offset']
            hasMore = create_get_recent_companies_response.json()[u'has-more']

            while hasMore == True:
                for i in create_get_recent_companies_response.json()[u'companies']:
                    get_more_companies_call = "https://api.hubapi.com/companies/v2/companies/?hapikey={hapikey}&offset={offset}".format(hapikey=wta_hubspot_api_key, offset=offset)
                    get_more_companies_call_response = requests.get(get_more_companies_call, headers=headers)
                    companyName = i[u'properties'][u'name'][u'value']
                    print("{companyName}".format(companyName=companyName))


        else:
            print("Something went wrong, check the supplied field values.\n")
            print(json.dumps(create_get_recent_companies_response.json(), sort_keys=True, indent=4))

    if __name__ == "__main__":
        get_companies()
        sys.exit()

问题在于它只是不断返回相同的初始 100 个结果;发生这种情况是因为参数"has-more":True 在初始调用时为真,所以它只会继续返回相同的...

我的理想方案是我能够解析大约 120 个响应页面中的所有公司(大约有 12000 家公司)。当我通过每个页面时,我想将它的 JSON 内容附加到一个列表中,这样最终我就有了这个列表,其中包含所有 120 个页面的 JSON 响应,以便我可以解析该列表以用于不同的功能.

我迫切需要一个解决方案:(

这是我在主脚本中替换的函数:

            def get_companies():

                create_get_recent_companies_call = "https://api.hubapi.com/companies/v2/companies/recent/modified?hapikey={hapikey}".format(hapikey=wta_hubspot_api_key)
                headers = {'content-type': 'application/json'}
                create_get_recent_companies_response = requests.get(create_get_recent_companies_call, headers=headers)
                if create_get_recent_companies_response.status_code == 200:

                    for i in create_get_recent_companies_response.json()[u'results']:
                        company_name = i[u'properties'][u'name'][u'value']
                        #print(company_name)
                        if row[0].lower() == str(company_name).lower():
                            contact_company_id = i[u'companyId']
                            #print(contact_company_id)
                            return contact_company_id
                else:
                    print("Something went wrong, check the supplied field values.\n")
                    #print(json.dumps(create_get_recent_companies_response.json(), sort_keys=True, indent=4))

【问题讨论】:

    标签: python json python-2.7 loops hubspot


    【解决方案1】:

    问题似乎是这样的:

    • 您在第一次调用中获得了偏移量,但不对调用返回的实际公司数据做任何事情。
    • 然后在 while 循环中使用相同的偏移量;您永远不会在后续调用中使用新的。这就是为什么您每次都得到相同的公司。

    我认为get_companies() 的这段代码应该适合你。显然,我无法测试它,但希望它没问题:

    def get_companies():
            create_get_recent_companies_call = "https://api.hubapi.com/companies/v2/companies/?hapikey={hapikey}".format(hapikey=wta_hubspot_api_key)
            headers = {'content-type': 'application/json'}
            create_get_recent_companies_response = requests.get(create_get_recent_companies_call, headers=headers)
            if create_get_recent_companies_response.status_code == 200:
    
                while True:
                    for i in create_get_recent_companies_response.json()[u'companies']:
                        companyName = i[u'properties'][u'name'][u'value']
                        print("{companyName}".format(companyName=companyName))
                    offset = create_get_recent_companies_response.json()[u'offset']
                    hasMore = create_get_recent_companies_response.json()[u'has-more']
                    if not hasMore:
                        break
                    else:
                        create_get_recent_companies_call = "https://api.hubapi.com/companies/v2/companies/?hapikey={hapikey}&offset={offset}".format(hapikey=wta_hubspot_api_key, offset=offset)
                        create_get_recent_companies_response = requests.get(create_get_recent_companies_call, headers=headers)
    
    
            else:
                print("Something went wrong, check the supplied field values.\n")
                print(json.dumps(create_get_recent_companies_response.json(), sort_keys=True, indent=4))
    

    严格来说,break 之后的else 不是必需的,但它与Zen of Python“显式优于隐式”保持一致

    请注意,您只检查一次 200 响应代码,如果您的循环内出现问题,您将错过它。您可能应该将所有调用都放在循环中,并每次检查是否有正确的响应。

    【讨论】:

    • 嗨@SiHa,感谢您的回复 - 不幸的是,这也返回了相同的结果,尽管直接返回前 100 个而不是一个接一个(这是一种改进!)
    • @Marko 抱歉,我错过了您在 while 循环内外使用不同名称(create_get_recent_companies...get_more_companies_call)的事实。这意味着,在我的初稿中,虽然在循环中获取了更多结果,但每次都会迭代 first 响应。我现在更改了名称,以便它们相同。希望它现在可以工作。
    • @SiHia 你是一个绝对的传奇人物——这完全奏效了。我还有一个问题。上面的脚本是一个“测试脚本”——我试图缩小主脚本之外的功能。然而,回到主脚本中,我需要替换的函数是我现在在上面添加的函数......你认为收集每页结果的最佳方法是什么?我打算尝试将其附加到列表中,还是您认为我可以像上面最初所做的那样“返回”它?
    • 详细说明 - get_companies() 函数实际上位于另一个函数中,并且该函数针对 CSV 中的每一行运行。我想理想情况下,我最好使用测试脚本将所有公司下拉到本地文件中,然后使用它来提取 companyId 进行所有其他操作,这比提取所有 120 页要快得多约 9000 行...
    • 我同意,将所有数据拉下来一次,然后在本地处理它可能会更快。你从get_companies() 返回什么结构很大程度上取决于你需要什么数据;如果只是名称,那么一个简单的列表就可以了,但是如果您还需要关联数据,那么可能是一个字典(或者可能只是原始 JSON)是最好的。你有你现在需要进一步进行的东西。如果您再次卡住,最好发布另一个问题。编码愉快!
    猜你喜欢
    • 2019-02-11
    • 1970-01-01
    • 1970-01-01
    • 2022-11-24
    • 1970-01-01
    • 1970-01-01
    • 2018-12-30
    • 2017-08-29
    • 1970-01-01
    相关资源
    最近更新 更多