如何将响应从request.get转换为DataFrame?

时间:2018-08-05 08:57:26

标签: python json python-requests

我有以下代码:

def flatten_json(y):
    out = {}
    def flatten(x, name=''):
        if type(x) is dict:
            for a in x:
                flatten(x[a], name + a + '_')
        elif type(x) is list:
            out[name[:-1]] = x
        else:
            out[name[:-1]] = x
    flatten(y)
    return out 

def importdata(data):
    responsedata = requests.get(urlApi, data=data, headers=hed, verify=False)
    return responsedata


def generatejson(response):
    # Generate flat json file
    sample_object = pd.DataFrame(response.json())['results'].to_dict()
    flat = {k: flat_json(v) for k, v in sample_object.items()}
    return json.dumps(flat, sort_keys=True)

response = importdata(data)
flat_json = generatejson(response)

importdata(data)返回的示例: https://textuploader.com/dz30p

此代码向API发送获取请求,获取结果以解析它们并生成JSON文件。

这很好用。

现在,我想修改importdata函数以支持分页(合并在一起的多个调用)。

所以我写了这段代码:

def impordatatnew():
...
is_valid = True
value_offset = 0
value_limit = 100
datarALL = []
while is_valid:
        is_valid = False
        urlApi = 'http://....?offset={1}&limit={2}&startDate={0}'.format(
            requestedDate,value_offset,value_limit)
        responsedata = requests.get(urlApi, data=data, headers=hed, verify=False)
        if responsedata.status_code == 200:  # Use status code to check request status, 200 for successful call
            responsedata = responsedata.text   
            value_offset = value_offset + value_limit
            # to do: merge the result of the get request
            jsondata = json.loads(responsedata)
            if "results" in jsondata:
                if jsondata["results"]:
                    is_valid = True
            if is_valid:
                # concat array by + operand
                datarALL = datarALL + jsondata["results"]
        else:
            #TODO handle other codes
            print responsedata.status_code
return datarALL

此代码使用分页。它连接到API并逐页获取结果,并将它们组合在一起成为一个列表。如果我这样做:

print json.dumps(datarALL) 我看到了组合的JSON,因此效果很好。 转储示例: https://jsonblob.com/707ead1c-9891-11e8-b651-496f6b276e89

return datarALL的示例:

https://textuploader.com/dz39d

我的问题:

我似乎无法将impordatatnew()的返回值用于generatejson()。如何使impordatatnew()的返回值与 generatejson()?我尝试进行如下修改:

def generatejsonnew(response):
    #Generate flat json file
    sample_object = pd.DataFrame(response.json()).to_dict()
    flat = {k: flat_json(v) for k, v in sample_object.items()}
    return json.dumps(flat, sort_keys=True)

它给出:

  

sample_object = pd.DataFrame(response.json())。to_dict()AttributeError:“列表”对象没有属性“ json”   我了解这一点,但我不知道如何解决。我似乎无法实现这种转换。

1 个答案:

答案 0 :(得分:1)

它不起作用,因为您这样做:

responsedata = responsedata.text   
jsondata = json.loads(responsedata)
datarALL = datarALL + jsondata["results"]

您在这里似乎要逐步建立一个列表。您可以将其简化为:

dataALL += responsedata.json()

问题稍后出现:

pd.DataFrame(response.json())

这是因为您要对已经从JSON解析为Python列表的内容再次调用json()。因此出现错误消息。

但是真正的难题是为什么要这样做:

sample_object = pd.DataFrame(response.json()).to_dict()

除了将列表重新格式化为字典之外,这实际上不是“使用熊猫”。当然,还有一种更直接的方法,例如使用for循环来构建dict(确切的说,没有样本数据我们就无法分辨)。

无论如何,如果您要填充一个DataFrame,只需删除.json()部分,它的工作方式应与原始的非分页代码类似。

但是,一种更有效的方法是使用原始代码在每个页面上简单地构造一个DataFrame,然后调用pd.concat(pages),其中pages是这些DataFrame的列表。然后无需构建dataALL

最终,您的代码可以简化得更多,最终像这样:

pd.concat(pd.read_json(url, ...) for url in all_page_urls)

也就是说,首先使用for循环来构建all_page_urls,然后使用上述单线将所有数据收集到单个DataFrame中。

参考:https://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_json.html#pandas.read_json