☰
ArcGIS Python地理处理脚本:从语法到自定义工具箱
2026/10/29 9:22:11 网站建设 项目流程

简介:《[初学入门]ArcGIS中Python脚本的使用》是一份面向GIS初学者和ArcGIS入门用户的docx文档,聚焦如何用Python脚本自动化地理处理任务,缓解手工操作效率低、流程难复用的问题。压缩包仅含1个docx文件,大小约490KB,轻量便于查阅;正文从数学运算符、字符串、模块导入、def函数、if/while/for流程控制和输入输出讲起,再延伸到arcpy地理处理对象、工具帮助与列表参数、工具箱别名、ModelBuilder脚本嵌入、PythonWin调试,以及Describe/Exists和地图代数等内容,并对关键语法配以简短示例。文档按“语言基础—ArcGIS集成—调试与数据信息获取”组织,目录层级清晰,适合边查边练,也便于把零散语法对应到缓冲区分析等具体任务,适合需要从零起步并逐步实践ArcGIS Python的读者。已有1492人学习,可作为课堂辅助或自学清单,帮助读者建立脚本排错、参数组织和流程复用的基本思路。

1. ArcGIS 里那把最容易被闲置的脚本扳手

ArcGIS 桌面里重复三遍以上的操作,就该考虑交给 Python 脚本。手上这份材料是一份翻译加学习笔记性质的入门教程,从 Python 语法一路写到地理处理对象、工具箱别名、ModelBuilder 里挂脚本,代码在 9.x 桌面上逐条跑过并贴了运行结果。它要解决的问题很具体:ArcToolbox 里点十几次鼠标才能完成的裁剪、缓冲、重投影、字段统计,怎么用几十行代码固化下来,再做成一个带参数面板的自定义工具。适合两类人——语法书翻两页就困、但确实要动手写脚本的初学者,以及天天在目录树里翻 shp、想把重复劳动交出去的从业者。下面的拆解按「先能读懂 → 再能跑通 → 最后不翻车」推下去。

2. 语法只挑脚本里真用得上的:运算符、字符串、def 与流程控制

这一章不铺语法全景,只挑写地理处理脚本时高频出现的那几块。判断标准很简单:在后面的裁剪、缓冲、字段统计里会不会用到。用不上的一律跳过。

2.1 运算符与数值类型:取模为什么在方位角里天天出现

Python 2 的整数除法会截断小数,5/2得 2 而不是 2.5,这个特性在按像元数算面积、按整数网格算行列号时很容易埋雷。规则只有一条:参与运算的有一方是浮点,结果才是浮点。取模%在这里不是数学练习,而是把角度锁进 0~359 的标准手法。

# 以下均为 Python 2 语法,ArcMap 自带的解释器只认这个版本 import math az = 270 newaz = (az + 180) % 360 # 方位角反向 180 度,取模把结果锁回 0~359 print newaz # 90 print 5 / 2 # 2 全是整型,小数被截掉 print 5.0 / 2 # 2.5 一方是浮点,结果才是浮点 print 2 ** 0.5 # 1.4142 没有开方运算符,用 0.5 次幂代替 print math.sqrt(2) # 1.4142 等价写法,前提是 import math print math.log10(100) # 2.0 print math.e # 2.7182818284590451

代码逻辑:前四行处理整型与浮点的混算,%用于角度归一化,**用于开方。参数上没什么可调的,唯一要记住的是math里的三角函数吃弧度不吃角度,从投影坐标算方位角时,出来的是弧度,得手动乘180/math.pi转回去。下面这段算两点距离,两种写法结果一致,hypot更省事也更不容易溢出:

x1, y1 = 520382, 4152373 x2, y2 = 520475, 4152963 dx, dy = x2 - x1, y2 - y1 print math.hypot(dx, dy) # 597.2846892395618 print (dx * dx + dy * dy) ** 0.5 # 同一个结果

dx、dy是投影坐标系下的米,所以结果单位也是米。这组数字来自某实验室一份 DEM 附属点表,坐标看着像 UTM,实际检查过Describe的spatialReference才敢用——这一点后面第三章还会提。

2.2 字符串与路径:把目录里的 shp 捞出来靠这几招

路径拼接和扩展名判断是脚本里出现频率最高的字符串操作,比任何算法都常见。切片规则是含头不含尾,s[2:4]取的是下标 2 和 3。

s = 'zhulj' print s[0] # z 下标从 0 开始 print s[-1] # j 倒数第一个,等价 s[len(s)-1] print s[2:4] # ul 前闭后开 print s.upper() # ZHULJ print s * 3 # zhuljzhuljzhulj p = 'd:/work/lu.shp' print p.find('.') # 10 扩展名点号的位置,用来切扩展名 print p.split('/') # ['d:', 'work', 'lu.shp'] print p.split('/')[-1] # lu.shp p2 = r'd:\work\soil.shp' # r 前缀让反斜杠不再当转义符 print p2 print 'streams.shp'.endswith('.shp') # True

逻辑说明:find返回首次出现的位置,用它可以从后往前截取扩展名;split按分隔符拆成列表,取[-1]就是文件名;r''是为 Windows 路径准备的后悔药,不带r时\t、\n、\s会被当转义序列,d:\test\soil.shp里那个\t会直接变成制表符,路径瞬间失效。这是新手最常见的一种“路径明明对却打不开”。

2.3 def 加 if:把太阳高度角算成可复用函数

def定义的是可以反复调用的代码块,参数写在括号里,返回用return。下面这个例子来自材料的核心片段:给一个纬度和一个太阳倾角,算出正午太阳高度角和方位角,后面做山影(Hillshade)时这两个值正好是输入参数。

import math def radians(angdeg): return angdeg * math.pi / 180 def degrees(angrad): return angrad * 180 / math.pi def sun_angle(lat, decl): """lat 为纬度(南半球取负),decl 为太阳倾角;返回 (太阳高度角, 方位角)""" sunangle = 90 - lat + decl azimuth = 180 if sunangle > 90: # 越过天顶,需要反射回来 sunangle = 180 - sunangle azimuth = 0 return sunangle, azimuth print sun_angle(30, 20) # (80, 180) print math.sin(radians(45)) # 0.707106781187 print degrees(math.acos(0.5)) # 60.0

参数说明:lat是研究区中心纬度,decl是节气对应的太阳倾角(夏至约 23.44,春秋分 0,冬至 -23.44)。if sunangle > 90这个分支不是装饰,纬度低、倾角大的时候太阳高度角会超过 90 度,不折回来喂给 Hillshade 工具,出来的阴影方向是反的。返回元组而不是两个函数调用,是为了保证两个值来自同一次判断。

2.4 for 与 while:遍历目录、筛要素类

for走序列,while走条件。写脚本时前者用于遍历目录和要素列表,后者多用于游标推进,这个区别后面第四章会再碰到。

import os ws = r'C:\prog\hmbarea' ilist = os.listdir(ws) # 工作目录下所有文件名 fcs = [] # 空列表,存以 .shp 结尾的 for i in ilist: if i.endswith('.shp'): fcs.append(i) for fc in fcs: print fc

逻辑说明:os.listdir只返回名字不带路径,所以后面调工具时要自己拼全路径。endswith区分大小写,.SHP会被漏掉,稳妥写法是先i.lower().endswith('.shp')。这段唯一的“参数”就是工作目录ws,把它换掉就能复用到别的目录。

2.5 参数从哪来:sys.argv 与脚本工具的对应关系

脚本写死参数只能自己用,把参数从命令行或工具面板递进来才能给别人用。最原始的办法是sys.argv。

import sys lat = float(sys.argv[1]) # 第 0 个是脚本自身路径,参数从 1 开始 decl = float(sys.argv[2]) print '正午太阳角=' + str(sun_angle(lat, decl)[0])

参数说明:在 PythonWin 里运行时,弹窗的 Arguments 栏按空格分隔填40 23.44,对应argv[1]和argv[2]。一旦把脚本挂成 ArcToolbox 里的脚本工具,sys.argv就按工具参数面板的顺序自动填充,第 0 位依然是脚本路径。这里必须用float()显式转换,因为argv里全是字符串,直接参与算术会报类型错误。这套对应关系是最后一章做工具参数表的基础,顺序错一位,参数就串味。

3. 建地理处理对象:从 arcgisscripting 到 arcpy,先把 workspace 固定

这一章是整份材料的分水岭。前面是通用 Python,后面每一行都得跟 ArcGIS 打交道,而打交道的第一步永远是创建那个“地理处理对象”。对象建不对,后面所有方法都无从谈起。

3.1 三代写法与它们的适用版本

材料覆盖了 9.x 到 10.x 两个时代,写法差异不小,照抄别人的代码跑不通,八成是这一层没对上。

写法典型版本创建方式现状
arcgisscripting9.x 桌面arcgisscripting.create(9.3)依赖随桌面安装的 Python 2.5/2.6
COM 调度跨版本过渡期Dispatch 到固定的地理处理 ProgID能绕开版本绑定,但性能与报错信息都差
arcpy10.x 之后直接import arcpy,模块级函数现在的主流写法,无 create()
# 9.x 写法:对象要自己 create,版本号跟桌面版本走 import arcgisscripting gp = arcgisscripting.create(9.3) gp.workspace = r'C:\Tongass' gp.overwriteoutput = 1 gp.clip_analysis('standb4', 'clipcov', 'standb4_clip', 'POLY', '1.25')
# 10.x 之后:不再有 create(),环境和工具都挂在模块上 import arcpy arcpy.env.workspace = r'C:\Tongass' arcpy.env.overwriteOutput = True arcpy.Clip_analysis('standb4', 'clipcov', 'standb4_clip')

逻辑说明:9.x 里gp是个对象,属性和方法都挂在它身上;10.x 里arcpy是个模块,env承接原来的环境属性,工具变成模块级函数。overwriteoutput在 9.x 里是数字 1,在 10.x 里是布尔True,写反了某些版本不报错但行为不对。写新脚本直接用 arcpy,读老脚本时心里有这张表就够了。

3.2 List 系列:动手前先查清工作空间里有什么

ListFeatureClasses、ListFields、ListRasters、ListDatasets这几个是脚本的“侦察兵”。不查就硬跑,最常见的结果是工具报输入不存在,或者只处理了一半数据还浑然不觉。

import arcpy arcpy.env.workspace = r'C:\prog\hmbarea' # 通配符 w* 只匹配 w 开头,第二个参数限定要素类型为面 fc_list = arcpy.ListFeatureClasses('w*', 'Polygon') for fc in fc_list: print fc # 第二个参数 '*' 表示字段名全匹配,第三个 'All' 表示所有字段类型 field_list = arcpy.ListFields('landuse', '*', 'All') for f in field_list: print f.name, f.type, f.length

参数说明:第一个参数的通配符遵循*任意多字符、?单字符;第二个参数不写则返回全部类型,写了Polygon、Polyline、Point就只返回对应几何类型;ListFields的第三个参数可以填All、Required、Selected等,做字段批处理时用Required能跳过系统字段。这里有个容易混淆的点:遍历 coverage 要用ListDatasets而不是ListFeatureClasses,因为 coverage 在工作空间层面是数据集,里面的弧、多边形、节点才是要素类。

3.3 Describe 与 Exists:别靠扩展名猜数据

扩展名经常骗人。.shp之外的.dwg、.mdb、栅格数据集,光看名字判断不了几何类型和坐标系,Describe才是可靠的。

import arcpy path = r'C:\prog\hmbarea\landuse' d = arcpy.Describe(path) print d.dataType # RasterDataset / ShapeFile / FeatureClass print d.shapeType # Polygon / Polyline / Point / Raster print d.spatialReference.name # 投影名,未定义时是 Unknown if arcpy.Exists(path): print '存在,可以继续' else: print '不存在,别硬跑'

逻辑说明:dataType告诉你这是什么东西,shapeType告诉你几何类型,spatialReference.name告诉你坐标系。三者合起来基本能判断“这个输入能不能直接喂给裁剪工具”。Exists只判断存在性,不判断有效性——被锁定或损坏的数据也会返回真,真正的坑在后面排查章说。

3.4 在循环里用 Describe:批量体检坐标系

单条数据看一眼就够,批量处理时要把判断写进循环,跑之前先把不合格的筛掉,比跑到一半崩掉体面得多。

import arcpy arcpy.env.workspace = r'C:\prog\hmbarea' for fc in arcpy.ListFeatureClasses(): if not arcpy.Exists(fc): continue d = arcpy.Describe(fc) sr = d.spatialReference if sr.name == 'Unknown': print '%s 没有投影,跳过' % fc continue print '%s | %s | %s' % (fc, d.shapeType, sr.name)

逻辑说明:continue提前跳出本轮,避免后面拿空坐标系做运算。这里的判断条件是sr.name == 'Unknown',比if not sr.name更明确,也方便改成白名单——只允许WGS_1984_UTM_Zone_*之类通过时,把判断反过来写即可。批量跑之前先跑一遍这段,能省掉大量无效等待。

4. 别名、流水线与游标:把三步操作压成一条命令

单个工具调用没什么难度,难的是把它们串起来还能维护。材料里最有实操价值的一段,就是把覆盖转换、缓冲、裁剪串成流水线,并且用别名把同名工具的歧义消掉。

4.1 别名表:clip 为什么有两个

ArcToolbox 里同名工具不少,裁剪在 Coverage 工具集下有一个,在 Data Management 的要素工具集下还有一个,适用数据类型不同。脚本里没有“右键选择”这种操作,只能靠别名区分。工具别名的查看方式是右键工具看属性,把常用的记住就行。

别名对应工具箱典型工具
analysisAnalysis ToolsClip、Buffer、Intersect
managementData Management ToolsCopyFeatures、Project、AddField
conversionConversion ToolsFeatureClassToShapefile
arcCoverage ToolsCoverage 专用裁剪、叠加
saSpatial Analyst地图代数、栅格计算
3d3D Analyst山影、坡度、视域
cartography、stats、ga、lr制图、统计、地统计、线性参考按需

调用格式是工具名_别名,不带别名时会到默认工具箱里找,找到的不是你想要的那一个就产生静默错误——不报错,结果不对,最难查。

4.2 串一条能跑的流水线:转换 → 200 米缓冲 → 裁剪

下面这段把散落在三个工具箱里的操作串成一条,输入是一份 coverage 的弧段和一份地质多边形。

import arcpy arcpy.env.workspace = r'C:\prog\hmbarea' arcpy.env.overwriteOutput = True # 1. coverage 的弧段转成 shp,注意路径里带要素集,用 /arc 指定 arcpy.CopyFeatures_management('streams/arc', 'streams.shp') # 2. 沿水系做 200 米缓冲,距离必须带单位 arcpy.Buffer_analysis('streams.shp', 'stbuff200.shp', '200 Meters', 'FULL', 'ROUND', 'ALL') # 3. 用缓冲面裁剪地质图,只保留水系两侧 200 米内的地质单元 arcpy.Clip_analysis('geol.shp', 'stbuff200.shp', 'geolstr200.shp') print arcpy.GetMessages()

参数说明:Buffer_analysis的第三个参数必须带单位,写成裸数字200会按输入的坐标系单位解释,地理坐标系下就变成 200 度,结果荒谬且不报错;第四个参数FULL是端头类型(圆头/平头),第五个ROUND是拐角样式,第六个ALL表示所有缓冲要素融合成一个。Clip_analysis的第三、四个参数是 XY 容差,一般省略用默认值。最后一行GetMessages()是必须养的检查习惯,工具的执行信息、警告、错误都在里面,不打印就只能看到一个孤零零的 True。

4.3 gp.Toolbox:老写法能看懂,别照抄

9.x 时代有个省字的写法:把工具箱设成默认,之后调工具就不用带别名。这个写法在 10.x 之后失效了,老脚本里见到要能认出来,但新脚本别再写。

# 9.x 写法,仅用于读懂历史脚本;10.x 之后 gp.Toolbox 不再生效 import arcgisscripting gp = arcgisscripting.create(9.3) gp.Toolbox = 'Analysis' gp.Buffer('streams.shp', 'stbuff200.shp', 200) gp.Clip('geol.shp', 'stbuff200.shp', 'geolstr200.shp')

逻辑说明:gp.Toolbox = 'Analysis'只影响之后调用的裸工具名,本质是给别名补了个默认值。它带来的问题是可读性——半年后回来看gp.Clip根本不知道调的是 Coverage 版还是 Analysis 版。血泪经验是:宁可多打几个字符,也别省这个别名。

4.4 地图代数:栅格计算在脚本里怎么写

矢量的裁剪缓冲是“搬运几何”,栅格的运算则是“算每个像元”。材料里这一节用的是 Spatial Analyst 的地图代数,脚本里的写法和栅格计算器里的表达式不完全一样。

import arcpy from arcpy.sa import * arcpy.CheckOutExtension('Spatial') # 扩展模块必须先签出 arcpy.env.workspace = r'C:\prog\hmbarea' out = Con('landuse == 5', 1, 0) # 条件判断:等于 5 给 1,否则给 0 out.save('built_up_mask')
# 9.x 的老写法,表达式是一整条字符串,字段用方括号包 gp.SingleOutputMapAlgebra_sa("out = con([landuse] == 5, 1, 0)")

参数说明:Con的第一个参数是条件栅格,第二、三个是条件成立与不成立时的取值,可以是常量也可以是另一个栅格。9.x 的字符串写法里,栅格名要用[]包起来,等于号==和=的区别在这里非常致命——赋值和判断写反不会报错,只会算出一个恒定值。签出扩展模块这一步别省,没签出时from arcpy.sa import *能过,一调就报许可错误。

4.5 游标:读属性、改字段、写新表

前面的工具都是“整份数据进,整份数据出”,游标是唯一能逐行处理的手段。老写法用gp.UpdateCursor配while,新写法用arcpy.da配with。

import arcpy arcpy.env.workspace = r'C:\prog\hmbarea' # 用 with 打开游标,退出时自动释放,不会残留锁 with arcpy.da.UpdateCursor('geolstr200.shp', ['Shape_Area', 'Area_km2']) as cur: for row in cur: row[1] = row[0] / 1000000.0 cur.updateRow(row)
# 9.x 老写法:游标必须手动释放,否则文件被锁 rows = gp.UpdateCursor('geolstr200.shp') row = rows.Next() while row: row.Area_km2 = row.Shape_Area / 1000000.0 rows.UpdateRow(row) row = rows.Next() del row, rows

参数说明:UpdateCursor的第二个参数是字段列表,顺序决定row[0]、row[1]对应哪个字段,写错顺序会把面积塞进编号字段且不报错。Shape_Area的单位取决于坐标系,投影坐标下是平方米,地理坐标下是平方度,除以一百万之前一定先确认坐标系。del row, rows那两行在老写法里是必须的,漏了之后输出文件删不掉、下次覆盖失败,排查起来非常费劲。

5. 避坑与排查:五条把脚本跑挂的真实现场

这一章按“现象 → 原因 → 解决”记录,都是照着材料里的代码敲一遍就会撞上或者迟早撞上的。

5.1 现象:脚本报语法错误,或者工具报输入不存在,但路径肉眼看着没问题

原因:两个来源叠在一起。一是中文注释让老版本解释器在编码上出错,材料里专门提示过注释不要用中文;二是 Windows 路径里的反斜杠被当转义符吃掉了,C:\temp\new.shp里的\t、\n会变成制表符和换行。

解决:脚本头部加编码声明# -*- coding: utf-8 -*-,或者注释干脆全英文;路径统一用r'...'原始字符串或正斜杠c:/work/a.shp,拼接用os.path.join,别手动拼反斜杠。上线前把数据挪到全英文路径下跑一次,能排除掉一大半玄学问题。

5.2 现象:工具名写对了却报“找不到工具”,或者跑完结果明显不对

原因:同名工具分属不同工具箱,裸工具名会走到默认那个去。裁剪、叠加、投影这几个尤其容易撞。

解决:全部改成工具名_别名的完整写法,Clip_analysis、Project_management这种。查别名的正规途径是右键工具看属性,别靠猜。

5.3 现象:昨天还能跑的脚本,今天 import 就失败,甚至工具在 ArcToolbox 里直接挂不上

原因:动了随桌面版一起装的那个 Python。材料里明确警告过不要升级它,因为arcgisscripting是与特定解释器版本编译绑定的,换成别的版本就 import 不进来。

解决:保持桌面自带解释器原样,要写新代码就单独装一套环境跑 arcpy,两套互不干扰。已经升级坏了的,重装桌面环境的 Python 组件比到处找兼容包省时间。

5.4 现象:工具返回成功,但打开输出还是上次的旧结果

原因:输出已存在且没开覆盖,某些版本不报错,静默返回旧文件。另一种是上一次运行崩溃留下了同名中间文件。

解决:脚本开头统一arcpy.env.overwriteOutput = True,或者在处理前显式arcpy.Delete_management(输出路径)。中间文件用arcpy.env.scratchWorkspace指到临时目录,别堆在工作空间里。跑完养成打印GetMessages()的习惯,静默成功最需要警惕。

5.5 现象:输出文件删不掉、下次覆盖失败、目录里多出一堆.lock文件

原因:游标没释放。老式gp.UpdateCursor配while的写法,循环结束不del就还攥着文件句柄;arcpy.da的写法忘了用with也一样。

解决:一律用with arcpy.da.UpdateCursor(...) as cur:的形式,让上下文管理器负责释放;老写法必须补del row, rows。判断有没有残留锁,看输出目录里有没有.lock文件,有就说明上一个进程没退干净。

6. 挂成工具箱里的工具:参数表填对,验证走三遍

脚本在自己机器上跑通只是及格线,真正的交付是把它挂进 ArcToolbox,让不写代码的同事也能填参数、点确定。这一步翻车最多的地方是参数顺序。

脚本里的sys.argv[1]、[2]、[3]与脚本工具属性里“参数”页签的行顺序一一对应,第一行就是argv[1],第 0 位永远是脚本自身。所以写脚本时最好先在开头把参数按顺序接完,再改成工具,别中途插参数。

序号参数名数据类型方向说明
1输入要素Feature Class输入参与缓冲或裁剪的要素
2输出要素Feature Class输出写成绝对路径或工作空间内相对名
3缓冲距离Linear Unit输入必须带单位,如200 Meters
4是否覆盖Boolean输入对应overwriteOutput

参数接进来之后先做一层兜底,空值在工具面板里传进来是空字符串,直接float()会抛ValueError:

import arcpy import sys in_fc = sys.argv[1] out_fc = sys.argv[2] dist = sys.argv[3] if len(sys.argv) > 3 and sys.argv[3] else '200 Meters' if not arcpy.Exists(in_fc): arcpy.AddError('输入不存在:' + in_fc) sys.exit(1) # 非零退出码,工具面板会标红 arcpy.Buffer_analysis(in_fc, out_fc, dist) arcpy.AddMessage(arcpy.GetMessages())

AddError和AddMessage是给工具面板看的,跟print不是一回事——print输出到标准输出,挂成工具后用户看不到,必须用AddMessage才会出现在结果窗口里。这个细节我吃过亏,脚本明明打印了错误原因,同事那边只看到一个红叉。

验证我一般走三遍:PythonWin 里打断点单步过一遍,确认变量值;在工具面板里用最小数据集跑一遍,确认参数顺序没错位;最后拿一份没投影的数据故意跑一遍,确认错误提示是人话而不是异常堆栈。第三遍最有价值,因为用户永远会拿不合格的数据来试。

ModelBuilder 里嵌脚本反而简单,把脚本工具拖进模型,前面接一个迭代器就能批量跑,唯一要注意的是模型里的中间数据默认写到内存工作空间,脚本读不到,得在模型属性里把中间数据落盘到指定目录。从前我总觉得脚本跑通就算完事,直到有人拿着参数面板截图问我为什么第二个框填不进去——从那以后每次挂工具,参数表、空值兜底、错误提示这三样必须挨个走一遍才敢交出去。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询