You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 01:28:11