置Python環(huán)境配置:安裝pip與gdal實現(xiàn)arcpy協(xié)同)
做GIS批處理的人十有八九都撞上過這個尷尬場景桌面端 ArcGIS 10.2.2 裝好后自帶 Python 2.7.5 就躺在C:\Python27\ArcGIS10.2里平時寫個 arcpy 腳本處理要素類沒問題可真想用 pip 裝個第三方庫或者讓 gdal 去讀大影像就會發(fā)現(xiàn)這個環(huán)境連 pip 都沒有各種報錯能把你卡在原地。這篇教程解決的就是這個痛點核心三件事給內(nèi)置 Python 2.7.5 裝上 pip、把 gdal 順利裝進這個老環(huán)境、再讓 arcpy 和 gdal 在同一個腳本里配合不打架。適合正在和 ArcGIS 批處理、影像裁剪拼接、數(shù)據(jù)格式轉(zhuǎn)換死磕的測繪、土地、規(guī)劃、自然資源相關從業(yè)者你用得上。1. 為什么死磕內(nèi)置環(huán)境而不是另裝一套 Python1.1 arcpy 和內(nèi)置 Python 是綁定的很多人第一個念頭是ArcGIS 自帶的 Python 太老我自己裝個新的 Python 不就行了如果完全不碰 arcpy 只做 gdal 處理這個思路沒錯但只要你還想在同一個腳本里調(diào)用 arcpy 的要素管理、幾何修復、拓撲檢查等能力你就繞不開內(nèi)置解釋器。原因在于 arcpy 并不是一個純粹的第三方 Python 庫。它由 ESRI 開發(fā)安裝 ArcGIS Desktop 時會將模塊文件寫入到安裝目錄的Lib\site-packages下同時還要讀取本機的許可服務。你另裝一個 Python 環(huán)境import arcpy 大概率會直接拋ModuleNotFoundError或者ImportError: DLL load failed就算你把 arcpy 整個文件夾復制到新環(huán)境也會因為底層 C 擴展對應的編譯器版本、Python ABI 不一致而崩潰。我早年試過把 arcpy 硬塞進 Anaconda 里折騰兩天最后還是老老實實回退到了內(nèi)置環(huán)境。1.2 自帶環(huán)境里其實藏著不少東西打開命令行輸入C:\Python27\ArcGIS10.2\python.exe你會發(fā)現(xiàn)這個環(huán)境并不算“裸”。它自帶 numpy所以做柵格數(shù)組運算沒問題自帶 sqlite3、json、logging 等標準庫日常腳本都夠用還帶一個pythonw.exe可以無黑窗運行 GUI 小程序。最關鍵的是因為 ArcGIS 10.2.2 時代桌面端還是 32 位應用所以內(nèi)置 Python 是 32 位的這反而讓很多老包、老動態(tài)庫變得非常好裝。1.3 什么時候可以另選環(huán)境只有兩種場景我會建議你放棄內(nèi)置環(huán)境一是你已經(jīng)完全不用 ArcGIS 桌面端只做 gdal 柵格處理二是你用 ArcGIS Pro它自帶新一代 Python 3 環(huán)境那是另一套玩法。否則一臺機器上同時存在兩套 Pythonpip 命令亂指、import 模塊沖突的問題會比想象中的更麻煩。2. 先給內(nèi)置 Python 裝上 pip老版本有老版本的門道2.1 先確認到底有沒有 pip不用猜直接驗證C:\Python27\ArcGIS10.2\python.exe -m pip --version如果提示No module named pip那就說明這個內(nèi)置環(huán)境沒有裝 pip。注意這時候不要試python -m ensurepipPython 2.7.5 時代的內(nèi)置環(huán)境還沒有集成 ensurepip 機制執(zhí)行后大概率會提示ensurepip is not available。直接走 get-pip.py 這條老路。2.2 下載支持 Python 2.7 的老版本 get-pip.py現(xiàn)在直接從 pypa 官網(wǎng)下載的 get-pip.py 已經(jīng)不支持 Python 2運行時會直接提示 Python 2.7 已停止維護然后退出。正確做法是訪問https://bootstrap.pypa.io/pip/2.7/get-pip.py這是一個專門給 Python 2.7 保留的最后版本對應 pip 20.3.4。把頁面內(nèi)容用瀏覽器“另存為”保存到本地文件名get-pip.py然后執(zhí)行C:\Python27\ArcGIS10.2\python.exe get-pip.py安裝完成后pip 和 setuptools 會一起寫入C:\Python27\ArcGIS10.2\Lib\site-packages腳本入口則出現(xiàn)在C:\Python27\ArcGIS10.2\Scripts目錄下。2.3 為什么非要寫python -m pip而不是直接敲 pip這是新手最容易踩的坑。Windows 的命令行里直接敲 pip系統(tǒng)會按照 PATH 環(huán)境變量去找 pip.exe。如果這臺機器后來裝過別的 Python、ArcGIS Pro 自帶的 Python、或者是某個軟件捆綁的 PythonPATH 里靠前的那個解釋器會優(yōu)先搶到 pip 命令結(jié)果就是“你明明給內(nèi)置環(huán)境裝了 pip輸入 pip 卻報……”pip 無法將“pip”項識別為 cmdlet、函數(shù)、腳本文件或可運行程序的名稱。或者pip fatal error in launcher: unable to create process using ...原因基本都是 pip.exe 啟動時找到了錯誤的 Python 路徑。規(guī)避方法很簡單所有 pip 操作都顯式指定解釋器寫成C:\Python27\ArcGIS10.2\python.exe -m pip install 包名這樣無論 PATH 怎么亂pip 都會被綁定到你指定的內(nèi)置環(huán)境上。提示如果python.exe -m pip這個命令本身可以運行說明環(huán)境沒壞只是直接敲 pip 時的指向有問題。不要急著卸載重裝優(yōu)先用“python -m”寫法。2.4 順手把 pip 源換掉老環(huán)境的下載速度能提升幾倍Python 2.7 的老環(huán)境使用 pip 時的另一個痛點是網(wǎng)絡。默認官方源在國內(nèi)訪問速度不穩(wěn)定大一點的包動不動就超時。推薦把它改成國內(nèi)的鏡像源這里以清華鏡像為例。永久生效的配置位置在用戶目錄下C:\Users\你的用戶名\pip\pip.ini如果pip文件夾不存在手動新建一個。pip.ini內(nèi)容如下[global] timeout 60 index-url https://pypi.tuna.tsinghua.edu.cn/simple trusted-host pypi.tuna.tsinghua.edu.cn保存后再用python -m pip install就會自動走鏡像源下載速度差距非常明顯。臨時指定源也可以比如C:\Python27\ArcGIS10.2\python.exe -m pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple3. gdal 裝進 Python 2.7.5 的正確姿勢3.1 為什么直接pip install gdal會讓人崩潰按一般思路裝 gdal 自然是pip install gdal但很快你就會看到一長串編譯日志最后跳出一句error: Microsoft Visual C 9.0 is required. Get it from ...或者Unable to find vcvarsall.bat問題出在 gdal 這個包在 Python 索引里的 source 發(fā)行版包含 C 擴展源碼pip 在 Windows 上找不到合適的編譯器就會失敗。Python 2.7 時代官方推薦的編譯器是 Visual C 2008VC9新電腦上幾乎沒人專門裝它。所以不要硬編譯直接找預編譯的 wheel 包。3.2 選對 wheel 包的三個硬條件ArcGIS 10.2.2 自帶 Python 是 32 位的即使你的操作系統(tǒng)是 64 位也沒關系安裝包必須對應 Python 版本和系統(tǒng)位數(shù)。三個條件缺一不可Python 版本標識必須是cp27平臺標識必須是win32選擇支持 Python 2 的最后幾個穩(wěn)定版本比如 GDAL 2.2.4 或 2.4.4一個可行的文件名大概是GDAL-2.4.4-cp27-cp27m-win32.whl文件下載后在命令行執(zhí)行C:\Python27\ArcGIS10.2\python.exe -m pip install GDAL-2.4.4-cp27-cp27m-win32.whl看到Successfully installed GDAL-2.4.4就說明裝上了。注意有些 whl 文件名很接近但cp27m和cp27mu是不同的 ABI 標識Windows 上一般選cp27m。選錯會直接報is not a supported wheel on this platform換一個版本就能解決。3.3 安裝后驗證除了版本號還要查 DLL安裝完成后在命令行進入 Python 交互模式C:\Python27\ArcGIS10.2\python.exe然后執(zhí)行from osgeo import gdal, ogr, osr print(gdal.VersionInfo())如果正常打印出版本號說明核心安裝成功。如果報ImportError: DLL load failed: 找不到指定的模塊那多半是 gdal 的動態(tài)庫沒有被系統(tǒng)找到。gdal 的許多 DLL 被安裝到了C:\Python27\ArcGIS10.2\Lib\site-packages\osgeo目錄下而這個目錄沒有被加入 PATH。解決辦法是在腳本開頭先把路徑塞進環(huán)境變量import os os.environ[PATH] rC:\Python27\ArcGIS10.2\Lib\site-packages\osgeo ; os.environ[PATH] from osgeo import gdal, ogr, osr這一招幾乎能解決所有“gdal 裝上但 import 報錯”的問題。3.4 順便再裝幾個常用庫內(nèi)置環(huán)境里 numpy 已經(jīng)有了但數(shù)據(jù)分析時你可能還想用 pandas、psycopg2、openpyxl 這些。安裝方式一樣C:\Python27\ArcGIS10.2\python.exe -m pip install pandas注意 pandas 的較新版本在 Python 2.7 上不穩(wěn)定建議用pandas0.24.2這類最后支持 Python 2 的版本。裝之前可以先python -m pip list看看當前環(huán)境里已有哪些包避免重復安裝造成版本混亂。4. 讓 arcpy 和 gdal 在一段腳本里默契配合4.1 二者共存其實不沖突很多同學擔心一個腳本里同時import arcpy和from osgeo import gdal會起包名沖突。至少我在這個內(nèi)置環(huán)境下測過二者可以共存。arcpy 走的是 ESRI 的模塊體系gdal 走的是獨立的 osgeo 入口命名空間上井水不犯河水。真正的難點在于兩個庫操作同一份數(shù)據(jù)時如何處理文件鎖、坐標系統(tǒng)和編碼。4.2 一個綜合示例修復幾何、讀取柵格、輸出新柵格我寫一個貼近實際工作的腳本把 arcpy 的矢量和 gdal 的柵格能力串起來。場景是先修一份面要素的幾何錯誤再用 gdal 讀一下 DEM 影像最后輸出一個放大了兩倍像元值的 GeoTIFF。# -*- coding: utf-8 -*- import arcpy from osgeo import gdal, osr # 開啟覆蓋輸出避免二次運行報錯 arcpy.env.overwriteOutput True arcpy.env.workspace uD:\\gis_data\\shp in_fc ulanduse.shp out_fc ulanduse_repair.shp # 1. arcpy 修復幾何錯誤 arcpy.RepairGeometry_management(in_fc, out_fc) print u修復完成: {0}.format(out_fc) # 2. gdal 讀取 DEM src_path uD:\\gis_data\\dem.tif src_ds gdal.Open(src_path) if src_ds is None: raise IOError(u無法打開影像檢查路徑是否存在{0}.format(src_path)) band src_ds.GetRasterBand(1) data band.ReadAsArray() print u影像尺寸: {0} x {1}.format(src_ds.RasterXSize, src_ds.RasterYSize) # 3. 檢查坐標系是否一致 sr_arcpy arcpy.Describe(out_fc).spatialReference sr_gdal osr.SpatialReference() sr_gdal.ImportFromWkt(src_ds.GetProjection()) if sr_arcpy.factoryCode ! sr_gdal.GetAuthorityCode(None): print u警告: 矢量與柵格坐標系不一致請確認后再繼續(xù) # 4. 寫出新柵格 driver gdal.GetDriverByName(GTiff) out_ds driver.Create(uD:\\gis_data\\dem_double.tif, src_ds.RasterXSize, src_ds.RasterYSize, 1, gdal.GDT_Float32) out_ds.SetProjection(src_ds.GetProjection()) out_ds.SetGeoTransform(src_ds.GetGeoTransform()) out_band out_ds.GetRasterBand(1) out_band.WriteArray(data * 2) out_ds.FlushCache() # 5. 釋放文件句柄 out_ds None src_ds None del data print u全部處理完成這個腳本基本概括了日常配合使用的幾個關鍵點arcpy 處理完矢量gdal 讀取柵格然后比較坐標系、寫新柵格。最后那句out_ds None和src_ds None特別關鍵不做這步的話被占用的影像文件可能一直沒法被其他程序刪除或覆蓋。4.3 坐標系統(tǒng)互轉(zhuǎn)的兩個常用方法arcpy 和 gdal 對坐標系統(tǒng)的表示方式不同。arcpy 里要素類的 spatialReference 可以通過factoryCode拿到 WKIDgdal 的空間參考則是osr.SpatialReference對象可以從 WKT 導入?;ハ噢D(zhuǎn)換的常用寫法# gdal 轉(zhuǎn) arcpy sr_gdal osr.SpatialReference() sr_gdal.ImportFromEPSG(4326) arcpy_sr arcpy.SpatialReference(sr_gdal.GetAuthorityCode(None)) # arcpy 轉(zhuǎn) gdal arcpy_sr arcpy.Describe(in_fc).spatialReference sr_gdal osr.SpatialReference() sr_gdal.ImportFromWkt(arcpy_sr.exportToString())核心思路是 gdal 用 WKTarcpy 用 WKT兩邊都通過 WKT 對接就不會出現(xiàn)坐標系上下顛倒或者單位不一致的問題。4.4 中文路徑和 Python 2 編碼問題Python 2.7 的字符串默認是字節(jié)串不是 Unicode。路徑里一旦出現(xiàn)中文arcpy和gdal都有可能拋UnicodeDecodeError。我的經(jīng)驗是腳本開頭固定寫# -*- coding: utf-8 -*-所有文件路徑都寫成u...形式盡量不在路徑里混用加號字符串拼接。如果你在print中文時控制臺亂碼可以把代碼保存為 UTF-8 編碼后重新設置控制臺代碼頁或者在 ArcGIS 的 Python 窗口里運行就不會有這個問題。5. 高頻報錯速查表與幾個保險操作5.1 常見問題對照表下面這張表是我實際排障過程中整理出來的高頻問題按“看到什么報錯就查什么”的方式使用。報錯信息原因解決辦法No module named pip內(nèi)置環(huán)境沒有安裝 pip走 get-pip.py 老版本安裝流程pip 無法將“pip”項識別為 cmdlet系統(tǒng) PATH 里沒有 pip或指向其他 Python 的 pip使用python -m pip或把 Scripts 目錄加入 PATHis not a supported wheel on this platformwheel 包平臺、Python 版本不符核對 cp27、win32 標識Unable to find vcvarsall.bat源碼編譯時缺少 VC9 編譯器放棄編譯換用預編譯 wheelImportError: DLL load failedgdal 的 DLL 路徑不在 PATH腳本開頭動態(tài)添加 osgeo 目錄到 PATHERROR 4: Unable to open影像路徑不存在或文件名含中文檢查路徑改用英文目錄名或 u 前綴UnicodeDecodeErrorPython 2 默認編碼問題用 Unicode 字符串表示路徑腳本頭加編碼聲明5.2 環(huán)境備份寧可多備份不可賭運氣內(nèi)置環(huán)境一旦搞亂重裝 ArcGIS 成本太高。我的做法是在所有配置完成、gdal 和常用庫都驗證無問題后把整個C:\Python27\ArcGIS10.2目錄復制一份到移動硬盤或 D 盤做備份。這個目錄本質(zhì)上是綠色可用的出問題時把備份復制回來再把系統(tǒng)環(huán)境變量指過去就行。如果想更精確一點先輸出依賴清單C:\Python27\ArcGIS10.2\python.exe -m pip freeze requirements.txt以后要恢復時C:\Python27\ArcGIS10.2\python.exe -m pip install -r requirements.txt不過要注意Python 2.7 的pip freeze會把 numpy 這類包也列進去恢復安裝時使用鏡像源才不會太痛苦。5.3 把內(nèi)置 Python 配置到 PyCharm命令行和 IDE 都能用命令行用的時間長了重度腳本開發(fā)我還是建議配一個 IDE不然代碼長一點就難維護。以 PyCharm 為例新建項目后在File - Settings - Project - Python Interpreter里點擊齒輪選擇 Add然后指向C:\Python27\ArcGIS10.2\python.exe配置完成后PyCharm 的代碼補全、調(diào)試器都能正常工作但你仍然可以繼續(xù)用命令行里的python -m pip安裝包兩邊共用同一個 site-packages不會出現(xiàn) IDE 里能運行、命令行里卻報錯的情況。5.4 一個容易被忽略的小細節(jié)Scripts 目錄的 PATH如果你希望直接在命令行敲pip而不是每次打一長串python -m pip可以在系統(tǒng)環(huán)境變量 PATH 里追加這兩個目錄C:\Python27\ArcGIS10.2 C:\Python27\ArcGIS10.2\Scripts但前提是這臺機器上沒有其他 Python 搶占pip命令。如果還有其他 Python我建議還是用python -m pip雖然多打幾個字符但永遠不會錯。再分享點個人經(jīng)驗。我在實際項目中踩過最深的坑不是裝不上而是裝好后過兩個月回到這個環(huán)境發(fā)現(xiàn) pip 命令指向了別的解釋器gdal 導入也開始亂套。所以后來我給自己定了一條紀律凡是碰 ArcGIS 內(nèi)置環(huán)境操作前后都要先敲一遍python -m pip --version確認解釋器路徑再敲一遍python -c from osgeo import gdal; print(gdal.VersionInfo())確認 gdal 可用兩行驗證跑通再繼續(xù)。這個習慣雖然簡單但真的能省下大量排障時間。最后再補一個小技巧如果把整個環(huán)境備份文件連同 requirements.txt 一起放到項目目錄里哪天換電腦重構環(huán)境照著清單一次還原十分鐘就能恢復全部戰(zhàn)斗力。