将匹配条件的嵌套trait列表转换为pandas DataFrame
问题背景
通过OpenSea API批量获取Azuki系列NFT的特征数据时,返回的trait_type_responses为嵌套列表结构:
- 第一层每个元素对应一个NFT资产的特征集合
- 第二层每个元素是单个特征的字典,包含
trait_type、value、trait_count字段
需要提取trait_type和value字段,生成固定列顺序的DataFrame,列包含Type、Background、Mouth、Eyes、Hair、Clothing、Offhand、Ear、Neck、Headgear、Face、Special,缺失特征填充空值。
之前通过固定列表下标取值的方式,因为接口返回的特征顺序不固定、部分特征缺失,导致数据错位。
实现方案
核心逻辑是放弃按下标取值的思路,先把每个NFT的特征列表转换成trait_type: value格式的字典,再批量生成DataFrame,pandas会自动匹配列名、对缺失字段填充空值,从根源上避免顺序和缺失导致的错位问题。
针对已获取的trait_type_responses的处理代码
import pandas as pd # 预先定义需要保留的列及固定顺序 target_cols = [ "Type", "Background", "Mouth", "Eyes", "Hair", "Clothing", "Offhand", "Ear", "Neck", "Headgear", "Face", "Special" ] # 逐个转换每个NFT的特征为字典 row_list = [] for trait_list in trait_type_responses: # 字典推导式直接生成 特征名:特征值 的映射,和特征顺序无关 trait_map = {item["trait_type"]: item["value"] for item in trait_list} row_list.append(trait_map) # 生成DataFrame,指定列顺序,缺失列自动填充NaN(和None语义一致) df = pd.DataFrame(row_list, columns=target_cols) # 如果需要把空值从NaN替换为None,追加这行即可 df = df.where(pd.notnull(df), None)
优化版批量请求+转换代码(适配大数据量场景)
实际批量拉取数据时需要加请求间隔、异常捕获,避免触发接口频率限制、因单条请求失败中断整个任务:
import requests import pandas as pd import time trait_type_responses = [] # 替换为你自己的OpenSea API Key headers = {"X-API-KEY": "your_real_api_key"} target_cols = [ "Type", "Background", "Mouth", "Eyes", "Hair", "Clothing", "Offhand", "Ear", "Neck", "Headgear", "Face", "Special" ] # 按需要修改NFT id的遍历范围 for t_id in range(1, 10001): api_url = f"https://api.opensea.io/api/v1/asset/0xed5af388653567af2f388e6224dc7c4b3241c544/{t_id}/?account_address=0xed5af388653567af2f388e6224dc7c4b3241c544&include_orders=false" try: resp = requests.get(api_url, headers=headers, timeout=15) if resp.status_code == 200: traits = resp.json()["traits"] trait_type_responses.append(traits) else: # 请求状态码异常时存空列表,保证行号和t_id一一对应 trait_type_responses.append([]) # 控制请求频率,避免被接口拦截 time.sleep(0.2) except Exception as e: print(f"获取NFT #{t_id} 失败,错误信息:{str(e)}") trait_type_responses.append([]) continue # 后续转换逻辑和之前一致 row_list = [] for trait_list in trait_type_responses: trait_map = {item["trait_type"]: item["value"] for item in trait_list} row_list.append(trait_map) df = pd.DataFrame(row_list, columns=target_cols)
方案说明
- 该方法完全不依赖接口返回的特征顺序,只要
trait_type字段名正确,就能自动匹配到对应列,哪怕部分特征缺失也不会出现错位。 - 字典推导式+DataFrame原生生成的方式运行效率很高,哪怕处理上万条NFT数据也能秒级完成。
- 之前使用
json_normalize未得到预期结果,是因为原始数据是两层嵌套列表结构,先把每个子列表展平为单层字典再转换,比直接套json_normalize逻辑更简单可控。
内容的提问来源于stack exchange,提问作者mimiskims
相关产品推荐
相关产品推荐

