使用 writerows,lambda 将数据添加到特定列

Posted

技术标签:

【中文标题】使用 writerows,lambda 将数据添加到特定列【英文标题】:Add data to specific column using writerows, lambda 【发布时间】:2022-01-23 20:38:27 【问题描述】:

我已经遍历通过 API 查询返回给我的 JSON 对象,并且可以将数据 (obj_key1) 获取到我的 target_csv,但数据显示在第一列,而不是 data 列,我正在尝试指定。

示例 JSON:

['obj_key': 0.5,
  'obj_key1': 4000,
  'obj_key2': '2020-05-01',
  'obj_key3': 0.0,
  'obj_key4': 'US',
  'obj_key5': 50000,
  'obj_key6': 11,
  'obj_key7': 0.0,
  'obj_key8': 20000,
  'obj_key9': 0.01,
  'obj_key10': '6786547',
  'obj_key11': None,
  'obj_key12': 12,
 'obj_key': 0.4,
  'obj_key1': 5000,
  'obj_key2': '2020-05-02',
  'obj_key3': 0.0,
  'obj_key4': 'US',
  'obj_key5': 657435,
  'obj_key6': 112,
  'obj_key7': 0.0,
  'obj_key8': 678548,
  'obj_key9': 0.032,
  'obj_key10': '6786547',
  'obj_key11': None,
  'obj_key12': 13,...]

代码:

import csv
import json
import requests

token = token

with open('../folder/file.csv') as src, open('target_file.csv', 'w', newline='') as tgt:
    reader = csv.reader(src)
    writer = csv.writer(tgt)

    columns = next(reader)

    writer.writerow(columns)

    headers = 
        'Authorization': token,
        'Content-Type': 'application/json; charset=utf-8',
    

    for id, name, date, data in reader:

        response = requests.get(f'https://base_url/api/endpoint?start_date=2021-05-01&end_date=2021-05-15' + '&id=' + str(id),
            headers=headers
        )

        response_data = response.json()
        for i in range(len(response_data)):
            data = writer.writerows(map(lambda x: [response_data[i]['obj_key1']], range(1)))

预期的 CSV 输出:

id name date data
6786547 Name 2020-05-01 4000
6786547 Name 2020-05-02 5000

【问题讨论】:

您只获得最后一个日期的数据,因为每次执行 data = response_data[i]['obj_key'] 行时,它都会替换之前的 data 值——所以在 for 循环结束时分配的最后一个东西它将是它的价值。 @martineau 谢谢,我注意到这就是正在发生的事情。我面临的问题是解决这个问题,因此所有值都添加到 CSV,而不仅仅是替换前一个值的最后一个值。 我真的不知道输入数据的格式或 CSV 每一行中的内容,基本上你必须在 data 循环内做一些事情 - 也许写一行CSV 或累积值并使用其中一个以上的内容写入行。 我用我最近的编辑更新了上面的代码,得到了每个对象的单独数据,但现在它只显示在第一行,所以现在我必须弄清楚如何将其写入特定的“数据”列。 如果您编辑了您的问题并展示了 JSON 数据的样子以及转换为 CSV 格式后的样子的示例,将会很有帮助。 【参考方案1】:

我将推荐一些看起来非常不同,但应该可以完成工作的东西。

对我来说,最重要的想法是将流程分成不同的部分——这样每个人都更容易理解。

先阅读

我已选择将所有 API 读取保存到字典列表中,将在下一部分中使用 CSV DictWriter 写出。

import csv
import requests

path = f'https://base_url/api/endpoint?start_date=2021-05-01&end_date=2021-05-15'
token = token
headers = 
    'Authorization': token,
    'Content-Type': 'application/json; charset=utf-8',


final_rows = []
with open('../folder/file.csv') as src:
    reader = csv.reader(src)
    next(reader)  # discard this header, will be created from dict row

    for my_id, name, date in reader:  # omitted `data` from input
        response = requests.get(path + f'&id=my_id', headers=headers)

        # Assuming `response.json()` looks like the sample JSON you provided
        for json_data in response.json():
            final_row = 
                'id': my_id,
                'name': name,
                'date': date,
                'data': json_data['obj_key1']
            

        final_rows.append(final_row)

我模拟了final_rows,看起来像:

final_rows = [
    
        'id': '6786547',
        'name': 'Name',
        'date': '2020-05-01',
        'data': '4000'
    ,
    
        'id': '6786547',
        'name': 'Name',
        'date': '2020-05-02',
        'data': '5000'
    
]

然后,写

现在,final_rows 几乎会自己写:

with open('target_file.csv', 'w', newline='') as tgt:
    writer = csv.DictWriter(tgt, fieldnames=final_rows[0].keys())
    writer.writeheader()
    writer.writerows(final_rows)

我得到:

id,name,date,data
6786547,Name,2020-05-01,4000
6786547,Name,2020-05-02,5000

【讨论】:

或者只是writer.writerows(final_rows) @chepner,谢谢,修改了我的代码!【参考方案2】:

下面是如何实现我在comment 中建议的关于多次调用writerow() 并将其传递给所有四列(idnamedatedata)的方法。您也许可以对其进行优化以先创建行,然后再调用writerows(),但我怀疑这是否值得。

请注意,您忽略了响应中列表的每个对象的 'obj_key2' 中的 date 并使用正在读取的 CSV 文件中的对象,这对我来说似乎很奇怪——但这似乎是您在你的问题。

import csv
import json
import requests

token = token

with open('../folder/file.csv', 'r', newline='') as src, \
     open('target_file.csv', 'w', newline='') as tgt:
    reader = csv.reader(src)
    writer = csv.writer(tgt)

    writer.writerow(next(reader) + ['data'])  # Copy header row and add column.

    headers = 'Authorization': token,                           
               'Content-Type': 'application/json; charset=utf-8'

    for id, name, date, data in reader:
        response = requests.get(
            f'https://base_url/api/endpoint?start_date=2021-05-01&end_date=2021-05-15' 
            f'&id=id', headers=headers)

        for obj in response.json():
            writer.writerow([id, name, date, obj['obj_key1']])

【讨论】:

以上是关于使用 writerows,lambda 将数据添加到特定列的主要内容,如果未能解决你的问题,请参考以下文章

csv.writerow 在添加 for 循环后现在可以工作了吗?

Python,repl.it - 未使用 csv.writer 和 writer.writerow 将详细信息写入文件

如何将JSON数据添加到HTML AWS lambda响应主体?

Node.js中的代码AWS Lambda Package不会调用putRecord()来将数据添加到AWS Kinesis Firehose Stream中

将 Lambda 函数添​​加到 AWS AppSync 数据源?

csv.writerows() 在每一行之后放置换行符