如何在Python中为OpenFDA API实现search_after参数?
解决OpenFDA API使用search_after分页重复数据的问题
你的代码核心问题是没有指定sort参数,OpenFDA的search_after依赖明确的排序字段来定位下一页数据,缺少sort时,API无法确定分页基准,导致每次都返回初始页的内容。以下是修正后的实现:
关键改动点
- 所有请求参数统一用
params字典传递,避免URL硬编码参数的冲突 - 初始请求就指定
sort=report_number:asc(基于唯一的report_number排序,确保分页无重复无遗漏) - 确保
search_after传递的是上一页最后一条记录的report_number,与排序字段严格对应
修正后的完整代码
import requests import pandas as pd import time import math # 基础API地址,不包含任何参数 BASE_URL = "https://api.fda.gov/device/event.json" # 初始化请求参数 params = { "api_key": "XXXXXXXXXXXXXXXXXXX", "search": "date_manufacturer_received:[20250101+TO+20250509]", "limit": 1000, "sort": "report_number:asc" # 必须指定排序字段,与search_after对应 } dataframes = [] def make_request(url, req_params): while True: response = requests.get(url, params=req_params) if response.status_code == 429: print("触发速率限制,等待60秒后重试...") time.sleep(60) elif response.status_code != 200: print(f"请求失败,状态码: {response.status_code}") print(response.text) return None else: return response.json() # 初始请求 print("获取初始数据...") data = make_request(BASE_URL, params) if not data or 'results' not in data: print("初始请求无结果或响应异常") exit() df = pd.DataFrame(data['results']) dataframes.append(df) last_report_number = data['results'][-1]['report_number'] print(f"初始数据获取完成,最后一条记录编号: {last_report_number}") # 获取总记录数 total_items = data.get('meta', {}).get('results', {}).get('total', 0) if total_items == 0: print("未获取到总记录数") else: print(f"总记录数: {total_items},需请求次数: {math.ceil(total_items / 1000)}") # 分页获取剩余数据 while last_report_number: print(f"获取{last_report_number}之后的数据...") # 复制基础参数并添加search_after page_params = params.copy() page_params['search_after'] = last_report_number data = make_request(BASE_URL, page_params) if not data or 'results' not in data or len(data['results']) == 0: print("无更多数据或响应异常,结束分页") break df = pd.DataFrame(data['results']) dataframes.append(df) new_last_report = data['results'][-1]['report_number'] # 检查是否进入循环(防止重复数据) if new_last_report == last_report_number: print("未获取到新数据,结束分页") break last_report_number = new_last_report print(f"当前页数据获取完成,最后一条记录编号: {new_last_report}") # 导出CSV if dataframes: final_df = pd.concat(dataframes, ignore_index=True) final_df.to_csv("APICallTesting.csv", index=False) print(f"数据导出完成,共{len(final_df)}条记录") else: print("无数据可导出")
注意事项
- 排序字段必须唯一:
report_number是OpenFDA事件数据的唯一标识,用它排序能确保分页无重复、无遗漏 - 速率限制处理:OpenFDA对API请求有频率限制,代码中保留了429状态码的重试逻辑,可根据实际情况调整等待时间
- 异常处理:新增了非200状态码的错误提示,便于排查请求问题
内容的提问来源于stack exchange,提问作者Halofan117 Halofan
相关产品推荐
相关产品推荐

