
1. 分幅索引表为什么总在“最后一公里”翻车做林业、国土、测绘类项目的朋友对分幅索引表应该不陌生一张图斑图层按图幅号归组把每个图幅覆盖到的县、乡、村、小班号拼成一行输出成 Excel 给外业或评审用。ArcGis 自带的接图表在稀疏图斑上看着还行一旦图斑又小又密图面就糊成一团所以大家更愿意用 ArcPy 批量生成表格版索引。真正让人头疼的不是arcpy.da.SearchCursor怎么遍历而是脚本跑完之后那一步字段到底对不对。我见过太多情况——图幅号列写进去了但小班号拼接顺序乱了县乡村去重后顺序被打乱中文在 ArcGis 的 Python 2.7 里直接变乱码.xls和.xlsx后缀写错xlwt和openpyxl互相打架。这些问题单靠肉眼翻 Excel 很难发现尤其是几百个图幅的时候。这篇就围绕“ArcGis Python 制作分幅索引表”这个场景把脚本骨架、编码坑、字段校验串起来讲。同时给一套 TaoToken 统一 Key 的接入配置把“生成索引表 → 调模型做字段语义校验 → 输出问题清单”这条链路跑通。适合已经在用 ArcPy 写脚本、但想让输出结果更可控的人。2. TaoToken 统一 Key 在索引表校验链路里的位置先说清楚它在这里干什么避免误解。TaoToken 不是替代 ArcGis也不是替代xlwt它解决的是“脚本产出结果之后怎么自动判断字段内容是否合理”这一段。比如你的索引表里“村”字段出现了空值、“小班号”拼接里混进了非数字字符、图幅号格式不统一这些规则用纯 Python 写正则也能做但字段语义层面的判断比如某个村名是否属于该乡镇交给模型更省事。TaoToken 提供的是统一 Key 接入方式一个 Key 可以走模型对话、Coding Plan、API 调用等入口配置集中放在settings.json里脚本读取配置即可不用把 Key 硬编码进 ArcPy 脚本。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 入口是 https://taotoken.net/api 注意 API 地址不带 UTM 参数。几个会用到的 deep link按场景分想先手动验证模型对字段的判断效果模型对话 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite长期写 ArcPy 脚本、想让模型辅助改代码Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite管理 Key、看额度控制台 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite创建和复制 KeyAPI Keys https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite接入参数、请求格式接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite如果你用 Claude Code 这类工具写脚本ClaudeCodeAnthropic https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaudecodeutm_campaignrewrite注意Key 只放在本地settings.json不要提交到 Git也不要在 ArcGis 工具箱里明文写死。3. settings.json 可复制配置骨架下面这份配置可以直接抄改api_key就行。字段名保持和接入文档一致脚本里用json.load读出来即可。{ taotoken: { api_key: sk-你的Key, base_url: https://taotoken.net/api, model: claude-sonnet-4-5, timeout: 60, max_retries: 2 }, arcgis_index: { in_feature: F:\\project\\data.gdb\\xiao_ban, save_path: F:\\project\\out\\分幅索引表.xls, sheet_name: 分幅索引表, sheet_title: 凯里市退化乔木林分幅索引表, header_line: [县, 乡, 村, 图幅号, 小班号], fields: [县, 乡, 村, PageNumber, 小班号] } }几个参数说明用表格对照更清楚参数作用常见取值api_keyTaoToken 统一 Key控制台复制base_urlAPI 根地址https://taotoken.net/apimodel校验用的模型按接入文档可选in_feature输入要素类.gdb 内要素save_path输出表路径.xls 配 xlwt.xlsx 配 openpyxlheader_line表头中文与 fields 一一对应fields要素类字段名注意大小写读取配置的代码很短# -*- coding:utf-8 -*- import json import os def load_cfg(cfg_path): with open(cfg_path, r) as f: return json.load(f) CFG load_cfg(os.path.join(os.path.dirname(__file__), settings.json)) TK CFG[taotoken] IDX CFG[arcgis_index]提示ArcGis Desktop 用的是 Python 2.7json模块自带但字符串前建议加u避免中文路径出问题。4. ArcPy 生成索引表 字段校验完整脚本这一节是主体。先跑通索引表生成再接校验。生成部分沿用SearchCursordict.get的思路校验部分调 TaoToken API。4.1 生成索引表核心逻辑# -*- coding:utf-8 -*- import arcpy import os import xlwt import sys reload(sys) sys.setdefaultencoding(utf-8) def make_map_set(in_feature, save_path, sheet_name, sheet_title, header_line, fields): wb xlwt.Workbook(encodingutf-8) ws wb.add_sheet(sheet_name, cell_overwrite_okTrue) ws.write_merge(0, 0, 0, len(header_line) - 1, sheet_title) for col in range(len(header_line)): ws.write(1, col, header_line[col]) xians, xiangs, cuns, xiao_bans {}, {}, {}, {} with arcpy.da.SearchCursor(in_feature, fields) as cursor: for row in cursor: key row[3] xians[key] xians.get(key, []) [row[0]] xiangs[key] xiangs.get(key, []) [row[1]] cuns[key] cuns.get(key, []) [row[2]] xiao_bans[key] xiao_bans.get(key, []) [str(int(row[4]))] for key in xians.keys(): xian sorted(list(set(xians[key])), keyxians[key].index) xiang sorted(list(set(xiangs[key])), keyxiangs[key].index) cun sorted(list(set(cuns[key])), keycuns[key].index) ws.write(key 1, 0, u、.join(xian)) ws.write(key 1, 1, u、.join(xiang)) ws.write(key 1, 2, u、.join(cun)) ws.write(key 1, 3, key) ws.write(key 1, 4, u、.join(xiao_bans[key])) wb.save(save_path)这里sorted(..., key原列表.index)是为了去重后保持原有顺序set()本身会打乱顺序不加这层会出问题。4.2 调 TaoToken 做字段校验生成完之后把每行数据拼成 JSON发给模型做规则语义校验。用urllib2Python 2.7 自带即可不额外装依赖。# -*- coding:utf-8 -*- import json import urllib2 def check_rows(rows, tk): url tk[base_url].rstrip(/) /v1/messages prompt u下面是分幅索引表的行数据请检查1) 图幅号是否为空或格式异常2) 小班号是否含非数字字符3) 县乡村是否存在空值。只输出问题行号和原因JSON 数组格式。\n json.dumps(rows, ensure_asciiFalse) body { model: tk[model], max_tokens: 1024, messages: [{role: user, content: prompt}] } req urllib2.Request( url, datajson.dumps(body), headers{ Content-Type: application/json, Authorization: Bearer tk[api_key] } ) resp urllib2.urlopen(req, timeouttk[timeout]) return json.loads(resp.read())把生成和校验串起来if __name__ __main__: make_map_set(IDX[in_feature], IDX[save_path], IDX[sheet_name], IDX[sheet_title], IDX[header_line], IDX[fields]) # 读取刚生成的表做校验示例直接构造行数据 rows [{row: 2, 县: u凯里市, 乡: u湾水镇, 村: u翁凼村, 图幅号: u1, 小班号: u1、3、4}] result check_rows(rows, TK) print(json.dumps(result, ensure_asciiFalse, indent2))4.3 校验动作要落到字段上模型返回的问题清单建议再写一层本地断言把“模型说有问题”转成“脚本抛异常”这样批量跑的时候不会漏。def assert_rows(rows): for r in rows: assert r.get(u图幅号), u图幅号为空: %s % r assert r.get(u小班号) and all( p.strip().isdigit() for p in r[u小班号].split(u、) ), u小班号含非数字: %s % r for f in [u县, u乡, u村]: assert r.get(f), u%s 为空: %s % (f, r)5. 验证请求与成功结果长什么样先单独验证 TaoToken 这条链路通不通再跑全量。最小请求curl -X POST https://taotoken.net/api/v1/messages \ -H Content-Type: application/json \ -H Authorization: Bearer sk-你的Key \ -d {model:claude-sonnet-4-5,max_tokens:256,messages:[{role:user,content:返回JSON: {\ok\:true}}]}成功时你会拿到类似结构{ id: msg_xxx, content: [{type: text, text: {\ok\:true}}], usage: {input_tokens: 12, output_tokens: 8} }索引表这边跑完脚本后打开.xls正常结果应该是标题行合并居中第二行是表头从第三行开始每个图幅一行县乡村用顿号拼接且顺序与原始数据一致小班号是纯数字拼接。如果某个图幅的“村”列出现重复村名说明set()去重那步没配sorted如果中文变问号是编码声明没加。6. 本篇常见错排查报错一UnicodeDecodeError: ascii codec cant decodeArcGis Desktop 的 Python 2.7 默认 ascii。解决文件头加# -*- coding:utf-8 -*-中文字符串前加u并在入口处reload(sys); sys.setdefaultencoding(utf-8)。报错二IOError: [Errno 2] No such file or directory但路径明明存在Windows 路径反斜杠在 Python 字符串里是转义符。用rF:\project\out.xls或双反斜杠F:\\project\\out.xls。报错三xlwt.Exception: Attempt to overwrite celladd_sheet时没加cell_overwrite_okTrue或者同一单元格写了两次。检查write_merge和后续write是否重叠。报错四.xlsx用 xlwt 保存后打不开xlwt只支持.xlsopenpyxl只支持.xlsx。后缀和库必须匹配别混用。报错五TaoToken 返回 401Key 没带Bearer前缀或者 Key 复制时带了空格。去 API Keys 页面重新复制https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite报错六模型返回内容不是纯 JSON提示词里明确“只输出 JSON 数组”并在解析前做一次text.strip().strip() 清洗避免被 markdown 代码块包裹。报错七小班号拼接出现1.0这种浮点字段类型是 Double 时str(row[4])会带小数点先int()再str()即str(int(row[4]))。7. 把校验接进你的日常脚本如果你只是偶尔做一次索引表手动核对也能过。但如果是按月出图、按项目批量跑建议把上面这套配置固化下来settings.json放项目根目录ArcPy 脚本读配置生成完自动调一次校验问题行直接打印到 ArcGis 的消息窗口。Key 走 TaoToken 统一管理换模型或换额度只改配置不动脚本。长期写这类脚本的话Coding Plan 那条入口会更顺手模型能直接读你的 ArcPy 代码上下文https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 。接入参数和请求格式以接入文档为准https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。想先手动试模型对字段的判断用模型对话入口https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite 。