Granta MI Scripting Toolkit 是材料信息管理平台 Granta MI 提供的编程访问入口,在需要批量、重复、定时导出材料数据时,它比界面手工导出要可靠得多。实际项目中,开发者常用它把 Granta MI 里的材料记录、属性、表格数据和关联文件同步到本地、数据仓库或下游系统,也会用它生成定期材料数据快照。这个主题的学习难点不在单个语法,而在连上服务器后如何正确查询记录、读取属性、处理编码、写出文件,并在失败时能快速定位问题。本文围绕使用 Granta MI Scripting Toolkit 导出数据这条主线,从环境准备、最小脚本、细节处理和定时调度几个方面展开,适合负责材料数据管理、需要把 MI 数据接入外部系统的开发者阅读。
1. 先理解 Scripting Toolkit 在材料数据导出中的定位
1.1 从界面导出到脚本导出的变化
Granta MI 自带查询界面和导出功能,适用于临时取数、人工确认、数据量比较小的场景。界面操作虽然直观,但要重复导出同一批材料属性、每周生成一次报告、或把数据交给下游系统时,手工导出很难保证每次的查询条件、显示字段、文件格式完全一致。稍微改一个筛选条件就可能漏掉几十条记录,而且操作过程难以审计。
Scripting Toolkit 的价值在于把“连接、查询、取属性、写文件”变成可保存、可版本管理、可重复执行的代码。脚本一旦写好,每次执行结果都基于同一套逻辑。即使下游系统需要调整字段,也只需要修改代码里的属性列表和输出格式,不需要在界面上重复点击。
1.2 适合用脚本导出的典型场景
在实际落地时,以下几类场景最容易从界面导出迁移到脚本导出:
- 每月或每周生成材料属性快照,用于项目归档。
- 把 Granta MI 中的材料数据同步到数据仓库、ERP 或自研选材系统。
- 在系统迁移或数据治理前,对全量材料数据做一次可审计的导出。
- 将材料数据接入数据分析流程,例如训练材料性能预测模型。
- 将 MI 中的表格数据、曲线数据、附件文件批量导出到共享盘或对象存储。
这些场景的共同点是:数据量大、执行频率稳定、输出结果需要被后续程序消费。脚本导出比手工导出更适合自动化,也更容易与现有运维体系结合。
1.3 脚本导出的核心不只是“生成文件”
脚本导出真正的价值是让数据导出结果可重复、可校验、可追溯。很多初级脚本只是把数据打印到屏幕,或者覆盖写一个 CSV,缺少日志、行数统计和异常处理。这样的脚本在测试环境能跑,进入生产后就很难排查:不知道哪一次导出成功,不知道文件里是否包含全部记录,也不知道失败发生在连接阶段还是写入阶段。
因此,一个合格的导出脚本至少要在输出文件中记录三方面信息:导出时间、导出的记录范围、成功记录数。如果出现异常,还应当把异常类型、堆栈和当时的查询条件写入日志。后面的章节会围绕这些要求逐步展开。
2. 准备运行环境:Python、SDK 和连接参数
2.1 环境要求
Granta MI Scripting Toolkit 通常以 Python 包或离线 wheel 文件形式提供。准备环境前,先确认几项基础信息:
| 项目 | 建议要求 | 说明 |
|---|---|---|
| Python 版本 | 3.8 及以上 | 不同版本 SDK 对 Python 版本要求不同,以交付文档为准 |
| 网络环境 | 能访问 Granta MI 服务器,或内网隔离环境 | 需要确认服务器地址、端口、证书是否可达 |
| 安装包 | wheel 文件或内部软件源 | 如果无法访问外网,优先使用管理员提供的离线包 |
| 下游依赖 | openpyxl、pandas、requests 等 | 按实际输出格式和脚本复杂度选择 |
| 账号 | 只读查询账号即可 | 导出场景不建议使用管理员账号 |
环境准备的关键不是“能装包”,而是“连接参数正确”。如果服务器地址、数据库名、账号权限有一点不匹配,后续所有脚本都会在连接阶段失败。
2.2 安装 Scripting Toolkit
在能够访问内部软件源的环境中,安装命令通常是:
pip install grantami-scripting-toolkit如果 Granta MI 部署在隔离内网,管理员通常会提供一个 wheel 文件,可以使用本地文件安装:
pip install grantami_scripting_toolkit-xxx-py3-none-any.whl安装完成后,可以先查看包是否被正确识别:
pip show grantami-scripting-toolkit python -c "import grantami_scripting_toolkit; print(grantami_scripting_toolkit.__version__)"这里的包名、版本号、导入路径以你实际拿到的安装包为准。不同版本之间的连接方法、类名和参数命名可能有差异,遇到ModuleNotFoundError时,优先检查安装的包名是否写错,而不是怀疑代码逻辑。
2.3 准备服务器地址、数据库和凭据
连接 Granta MI 通常需要以下参数:
| 参数 | 含义 | 常见示例 |
|---|---|---|
| server | Granta MI 服务器地址 | https://mi-server.example.com |
| database | 要访问的数据库名称 | MI_Materials_V5 |
| username | 登录账号 | export_user |
| password | 登录密码或应用密钥 | 从环境变量读取 |
| timeout | 请求超时时间 | 120秒 |
| verify_ssl | 是否校验服务器证书 | 生产环境为True |
不要把密码明文写在脚本里。推荐从环境变量或密钥管理服务读取。连接示例代码如下:
import os # 示例连接代码:实际类名和参数以当前版本 SDK 为准 from grantami_scripting_toolkit import MiClient client = MiClient( server=os.environ["MI_SERVER"], database=os.environ["MI_DATABASE"], username=os.environ["MI_USER"], password=os.environ["MI_PASSWORD"], timeout=120, )注意:下面代码给出的
MiClient、query_records、fetch_attributes是流程示意。不同版本的 SDK 可能会有不同的类名和方法名,落地前先在你安装的包中打开接口文档或dir(client)确认。
3. 编写第一个导出脚本:从连接服务器到写出 CSV
3.1 导出流程拆解
一个最小可用的导出脚本,可以拆成六个步骤:
- 建立会话,连接 Granta MI。
- 确定要导出的表和查询条件。
- 查询符合条件的记录列表。
- 对每条记录读取需要的属性值。
- 把属性值组装成 CSV 行数据。
- 写出文件,并记录导出统计信息。
这个流程看似简单,但每一步都有容易出错的地方。比如查询条件写错会导致空结果,属性名写错会导致获取不到值,CSV 编码不对会导致 Excel 打开乱码。下面按步骤给出示意实现。
3.2 建立会话并查询记录
建立会话后,第一步是查询记录。以导出名称中包含 “Aluminum” 的材料记录为例:
records = client.query_records( table="Material Data", condition='Name contains "Aluminum"', )查询条件通常使用 Granta MI 过滤语法。如果条件为空,可以设置condition=None来导出指定表中的全部记录。注意,全部记录导出时数据量可能很大,最好先加limit或在 WHERE 条件里缩小范围。
3.3 读取属性并构造行数据
得到记录列表后,需要读取每条记录的具体属性。材料数据库中的属性通常包括密度、抗拉强度、屈服强度、延伸率等:
header = ["Record ID", "Name", "Density", "Tensile Strength"] rows = [] for record in records: values = client.fetch_attributes( record_id=record.record_id, attributes=["Density", "Tensile Strength"], ) rows.append([ record.record_id, record.name, values.get("Density"), values.get("Tensile Strength"), ])在实际 SDK 中,fetch_attributes的返回值可能是字典、列表或带属性的对象。关键是明确每个属性对应的数据类型,避免把列表、字典直接写进 CSV。
3.4 写出 CSV 并处理中文字节
写出 CSV 时,推荐使用 Python 标准库csv,并指定 UTF-8 with BOM 编码:
from pathlib import Path import csv out_path = Path("material_export.csv") with out_path.open("w", newline="", encoding="utf-8-sig") as f: writer = csv.writer(f) writer.writerow(header) writer.writerows(rows)使用utf-8-sig的原因是:Excel 在打开 CSV 文件时,如果文件没有 BOM,默认可能按本地 ANSI 编码解析,中文字段容易出现乱码。utf-8-sig会在文件头写入 BOM,让 Excel 识别为 UTF-8 文件。
3.5 一个最小完整脚本
把以上步骤合并成一个完整脚本:
""" 最小导出脚本示例:连接 Granta MI,查询记录,导出属性到 CSV。 实际类名、方法名、导入路径以你安装的 Scripting Toolkit 版本为准。 """ import csv import os from pathlib import Path from grantami_scripting_toolkit import MiClient # 示例导入 SERVER = os.environ["MI_SERVER"] DATABASE = os.environ["MI_DATABASE"] USERNAME = os.environ["MI_USER"] PASSWORD = os.environ["MI_PASSWORD"] client = MiClient( server=SERVER, database=DATABASE, username=USERNAME, password=PASSWORD, timeout=120, ) records = client.query_records( table="Material Data", condition='Name contains "Aluminum"', ) header = ["Record ID", "Name", "Density", "Tensile Strength"] rows = [] for record in records: values = client.fetch_attributes( record_id=record.record_id, attributes=["Density", "Tensile Strength"], ) rows.append([ record.record_id, record.name, values.get("Density"), values.get("Tensile Strength"), ]) out_path = Path("material_export.csv") with out_path.open("w", newline="", encoding="utf-8-sig") as f: writer = csv.writer(f) writer.writerow(header) writer.writerows(rows) print(f"导出完成: {out_path.resolve()}, 共 {len(rows)} 条记录")运行脚本前,先确认环境变量已经设置好:
export MI_SERVER="https://mi-server.example.com" export MI_DATABASE="MI_Materials_V5" export MI_USER="export_user" export MI_PASSWORD="your_password"然后执行:
python export_material_data.py如果连接成功,脚本会在当前目录生成material_export.csv,并输出导出记录数。
4. 导出数据时必须处理的四个细节
4.1 给记录带一个唯一标识
很多数据库导出工具都有“导出数据没有主键 ID”的问题。DBeaver 导出表数据时,如果只选择了业务字段而漏了主键,后续要用脚本核对哪一行被修改、哪一行需要回写,会非常困难。Granta MI 脚本导出也是同样道理。
导出记录时,至少要携带一个能唯一标识记录的字段。Granta MI 中常见的是记录 ID、History GUID 或记录名称。名称不一定是唯一的,两个不同批次但名称相同的材料可能同时存在,只导出名称会导致后续无法区分记录。
建议在导出表头中增加以下字段:
| 字段 | 说明 |
|---|---|
| Record ID | 记录在当前数据库中的唯一编号 |
| Record History GUID | 记录历史版本标识,适合追踪变更 |
| Name | 记录名称,便于人工阅读 |
| Last Modified Date | 最后修改时间,适合增量导出判断 |
这样导出的数据即使脱离了 Granta MI 界面,也能通过唯一标识定位到原始记录。
4.2 中文字段乱码的根源与处理
中文乱码是导出任务里最常见的问题之一。它的根源通常是“写入编码”与“读取编码”不一致。在 Granta MI 脚本导出场景中,可能出现乱码的位置有三个:
第一,脚本读取数据时,CSV 写出使用了系统默认编码。在 Windows 中文环境下,Python 的默认编码可能是 GBK;在 Linux 环境下可能是 UTF-8。同一个脚本在不同服务器上运行,结果不一样。
第二,CSV 文件本身是 UTF-8 无 BOM,Excel 却按本地 ANSI 解析。这个问题在前面已经提到,解决方案是使用utf-8-sig编码写出。
第三,下游系统按 GB2312 或 GB18030 读取文件,但文件实际是 UTF-8。这种场景需要提前确认下游编码要求。
推荐做法如下:
| 场景 | 推荐编码 | 说明 |
|---|---|---|
| 文件由 Excel 直接打开 | utf-8-sig | 带 BOM,兼容性最好 |
| 文件由 Linux 脚本读取 | utf-8 | 不带 BOM,避免多余字符 |
| 老版本中文 Excel | gb18030 | 兼容繁体简体,但要注意下游编码约束 |
如果导出结果用于数据仓库或 BI 工具,优先使用utf-8;如果结果需要业务人员用 Excel 打开,优先使用utf-8-sig。
4.3 表格数据和文件类型属性不能简单拍平
Granta MI 中的材料数据不只包含密度、强度这类单值属性,还包含曲线数据、多层表格、图片、PDF 附件等。把这类数据简单“拍平”成一个字段写入 CSV,会丢失数据结构。
表格数据建议按“一主多子”的方式处理:主文件保存记录基础属性,子表单独导出成另一个 CSV 或另一个 Excel Sheet,并通过 Record ID 关联。文件类型属性建议导出为独立文件,同时生成一个元数据清单,记录文件对应哪个 Record ID、哪个属性、保存路径和文件名。
示例输出结构:
export/ metadata.csv records.csv attachments/ record_10001_datasheet.pdf record_10002_curve.png record_10003_test_report.pdfmetadata.csv至少包含 Record ID、属性名、文件名、大小、保存路径。这样附件和主数据在后续处理时可以重新关联。
4.4 大批量导出要控制内存和请求次数
如果一次性查询几千条记录,并把所有记录的所有属性都加载到内存,脚本可能运行到一半就内存溢出或请求超时。处理大量数据时,建议采用分批获取的方式:
- 先查询记录 ID 列表,不加载全部属性。
- 每 100 条或 200 条记录为一个批次,逐批读取属性。
- 每个批次读取后立即写入文件,释放内存。
这种做法的好处是避免服务端单次响应过大,也方便在某个批次失败时重新执行,而不需要重新查询全部记录。
5. 运行验证:不要以“能打开文件”作为通过标准
5.1 文件完整性检查
脚本跑完后,需要验证生成的文件是否完整。常见检查项包括:
- 文件是否生成,路径是否正确。
- 文件大小是否在预期范围内。
- CSV 表头是否和预期字段一致。
- 空文件是否意味着查询条件或权限有问题。
一个常见的错误是:脚本连接成功,但查询条件写错,导出的 CSV 只有表头没有数据。只看“文件能打开”发现不了这个问题,必须核对记录数。
5.2 行数与关键字段校验
推荐在脚本中加入一个异步或独立的校验步骤:重新读取生成的 CSV,统计行数,并和查询到的记录数对比。也可以手工在 Granta MI 界面执行同样的查询,对比记录数。
一个简单的 Python 校验方法:
import csv expected_count = len(records) with open("material_export.csv", newline="", encoding="utf-8-sig") as f: reader = csv.reader(f) header = next(reader) exported_count = sum(1 for _ in reader) print("表头:", header) print("期望记录数:", expected_count) print("实际记录数:", exported_count)如果两个数字不一致,优先检查查询条件、分页逻辑和数据修改时间。还需要注意:导出过程中如果其他用户正在修改数据,可能出现导出时记录数和服务端实际数据不一致的情况。
5.3 编码与字段类型检查
编码问题不能等 Excel 打开后才能发现。可以在脚本里加入自动检查:
| 检查项 | 方法 | 通过标准 |
|---|---|---|
| CSV 编码 | 用openpyxl或chardet检测文件编码 | 与预期编码一致 |
| 中文字段 | 抽样读取几行,打印字段值 | 没有乱码字符 |
| 数字字段 | 抽样校验类型和范围 | 数值格式正确,没有None混入文本 |
| 记录数 | 重新读取文件统计 | 与查询结果一致 |
注意:验证脚本本身也要纳入自动化流程。每次导出后至少执行一次校验,否则导出质量问题要到下游使用数据时才会暴露。
6. 工程化:配置外置、定时任务和日志
6.1 为什么建议把连接信息放到脚本外面
生产环境中的脚本不应该把服务器地址、数据库名、密码写成硬编码。配置外置的目的有三个:不同环境之间切换时不需要改代码;敏感信息不会进入版本库;运维人员可以直接修改配置而不需要接触代码。
常见的配置外置方式包括环境变量、INI/XML 配置文件、配置中心或密钥管理服务。对中小项目而言,XML 配置文件已经足够直观。
6.2 用 XML 文件管理导出任务
下面是一个导出任务配置示例,包含保存路径、调度时间、服务器信息、数据库名称和要导出的表:
<?xml version="1.0" encoding="utf-8"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" savepath="D:\data_export\材料数据" cron="0 0 2 * * ?"> <server>https://mi-server.example.com</server> <database>MI_Materials_V5</database> <exportTables> <table name="Tensile Properties" format="excel"/> <table name="Physical Properties" format="csv"/> </exportTables> </config>配置字段说明:
| 字段 | 含义 |
|---|---|
| savepath | 导出文件保存目录 |
| cron | 定时触发表达式,Quartz 风格 |
| server | 连接服务器地址 |
| database | 访问的数据库名称 |
| exportTables | 要导出的数据表列表 |
| table/@format | 输出格式,可选 csv 或 excel |
使用 Python 解析这个配置:
import xml.etree.ElementTree as ET tree = ET.parse("export_config.xml") root = tree.getroot() save_path = root.attrib["savepath"] cron = root.attrib.get("cron", "0 0 2 * * ?") server = root.findtext("server") database = root.findtext("database") tables = [] for table in root.findall("exportTables/table"): tables.append({ "name": table.attrib["name"], "format": table.attrib.get("format", "csv"), })这种方式适合把调度任务和导出逻辑解耦。运维人员只需要维护 XML 配置,不需要改 Python 代码。
6.3 定时调度方式
导出脚本工程化后,通常会交给调度系统定时执行。不同平台的写法不同:
Windows 计划任务可以使用schtasks命令:
schtasks /create /tn "GrantaExport" /tr "python D:\scripts\export_runner.py" /sc daily /st 02:00Linux 可以使用 crontab:
0 2 * * * cd /opt/granta-export && python export_runner.py >> logs/export.log 2>&1如果使用 Quartz 风格表达式,0 0 2 * * ?表示每天凌晨 2 点触发。不同调度框架对字段含义的处理不同,配置前应和调度系统文档核对。
6.4 日志落盘和失败告警
定时任务和手工执行的区别在于:手工执行时人能发现报错,定时任务失败时可能没有任何人察觉。因此必须把日志落到文件,并设置失败通知。
建议每条日志记录以下内容:
2025-06-01 02:00:01 [INFO] 导出任务开始,数据库=MI_Materials_V5 2025-06-01 02:00:15 [INFO] 查询记录完成,records=1280 2025-06-01 02:00:32 [INFO] 写入文件完成,path=D:\data_export\材料数据\records.csv 2025-06-01 02:00:32 [INFO] 校验通过,exported=1280 2025-06-01 02:00:33 [INFO] 导出任务结束如果出现异常,至少记录异常类型、堆栈、查询条件和当前处理到的记录位置。生产环境可以在此基础上接入邮件、企业微信、钉钉或统一告警平台。
7. 常见坑与排查链路
7.1 高频问题速查
| 问题现象 | 常见原因 | 检查方式 | 处理建议 |
|---|---|---|---|
| 连接超时 | 网络不通、服务器端口未放开 | 使用 curl 测试服务器端口 | 确认网络策略、代理设置和超时参数 |
| 返回 401/403 | 账号密码错误或账号无权限 | 检查账号和数据库权限 | 使用最小权限只读账号,确认角色 |
| 导出结果为空 | 数据库选错、查询条件过严 | 在 Granta MI 界面手工查询对比 | 打印查询条件,确认表名和条件语法 |
| CSV 中文乱码 | 文件编码和读取编码不一致 | 用文本编辑器检查编码 | 写出时使用utf-8-sig,或按下游要求转码 |
| 文件写入失败 | 保存目录不存在或权限不足 | 检查目录和权限 | 脚本启动前自动创建目录并检查可写 |
| 大批量导出卡死 | 一次请求加载数据过多 | 查看日志和服务端负载 | 分批获取,限制每批记录数 |
| 脚本执行时间过长导致会话失效 | 会话超时策略 | 查看会话超时配置 | 在读取前重新认证,或延长会话超时时间 |
| SSL 证书校验失败 | 内网证书不受信任 | 查看证书链 | 测试环境可临时关闭校验,生产环境必须导入 CA 证书 |
7.2 从现象倒推根因的排查顺序
遇到导出问题时,按以下顺序排查,能避免在错误方向浪费时间:
- 检查输入参数。确认 XML 配置、环境变量中的服务器地址、数据库、保存路径是否正确。
- 检查网络和证书。服务器能否 ping 通,端口是否开放,证书链是否完整。
- 检查账号权限。当前账号是否有查询该表、读取该属性的权限。
- 检查查询条件。在 Granta MI 界面手工执行同样条件,对比结果。
- 检查代码版本和 SDK 版本。确认脚本里的类名、方法名和当前 SDK 版本一致。
- 检查日志和异常。优先看异常类型和堆栈,而不是盲目改代码。
- 与服务端管理员确认限制。确认是否存在单次查询数量限制、连接数限制或备份窗口。
7.3 两个排查实例
实例一:Excel 打开 CSV 中文乱码
现象是脚本生成的 CSV 用记事本打开正常,用 Excel 打开乱码。原因是文件没有 BOM,Excel 默认按本地 ANSI 解析。解决方法是把写出编码改为utf-8-sig。如果文件已经生成,可以用文本编辑器另存为带 BOM 的 UTF-8,或转换成gb18030。预防手段是在脚本写出后自动检查文件编码。
实例二:定时任务偶尔导出行数不全
现象是每天凌晨导出的材料数据大部分时间正常,偶尔少几十条。排查时先看日志,发现失败批次的记录数和成功批次有明显差异。进一步检查发现,调度时间和服务端备份窗口重叠,读取时部分记录处于非稳定状态。另一种常见原因是增量导出的时间边界没有固定,导致因时区或调度延迟遗漏记录。处理方法是把调度时间避开备份窗口,并在每次导出前记录本次导出的时间范围,用于下次增量判断。
8. 生产环境最佳实践与扩展方向
8.1 生产环境落地清单
| 清单项 | 建议 |
|---|---|
| 账号权限 | 使用只读账号,不开放写权限 |
| 凭据管理 | 密码从环境变量或密钥服务读取,不落入代码库 |
| 日志 | 每次导出记录时间、记录数、文件路径、异常信息 |
| 校验 | 导出后自动核对记录数和关键字段 |
| 告警 | 失败时通过邮件或企业消息通知责任人 |
| 调度 | 避开服务端备份窗口,设置超时和重试 |
| 文件清理 | 定期清理历史导出文件,避免磁盘写满 |
| 版本管理 | 导出脚本进入 Git,配置与代码分离 |
| 回滚方案 | 保留上一次导出结果,新版本脚本异常时可快速回退 |
8.2 通用导出任务的共性经验
Granta MI 脚本导出和 MySQL、Oracle、DBeaver、IDEA Database 中的数据导出有很多共性。无论从哪种系统导出数据,都要关注连接字符集、唯一标识、NULL 值处理和行数校验。比如 DBeaver 导出表数据时漏掉主键,会导致回写和比对困难;Oracle 导出中文乱码通常也是连接字符集和客户端编码不一致造成的。把这些经验沉淀成统一的导出规范,比每次遇到问题再临时排查更有效。
8.3 后续扩展方向
如果导出脚本已经在生产环境稳定运行,下一步可以考虑:
- 增量导出。利用
Last Modified Date或Record History GUID只导出修改过的记录,减少数据量和执行时间。 - 配置中心化。从 XML 配置迁移到更完整的配置中心,支持在线修改和版本审计。
- 结果元数据化。导出时同时生成一份 JSON 元数据,描述导出时间、来源库、查询条件、字段映射,方便下游自动解析。
- 与数据看板集成。把导出的材料数据接入 BI 工具或数据中台,替代人工定期更新报表。
把导出脚本升级成数据订阅服务后,通常会遇到权限、增量计算和调度可靠性三个问题。这也是 Granta MI 数据工程化过程中最值得继续投入的方向。