ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

机器学习项目中的API数据获取:从请求到结构化数据集的完整指南

机器学习项目中的API数据获取:从请求到结构化数据集的完整指南 100天机器学习计划走到第17天课程开始从“直接读现成CSV”切换到“从API获取数据”。这一步看起来只是多了一个网络请求实际上会把项目流程从单机文件处理推到真实数据采集场景。API返回的JSON要解析、要清洗、要整理成表格还要处理鉴权、分页和限流这些问题在后面的任何完整机器学习项目里都会反复出现。这篇文章就按一遍实测顺序拆开先做哪些准备怎么写最小请求怎么处理批量拉取怎么把原始返回变成能进模型的数据集最后给一套排查顺序。1. 为什么要把“从API获取数据”当成独立环节1.1 API数据在机器学习流程里的位置机器学习项目第一步不是建模而是拿数据。前几天的练习通常用的是本地CSV、sklearn自带数据集、Kaggle下载好的压缩包这类数据已经被人处理过字段干净缺失值少标签齐全。真实项目不是这样数据源可能是一个天气平台、一个行情服务、一个内容系统多数情况下只能通过API按条件取数。API是服务器对外提供数据访问的接口。你发一个请求过去服务器把结果返回来常见格式是JSON。从API获取数据就是要完成“请求—接收—解析—结构化”这一整条链路数据拿到手之后才能进入特征工程和模型训练。放在100天机器学习这种长周期学习计划里第17天安排API数据获取意味着课程开始从“读懂现成数据”进入“自己取数”阶段。这个转变很关键因为实际工程里最耗时间的往往不是调模型而是把散落在各个接口里的数据收拾成一张能用的表。1.2 通过API取数和下载文件数据的差别很多初学者会问为什么不直接下载一个文件非要调API。两者最核心的差异有三个。第一文件是快照API是实时窗口。下载好的CSV永远不会自动更新API可以在每次调用时拿到最新数据。需要做预测、监控、定时建模的项目基本离不开API。第二API返回结构更复杂。CSV打开就是行列结构JSON则可能是多层嵌套data字段下面还有listlist里又有对象。解析API返回内容本身就是一项技能。第三错误处理方式不同。文件下载失败通常表现为“没下载下来”API调用失败会返回状态码、错误体、限流提示甚至返回200但内容为空。判断成功与否的标准更复杂。1.3 这篇文章适合谁看如果你正在跟100天机器学习这类长周期教程刚学过pandas和基础Python想开始做完整项目这篇文章适合你。如果你在做一个需要天气数据、行情数据、新闻内容或其他线上数据的小项目也可以按这套流程快速接入。需要说明的是我下面用到的URL和字段名都是示例你实际使用时必须以目标API官方文档为准不同服务差异很大。2. 调用API之前先把环境、密钥和文档确认清楚2.1 环境准备从API获取数据基础环境不需要太重。Python 3.9以上版本通常够用核心依赖只有两个requests和pandas。requests用来发HTTP请求pandas用来把解析结果转成表格。json是Python内置库不需要单独安装。建议创建一个虚拟环境尤其是你机器上同时有多个项目的时候。不同项目依赖版本可能冲突虚拟环境可以避免每次换项目都重装一堆包。python -m venv dataenv # Windows dataenv\Scripts\activate # macOS / Linux source dataenv/bin/activate激活环境后安装依赖pip install requests pandas安装完成后不要急着写代码先确认版本。常见环境下requests和pandas都能正常安装但如果公司网络或学校网络有额外限制换镜像源或者重新装一遍python环境再试。2.2 API密钥和鉴权方式大部分线上API都不是裸奔的需要密钥才能访问。常见的鉴权方式有三种。第一种Header里带密钥。很多RESTful API要求请求头加Authorization字段代码长这样headers { Authorization: Bearer YOUR_API_TOKEN, Content-Type: application/json }第二种URL参数里带key。个别API会把密钥直接放在查询参数里比如https://api.example.com/data?keyxxx。这种方式直观但密钥容易出现在日志里生产环境不太推荐。第三种OAuth2流程。需要先请求一个token再拿token访问业务接口。第一次学API取数不建议直接用这种类型前置步骤多调试成本高。不管用哪种密钥都要放环境变量或者本地配置文件里不要直接写在公开代码仓库中。教程代码里经常能看到明文key那是为了演示实际项目里一定要避免。2.3 拿到文档先看这六个信息从API获取数据最忌讳不看文档直接猜。猜字段名和参数运气好十分钟调通运气不好会浪费半天。我一般拿到一个API文档会先找六项信息Base URL所有接口共用的基础地址Endpoint具体路径比如/v1/weather请求方式GET、POST还是PUT必选参数哪些不传会直接报错返回格式JSON还是XML字段结构长什么样限流规则每分钟或每天最多多少次请求六项信息确认完再开始写第一个请求。尤其要看返回示例很多文档会贴一小段JSON那就是你解析时的地图。2.4 新手优先选择公开免费API学习阶段不需要一上来就找复杂的商业API。公开的天气接口、股票行情接口、公共数据平台通常文档清晰返回结构简单也容易找到示例。股票行情、天气数据、新闻内容都是比较典型的学习案例。等把基础流程跑通再换成数据量更大、鉴权更复杂的真实业务API。注意免费API通常有调用次数限制批量拉取之前先看清楚额度不要跑一次循环直接把当月配额用完。3. 从最小请求开始一条GET请求跑通全流程3.1 先写一个能返回200的最小案例不管目标API多复杂第一次调用都建议从最小请求开始。先不处理鉴权、分页、批量只发一条最简单的GET请求目标是拿到成功响应并打印状态码。import requests url https://api.example.com/v1/weather params { city: beijing } response requests.get(url, paramsparams, timeout10) print(response.status_code) print(response.text[:500])这里加timeout是必须的。如果不加请求可能一直挂在那里程序卡住你还要花时间排查。设10秒或15秒超时后会直接抛异常问题暴露得越早越好。第一次运行时可能会出现三种情况返回200打印出一段JSON字符串说明通了一半。返回401或403说明密钥有问题检查Header。返回404说明Endpoint或Base URL写错了去文档重新核对。3.2 先打印返回结构再决定怎么解析看到200之后下一步不是立刻转DataFrame而是先把返回的JSON结构完整打印出来。为什么先做这一步因为你不知道字段嵌套了几层不知道列表嵌在哪个对象下直接套pd.DataFrame(response.json())大概率得到一堆怪东西。import json data response.json() print(json.dumps(data, ensure_asciiFalse, indent2)[:1000])把返回内容格式化输出字段层级会变得很清楚。比如很多API会返回一个主对象里面有code、message、data三个字段真实数据在data下面。你直接转data才是对的转整个结果就会把code和message也当成一列不是你想要的结构。还有一种常见情况是data下面还有listlist里才是每一条记录。遇到这种嵌套结构就要先取出list再转成表。3.3 把JSON结构整理成DataFrame并保存拿到真实列表之后用pandas转成表就很自然了。import pandas as pd records data.get(list, []) df pd.DataFrame(records) print(df.head()) print(df.shape)转完DataFrame之后建议立刻做两件事检查行列数是否符合预期把结果保存成CSV。df.to_csv(weather_data.csv, indexFalse, encodingutf-8-sig)保存CSV是因为API数据是易变的同一个参数过一会儿再查可能就变了。存到本地后后面所有调试都基于这份快照不会因为网络波动导致结果对不上。encodingutf-8-sig是为了让Excel打开CSV时不乱码Windows环境尤其建议加这个参数。3.4 最小请求成功后的判断标准一次最小请求完全跑通至少要满足四个条件状态码是200返回内容能被json.loads正确解析DataFrame的行数和列数符合API返回的记录条数CSV保存后能重新读回来字段不丢中文不乱码如果只满足前两条说明请求通了但数据解析还没做好。如果所有条件都满足就可以进入下一步考虑分页和批量。4. 处理分页、限流和批量获取4.1 为什么单条请求远远不够真实业务里一次API请求返回的记录数往往有限制可能是20条、50条、100条。你想拉一个城市过去一年的天气或者一个股票代码几个月的历史行情一个请求根本拿不全。这时就要用到分页。分页方式常见有三种pagepage_size像翻书一样一页一页翻。offsetlimit跳过多少条取多少条。cursor/next_cursor服务器给你一个游标下一次请求带上游标取下一页。不管哪种思路都一样循环发送多次请求把所有分页数据拼起来。4.2 一个通用分页拉取示例以常见的page形式为例代码结构大概是这样的all_records [] page 1 page_size 100 while True: params { page: page, page_size: page_size, city: beijing } response requests.get(url, paramsparams, headersheaders, timeout15) data response.json() records data.get(list, []) all_records.extend(records) total data.get(total, 0) if page * page_size total: break page 1 time.sleep(0.5)这里有几个细节要注意。time.sleep(0.5)是主动限流。很多API对每秒请求次数有硬限制连续快速请求很容易触发429。加一个短暂停顿虽然慢一点但稳定得多。循环结束条件是用page * page_size total这是最常见的写法。但有些API返回的total并不可靠或者根本不返回total。这时可以改成当这一页返回的记录数小于page_size时说明已经到最后一页break退出。4.3 批量拉取前先算一笔账不要拿到分页代码就直接全量拉。先根据文档和业务需求算一下需要多少请求。假设一次返回100条总量10000条那至少要100次请求。如果API限流是每秒2次100次请求需要至少50秒。这只是非常粗略的估算具体参数以你的目标API为准。算这笔账的意义是让你对任务耗时和额度有心理预期。如果估算下来需要几万次请求那说明这个API可能不适合全量拉取要么申请更高权限要么换数据源要么只拉最近一段时间的增量数据。注意不要一上来就开最大并发。低并发能跑通不代表高并发能稳定跑通先把单次请求、小批量循环跑顺再考虑提高速度。4.4 失败重试和断点续拉批量请求越多中途失败的概率越大。网络抖动、服务端超时、限额触发都可能让循环中断。如果没有任何容错机制一旦中断就要从头跑既浪费时间又浪费额度。我建议在循环里加一个简单的重试逻辑。比如请求失败后等待2秒重试一次连续失败三次就跳过当前页并打印日志。for attempt in range(3): try: response requests.get(url, paramsparams, headersheaders, timeout15) if response.status_code 200: break except requests.exceptions.RequestException as e: print(fpage {page} error: {e}) time.sleep(2) else: continue更稳妥的方式是断点续拉。每成功拉取一页就把这页数据追加写入CSV同时记录当前页码。这样即使中途崩了下次也能从断点继续不用全部重来。4.5 把数据缓存到本地避免重复请求同一个时间段的数据如果只是换了一个参数或者换了一个脚本建议直接把拉取结果缓存到本地文件。比如文件名带上日期和参数weather_beijing_2025-01-01.csv这样调试特征工程时直接读本地文件不用反复请求API速度快也不消耗额度。只有需要更新数据时再重新拉取。5. 把API原始数据整理成机器学习数据集5.1 原始JSON为什么不能直接进模型见过很多人拿到API返回之后直接把整个JSON塞进模型结果报错一堆。原因很简单模型要的是结构化表格不是嵌套字典。原始JSON里常见的问题有时间字段是字符串比如2025-01-01T00:00:00Z需要转成datetime数值字段可能是字符串需要转float或int部分字段可能缺失输出里直接是null存在重复记录同一个ID出现多次字段名风格不统一有的叫user_name有的叫username所以在进入模型训练之前一定要做结构化清洗。5.2 清洗和扁平化的标准步骤第一步把嵌套字段抽出来。如果一条记录里有一个location对象里面有city和country可以拆成location_city和location_country两列。pandas处理这个很方便df[location_city] df[location].apply(lambda x: x.get(city) if x else None)第二步时间字段统一格式。把字符串转成pandas的datetime类型方便后面按时间筛选和聚合。df[timestamp] pd.to_datetime(df[timestamp]) df df.sort_values(timestamp)第三步去重。根据业务主键判断比如天气数据可能用city timestamp去重行情数据可能用code timestamp去重。df df.drop_duplicates(subset[city, timestamp])第四步处理缺失值。缺失比例低的可以直接删掉缺失比例高的要分析原因是API字段本身就没有还是请求参数导致的部分记录缺字段。5.3 构造特征时最值得注意的两个点API拿到的原始字段通常不能直接作为最终特征要通过特征工程构造更有意义的输入。以天气数据为例原始数据可能包含温度、湿度、风速三个字段但你想预测的是明天是否下雨那就要从这三个基础字段里构造出温差、湿度变化率、连续几天的平均风速等特征。特征构造有一个容易踩的坑时间序列数据不能使用未来信息。比如你在预测t1时刻的结果那么t1时刻的真实特征只能作为标签不能同时作为特征参与训练否则会造成数据泄漏。这一点在从API拉取历史数据做回测时尤其重要。5.4 标签到底从哪里来从API获取数据做大模型、分类或回归任务时标签来源通常有三个API返回结果里本身就带标签字段比如一个内容审核接口返回label字段标签来自另一个数据源比如天气数据加上“是否下雨”的观测记录标签通过业务规则生成比如根据股票下一周期的涨跌生成up/down标签标签和特征要分开保存尤其是训练集测试集拆分时不要把标签混在特征文件里让模型直接读。5.5 推荐的数据集保存结构简单项目可以直接用一整个CSV。多特征、多时间批次的项目我更喜欢把数据集分成特征文件和标签文件再加一个元数据文件记录数据来源和拉取时间。dataset/ features.csv labels.csv meta.jsonmeta.json里可以写数据源、时间范围、拉取时间、版本号。这个信息看着不起眼等你一周后回头做实验时会发现它特别重要。没有元数据你根本不知道手里这份数据是什么时候拉的、用了哪些参数。6. API调用中的常见错误与排查顺序6.1 先看懂状态码再决定排查方向从API获取数据时状态码是最直接的错误信号。我整理了一份常用排查表状态码常见含义优先排查方向200请求成功检查返回内容是否符合预期400参数错误或请求体异常参数名、参数类型、请求体长度401未认证密钥是否缺失、格式是否正确403无权限密钥权限、套餐限制、地区限制404地址不存在Endpoint路径、版本号、Base URL429请求过于频繁限流规则、请求频率、是否有退避500服务端错误等待重试偶尔一次不用过度处理503服务暂不可用服务端维护或过载延迟重试看到401和403时不要先去改代码逻辑先检查密钥。很多API要求Header里写Authorization: Bearer xxx少一个空格都会导致认证失败。把密钥放在环境变量里读取也方便排查因为你看不到明文key时反而更容易发现是环境变量没加载成功。6.2 400错误不要只看状态码要读返回体很多时候返回400状态码本身并不能告诉你哪里错了。真正的错误原因在响应体里。以现在很多大模型API为例请求超长或格式不对时返回体里会直接写“超出最大上下文长度”或“不支持的模型名”。如果只盯着状态码很容易走弯路。正确做法是每次请求失败后都把响应体完整打印出来而不是只打印状态码。response requests.get(url, paramsparams, headersheaders, timeout15) if response.status_code ! 200: print(Status:, response.status_code) print(Body:, response.text)拿到响应文本后先找error、message、detail这几个字段大多数API会把具体原因放在里面。6.3 推荐一套固定排查顺序我调试API时基本按照下面这个顺序很少会漏掉问题。第一步看现象。是报错、卡住、还是返回了数据但字段不对。第二步看响应体。很多问题在响应的错误字段里已经写清楚了。第三步看请求URL和参数。把实际发送的URL打印出来人工核对一下参数有没有拼错。必选参数是否都传了可选参数有没有用错格式。第四步看鉴权。检查headers是否带了密钥是否有效是否过期。第五步看数据范围。如果参数是一个时间范围检查起止时间是否合理范围是不是太大。第六步看网络和超时。有些请求本身很慢timeout设太短会导致误报失败。整套顺序的核心思路是先排除最好排除的再往深处查。不要一报错就怀疑是工具、库或者网络坏了。6.4 看起来像API问题实际经常是数据格式问题还有一种常见情况是请求返回200但后面所有代码都在报错。这种问题最容易误导人因为你会以为是解析代码写错了结果发现是数据本身有问题。比如API返回的某个字段可能是None但你的代码默认它一定是字符串调用.strip()就直接报错。再比如某个数值字段在正常情况下返回100少数情况下返回N/Apandas读进来之后类型就乱了。这些问题靠打印前几行数据是发现不了的因为前几条往往正常。建议批量拿到数据后先对每个关键字段调用describe()或value_counts()看一眼分布和类型。print(df.dtypes) print(df.isnull().sum())7. 从单次拉取到定时任务新手落地建议7.1 为什么真实项目需要定时拉取很多机器学习场景不是一次性建模就结束了。你需要定期更新训练数据或者定时把最新的API数据拉下来做预测。如果每次手动执行脚本很容易漏掉某一天的更新。定时任务就是解决“有人记住并且按时代码运行”这个问题。Python里有几个常见做法使用schedule库在脚本内部循环调度使用系统cronmacOS / Linux或任务计划程序Windows使用Airflow、Prefect这类专业调度工具不过对新手来说偏重入门阶段schedule最快简单任务够用。import schedule import time def job(): print(开始拉取API数据) # 执行你的数据拉取和保存逻辑 schedule.every().day.at(06:00).do(job) while True: schedule.run_pending() time.sleep(60)7.2 增量更新比全量更新更现实刚开始做定时任务时最容易犯的错误是每次运行都把全部数据重新拉一遍。如果数据量很小这没什么问题。但数据量变大之后就非常浪费API额度扛不住运行时间也越来越长。增量更新的思路是只拉上次更新到现在的数据。前提是API支持按时间范围过滤或者你本地记录了上次拉取到的最后一个ID或时间戳。把断点信息存到一个文件或数据库里下次运行先读这个值再作为参数传进API请求。增量更新需要额外处理时间边界。比如你上次拉到了今天0点的数据这次从0点开始继续拉偶尔会因为时区、延迟导致少量重复数据。重复数据一定要在清洗阶段做去重而不是完全相信断点参数。7.3 给长期运行的任务加日志和失败告警定时任务跑起来之后最怕的不是报错而是静默失败。程序没有正常退出也没有产生数据但没有任何日志你可能过了一周才发现。建议每次运行至少记录以下信息任务开始时间和结束时间拉取到的记录条数成功请求数和失败请求数失败请求的URL和错误摘要输出文件路径这些信息写入单独的日志文件不要直接print完就不管。定期查看日志能及时发现API参数变更、限流加重等问题。7.4 我给新手的最终落地顺序如果你今天第一次接触从API获取数据我建议不要同时做太多事情。先把最小请求跑通再加鉴权再处理分页再做定时任务一步一步来。具体顺序可以这样安排找一个文档清晰的免费API手动访问一次接口确认返回结构用Python写最小请求返回200并打印JSON把JSON转成DataFrame保存CSV添加分页循环拉取一个完整时间段的数据加错误处理和重试数据清洗并构造特征最后再上定时任务和增量更新每一步都要有明确的成功标准。第2步成功标准是浏览器或工具能拿到数据第3步成功标准是脚本能打印状态码和响应体第4步成功标准是CSV能重新读回。只有前一步稳了才开始下一步。7.5 真正要盯住的不是接口数量而是数据质量从API获取数据这个环节最容易让人产生误解的是觉得API越强大、数据源越丰富越好。实际做下来你会发现真正影响模型效果的是数据质量。字段对不对、时间是否连续、缺失多不多、重复多不多这些比接口本身重要得多。等你跑过几次完整流程后也会发现很多报错并不是API能力不行而是参数拼错、密钥无效、返回字段类型变了这类前置问题。把这些基础问题处理干净后面的模型训练才会顺畅。
返回列表