Python+GIS — shapefile批量導入PostgreSQL (PostGIS)

背景

Postgresql+PostGIS 是存儲、處理、分析空間數據的經常使用解決方案。相信多數GISer和我同樣,安裝好PostGIS的第一件事就是研究如何將Esri Shapefile導入數據庫。常見方法是經過PostGIS提供的數據導入工具,或者經過shp2psql命令行工具進行導入。
最近在研究Python空間數據處理時,想要經過Python腳本將shp文件批量入庫,查到了以下兩篇文章:html

嘗試運行了一下代碼,發現存在導入報錯、中文亂碼、沒法導入MultiPolygon等問題。
因而基於兩者的代碼進行了改造,解決了這些問題。python

步驟

1. 安裝依賴包

須要的python包主要有:sqlalchemy, geoalchemy2, geopandas, psycopg2,這些包有的依賴其它包,安裝起來比較麻煩,建議你們使用anaconda進行安裝。sql

2. 準備工做

首先建立一個測試數據庫gis_test
而後加載PostGIS擴展:數據庫

CREATE EXTENSION postgis;

固然,你也可使用python鏈接PostgreSQL進行數據庫的建立和PostGIS擴展的加載,這裏再也不贅述。app

3. 代碼

本文代碼刪掉了上述參考文章中「解析shp的geometry code,獲取geometry類型」的部分,直接將空間數據指定爲GEOMETRY 類型。工具

"""
shp2pgsql.py
import Shapefile to PostgreSQL.
author: mango
version: 0.1.0
Compatible with Python versions 3.x
"""
import geopandas as gpd
from sqlalchemy import create_engine
from geoalchemy2 import Geometry, WKTElement
import os

def shp2pgsql(file, engine):
    """單個shp文件入庫"""
    file_name = os.path.split(file)[1]
    print('正在寫入:'+file)
    tbl_name = file_name.split('.')[0]  # 表名
    map_data = gpd.GeoDataFrame.from_file(file)
    spatial_ref = map_data.crs.srs.split(':')[-1]  # 讀取shp的空間參考
    map_data['geometry'] = map_data['geometry'].apply(
        lambda x: WKTElement(x.wkt, spatial_ref))
    # geopandas 的to_sql()方法繼承自pandas, 將GeoDataFrame中的數據寫入數據庫
    map_data.to_sql(
        name=tbl_name,
        con=engine,
        if_exists='replace', # 若是表存在,則替換原有表
        chunksize=1000,  # 設置一次入庫大小,防止數據量太大卡頓
        # 指定geometry的類型,這裏直接指定geometry_type='GEOMETRY',防止MultiPolygon沒法寫入
        dtype={'geometry': Geometry(
            geometry_type='GEOMETRY', srid=spatial_ref)},
        method='multi'
    )
    return None


def shp2pgsql_batch(dir_name, username, password, host, port, dbname):
    """建立批量任務"""
    os.chdir(dir_name)  # 改變當前工做目錄到指定路徑
    engine = create_engine(username, password, host, port, dbname)
    file_list = os.listdir(dir_name)
    for file in file_list:
        if file.split('.')[-1] == 'shp':
            file = os.path.abspath(file)
            shp2pgsql(file, engine)
    return None


# 執行任務計劃
if __name__ == '__main__':
    file_path = r'D:\Data\mango'
    username = 'postgres'
    password = '123ewq'
    host = '127.0.0.1'
    port = '5432'
    dbname = 'gis_test'
    shp2pgsql_batch(file_path, username, password, host, port, dbname)

用改進後的代碼測試了多種點、線、面數據,均能成功寫入,且無中文亂碼問題。大功告成!post

相關文章
相關標籤/搜索