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