news 2026/6/26 11:03:47

19.API数据采集:用requests自动拉取MES数据

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
19.API数据采集:用requests自动拉取MES数据

一、问题背景:每天点"导出"要疯掉了

我们FAB的MES系统有个功能,但99%的人只用了一种方式——**手动导出**:

1. 打开MES网页

2. 填入查询条件(日期、工站、产品)

3. 点击"导出CSV"

4. 等5分钟下载

5. 打开Excel看看数据

每天要导10次,每次5分钟,一天花50分钟在"等下载"上。

偶尔忙起来忘了导出,第二天分析发现没数据。

**更难受的是**:数据自动化工具(SPC控制图、异常检测)做出来了,但没人天天喂数据给它们。

**其实MES有API接口**——给程序用的"数据取餐口"。直接调用API,3秒拿到数据。

**学完这一篇,你能做到:**

1. 用Python给API发请求,拿到数据

2. 解析JSON格式的数据

3. 把数据存下来,给其他分析工具用

────────────────────────────────────────

二、技术原理:API就是"程序之间的对话"

2.1 什么是API?

你可以把API理解成**自动售货机**:

- 你投币(发请求)→ 售货机吐出饮料(返回数据)

- 你手里不用有人(不需要登录网页)

- 24小时工作(不用等上班时间)

# 最基础的API调用

import requests

# 发请求(就像按售货机的按钮)

url = "http://mes-api.fab.local/api/lots"

response = requests.get(url)

# 看结果(售货机吐出了什么)

print(response.status_code) # 200 = 成功

print(response.json()) # 返回的数据(JSON格式)

就这两行,用数据了。

2.2 认识HTTP状态码

API调用结果好不好,先看状态码。记住这4个就够了:

| 代码 | 意思 | 怎么办 |

|------|------|--------|

| **200** | 成功 ✅ | 拿数据 |

| **401** | 没权限(Token过期) | 重新登录获取Token |

| **404** | 地址错了 | 检查URL拼写 |

| **500** | MES服务器崩了 | 等一会儿再试 |

2.3 JSON格式长什么样

API返回的数据一般是JSON,长得像Python的字典和列表:

# 假设API返回了这样的数据

data = {

"status": "success",

"count": 3,

"data": [

{"lot_id": "FAB-001", "process": "ETCH",

"thickness": 1250.5, "yield": 96.5},

{"lot_id": "FAB-002", "process": "ETCH",

"thickness": 1248.2, "yield": 95.8},

]

}

# 解析:取data字段

lots = data['data']

print(f"拿到了 {len(lots)} 批数据")

for lot in lots:

print(f" {lot['lot_id']}: 厚度={lot['thickness']}, 良率={lot['yield']}%")

**JSON和Python字典的区别**:基本一样。JSON是字符串,`response.json()` 把它转成Python的字典/列表。

────────────────────────────────────────

三、实战案例:三步写出你的API采集器

3.1 第一步:带Token的请求

大多数MES的API需要认证,最常见的方式是**Bearer Token**——相当于你的工牌:

import requests

# 你的Token(从MES IT同事那里拿)

TOKEN = "eyJhbGciOiJIUzI1NiIs..." # 一串很长的字符串

# 把Token放到请求头里

headers = {

"Authorization": f"Bearer {TOKEN}",

"Content-Type": "application/json"

}

# 发请求

url = "http://mes-api.fab.local/api/lots"

response = requests.get(url, headers=headers)

if response.status_code == 200:

data = response.json()

print(f"成功获取 {len(data.get('data', []))} 条数据")

else:

print(f"请求失败: {response.status_code}")

print(f"错误信息: {response.text}")

**为什么这样写?** `headers` 是HTTP请求的"附加信息",Bearer Token放这里,服务端读到Token就知道你是谁、有什么权限。`response.text` 是原始响应内容,调试的时候打印出来最快找到问题。

3.2 第二步:传参数筛选数据

API一般支持按日期、工站等条件筛选,用 `params` 参数:

# 筛选特定日期和工序的数据

params = {

"date": "2026-01-15", # 日期范围

"process": "ETCH", # 工站

"limit": 100 # 每页最多返回100条

}

response = requests.get(url, headers=headers, params=params)

data = response.json()

lots = data.get('data', [])

total = data.get('total', 0)

print(f"查询条件: 日期={params['date']}, 工站={params['process']}")

print(f"符合条件的数据: {total} 条, 本次返回: {len(lots)} 条")

**为什么这样写?** `params` 会自动拼接到URL后面变成 `/api/lots?date=2026-01-15&process=ETCH&limit=100`。用字典管理参数比直接拼字符串更安全(requests会自动处理特殊字符编码)。

3.3 第三步:自动处理分页

如果数据量大,API不会一次全部返回。需要"翻页":

def collect_all_lots(date, process, headers):

"""

采集指定日期和工序的全部Lot数据(自动翻页)

参数:

date: 日期字符串 "YYYY-MM-DD"

process: 工序名 "ETCH"

headers: 请求头(含Token)

返回:

list: 所有Lot数据的列表

"""

base_url = "http://mes-api.fab.local/api/lots"

all_lots = []

offset = 0

limit = 100

while True:

# 请求一页

params = {"date": date, "process": process,

"limit": limit, "offset": offset}

response = requests.get(base_url, headers=headers, params=params)

if response.status_code != 200:

print(f"第{offset//limit+1}页请求失败: {response.status_code}")

break

data = response.json()

page_lots = data.get('data', [])

total = data.get('total', 0)

# 把这一页的数据加入总列表

all_lots.extend(page_lots)

print(f"第{offset//limit+1}页: 获取 {len(page_lots)} 条, "

f"累计 {len(all_lots)}/{total} 条")

# 如果已经拿完所有数据,退出循环

offset += limit

if offset >= total:

break

return all_lots

# 使用

headers = {"Authorization": f"Bearer {TOKEN}"}

lots = collect_all_lots("2026-01-15", "ETCH", headers)

print(f"共采集 {len(lots)} 批Lot数据")

**为什么这样写?** 用 `while True` + `offset` 翻页是API采集的标准模式——每次请求一批,用完 `offset += limit` 后继续,直到 `offset >= total` 停止。`all_lots.extend(page_lots)` 比 `append` 更高效,因为 `extend` 直接把列表展开添加。我把整个逻辑封装成一个函数,以后调用就一行 `collect_all_lots("2026-01-15", "ETCH", headers)`,不用重复写翻页逻辑。

3.4 加上异常处理

def safe_collect(date, process, token):

"""

安全的数据采集函数

自动处理:网络超时、认证失败、服务器错误

永不崩溃——出错就打印日志,返回已经采集到的数据

"""

headers = {"Authorization": f"Bearer {token}"}

all_lots = []

try:

all_lots = collect_all_lots(date, process, headers)

except requests.exceptions.Timeout:

print("⚠ 请求超时!网络连接不稳定")

except requests.exceptions.ConnectionError:

print("⚠ 连接失败!请检查网络或MES服务是否正常")

except requests.exceptions.RequestException as e:

print(f"⚠ 请求异常: {e}")

# 即使出错了,也返回已成功采集的部分

print(f"最终采集结果: {len(all_lots)} 条")

return all_lots

# 使用

token = "YOUR_TOKEN_HERE"

data = safe_collect("2026-01-15", "ETCH", token)

# 可以用采集到的数据做其他事了

if data:

yields = [lot.get('yield', 0) for lot in data]

print(f"最低良率: {min(yields):.1f}%, "

f"最高良率: {max(yields):.1f}%, "

f"平均良率: {sum(yields)/len(yields):.1f}%")

**为什么这样写?** `try-except` 包裹整个采集过程,让程序不管遇到什么网络问题都不会崩溃。`requests.exceptions` 下有好几种异常类型,区分捕获方便针对性处理。最关键的是——**出错不要只报错,要返回已有的数据**。采集到99批,哪怕第100批失败了,99批也能用。

────────────────────────────────────────

四、效果对比

| 对比维度 | 手动导出 | API采集 | 提升 |

|---------|---------|--------|------|

| 单次耗时 | 5分钟 | 1-3秒 | **+100倍** |

| 每日操作 | 重复10次手动操作 | 跑一次脚本 | **全自动** |

| 数据完整性 | 容易忘记或漏选条件 | 固定参数、100%覆盖 | **零遗漏** |

| 出错处理 | 手动重新操作 | 自动重试+异常处理 | **省心** |

| 后续扩展 | 再分析要重新导出 | 存了数据直接给分析工具用 | **一次采集多次使用** |

────────────────────────────────────────

五、自己动手

# 练习:这里有一个模拟的API(不需要真的MES)

import requests

# 模拟API(公开的测试接口)

url = "https://jsonplaceholder.typicode.com/posts"

# 练习1:用GET请求获取数据

# 练习2:筛选出userId=1的数据(用params)

# 练习3:把数据存到本地CSV文件

# ✏️ 下面写你的代码

**思考题**:

1. 如果API返回了500错误,你的程序会不会崩溃?if语句和try-except哪个更好?

2. 如果你每天要采集5个不同工序的数据,怎么设计代码不重复?

3. 采集的数据怎么保存?存CSV、JSON、还是SQLite?

────────────────────────────────────────

六、常见误区

| 问题 | 表现 | 解决方法 |

|------|------|---------|

| **忘了加Token** | 一直返回401 | 检查headers里有没有Authorization字段 |

| **URL末尾多了一个/或少了** | 返回404 | 跟API文档核对URL |

| **以为一次能拿完** | 只拿到100条 | 检查有没有分页参数(limit/offset/cursor) |

| **params传了列表** | requests参数编码异常 | 用 `params={'ids': [1,2,3]}` 会自动处理 |

| **没做异常处理** | 网络波动直接崩溃 | 加try-except,即使错也要有返回值 |

| **请求太频繁** | 被MES封IP | 每次请求之间加 `time.sleep(1)` 降速 |

────────────────────────────────────────

> �� **你们MES有API接口吗?你对接时踩过什么坑?评论区聊聊**

> �� **收藏+点赞,后面讲到数据清洗和预处理会用到这里采集的数据** ��

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/26 11:02:46

MC9S08MP16硬件CRC模块详解:从CRC-CCITT原理到嵌入式高效校验实践

1. 项目概述与CRC核心价值在嵌入式开发,尤其是涉及通信协议、数据存储或固件升级的项目里,数据完整性校验是保证系统可靠性的基石。你肯定遇到过这样的场景:通过串口接收一帧数据,或者从Flash读取一段配置,怎么才能确信…

作者头像 李华
网站建设 2026/6/26 11:02:31

MC9S08MP16键盘中断与CPU机制:从寄存器配置到低功耗应用

1. 项目概述与核心价值在嵌入式系统开发中,中断机制是实现实时响应和高效任务管理的基石。它就像一位时刻待命的“管家”,当主程序(好比“主人”)正在处理日常事务时,一旦有紧急事件(如按键按下、定时器溢出…

作者头像 李华
网站建设 2026/6/26 11:01:41

深入解析MC9S08MP16 FTM模块PWM模式与同步机制

1. 项目概述与核心价值如果你正在使用飞思卡尔(现恩智浦)的MC9S08MP16系列微控制器,并且项目中涉及到电机控制、LED调光、开关电源或者任何需要精确时序和波形生成的场景,那么你大概率绕不开它的FlexTimer模块,也就是我…

作者头像 李华
网站建设 2026/6/26 11:00:22

UART本地回环与FIFO中断优化:嵌入式通信稳定与性能提升实践

1. 项目概述:从手册到实践,拆解UART的“自检”与“缓冲”艺术搞嵌入式开发的兄弟们都清楚,UART(通用异步收发传输器)这玩意儿,就像系统里的“老黄牛”,串口调试、设备通信、日志输出&#xff0c…

作者头像 李华
网站建设 2026/6/26 10:59:31

深入解析PCI总线:配置空间与仲裁机制实战指南

1. 项目概述:从手册到实战,拆解PCI总线的核心机制 如果你曾经调试过一块PCI或PCIe的扩展卡,或者在嵌入式系统里集成过外设控制器,大概率会碰到一个让人头疼的场景:系统启动后死活识别不到设备,或者设备间歇…

作者头像 李华
网站建设 2026/6/26 10:59:31

{{title}} - 技术设计文档

{{title}} - 技术设计文档 【免费下载链接】typora_plugin Typora Plugin. Feature Enhancement Tool | Typora 插件,功能增强工具 项目地址: https://gitcode.com/gh_mirrors/ty/typora_plugin 1. 概述 创建时间: {{date}} 作者: {{author}} 版本: {{versi…

作者头像 李华