1.現有數據和目標成果
1.1現有數據
源數據保存在數據庫中,使用的數據庫管理軟件是PostgreSQL。
本質上來說,數據存儲在數據庫中是以記錄存儲在表(table)上實現的,在shapefile中也是以記錄的形式存在屬性表(dbf)。所以數據庫中表的列(字段)可以與dbf表的列一一對應。數據庫中數據形式大致如下:
1.2目標成果
衆所周知,shapefile是ESRI公司制定的GIS數據的一種格式,一個正常的shapefile至少包括三部分:shp、dbf和shx。有關於shp文件等一系列說明,可以參考我之前的博客——shp系列,鏈接是
https://blog.csdn.net/Fan_z_0802/article/details/85078059
shp文件用ArcMap打開後如下(包括圖形和屬性表):
2.代碼過程
2.1連接數據庫獲取數據
要獲取數據庫數據必須要先連接數據庫,連接PostgreSQL的方法網上很多參考,也可以參考我源代碼的方式。
執行SQL(結構化查詢語言),獲取數據庫要導出數據的表的字段數,以及要導出的記錄。
一個簡單的示例如下:
'''連接數據獲取數據,WHU_Fan,0706'''
def getData():
'''databese是要連接數據庫的名字,user是訪問用戶(創建數據庫時設置),password是創建數據庫的密碼,host填localhost,端口爲安裝數據庫時設置的端口'''
'''這裏是PostgreSQL的連接方法,MySQL也類似,端口可能不一樣'''
conn = psycopg2.connect(database='test2',user='postgres',password='admin',host='localhost',port='5432')
cur = conn.cursor()
''''設置自己的sql語句'''
'''例如'''
tableName = 'outcome'
commandFindColumn = "select COLUMN_NAME from information_schema.COLUMNS where table_name='%s' "% (tableName)
'''執行SQL語句獲取數據'''
cur.execute(commandFindColumn)
columnRows = cur.fetchall()
'''SQL語句:導出outcome表的全部'''
commandFindRecord = "select * from %s order by 相似度 desc"%(tableName)
'''執行SQL語句獲取數據'''
cur.execute(commandFindRecord)
recordRows = cur.fetchall()
'''提交確認'''
conn.commit()
'''關閉連接'''
cur.close()
conn.close()
'''返回數據'''
return columnRows,recordRows
2.2解析數據
獲取的字段變量columnRows,是一個list,順序的包含數據庫對應表的每一個字段。
獲取的記錄信息recordRows,也是一個list,包含所有滿足條件的記錄。
2.3寫到shp中
1.調用函數連接數據庫獲取數據
2.創建shp文件
3.創建字段
4.寫入圖形和屬性信息
5.關閉保存文件
代碼如下:
'''outcome表導出到shp,WHU_Fan,0706'''
def writeToShp(filePath):
'''調用連接數據庫函數'''
columnRows,recordRows = getData()
'''創建shp文件w'''
w = shapefile.Writer(filePath)
'''創建字段,此處可以固定字段,或者靈活字段,根據需求改變'''
'''本處字段暫時寫固定已知的,可以改寫成靈活的'''
'''F 代表數值型,C 字符型'''
w.field('任務id','F')
w.field('來源', 'C')
w.field('poi名', 'C')
w.field('類型', 'C')
w.field('緯度', 'C')
w.field('精度', 'C')
w.field('地址', 'C')
w.field('地理位置', 'C')
w.field('抓取時間', 'C')
'''添加圖形和屬性信息'''
for recordRow in recordRows:
'''將字符型經緯度轉化爲數值型'''
x = float(recordRow[5])
y = float(recordRow[4])
'''創建點狀要素,座標爲經緯度'''
'''創建其他類型要素類似,輸入合理的座標點即可,詳細參考之前博客的shp文件說明'''
w.point(x,y)
'''創建對應的dbf屬性信息,與圖形一一對應'''
w.record(recordRow[0],recordRow[1],recordRow[2],recordRow[3],recordRow[4],recordRow[5],recordRow[6],recordRow[7],recordRow[8],encoding='UTF-8')
w.close()
3.源代碼
#encoding:utf-8
'''written by WHU_fan,0705'''
import shapefile
import psycopg2
from datetime import datetime
'''連接數據庫獲取數據'''
def getData():
conn = psycopg2.connect(database='test2',user='postgres',password='admin',host='localhost',port='5432')
cur = conn.cursor()
tableName = 'outcome'
commandFindColumn = "select COLUMN_NAME from information_schema.COLUMNS where table_name='%s' "%(tableName)
cur.execute(commandFindColumn)
columnRows = cur.fetchall()
'''導出outcome的成果'''
commandFindRecord = "select * from %s where poi名2!='' order by 相似度"%(tableName)
cur.execute(commandFindRecord)
recordRows = cur.fetchall()
conn.commit()
cur.close()
conn.close()
return columnRows,recordRows
'''outcome表導出到shp'''
def writeToShp(filePath):
columnRows,recordRows = getData()
w = shapefile.Writer(filePath)
'''添加字段'''
w.field('任務id','F')
w.field('來源', 'C')
w.field('poi名', 'C')
w.field('類型', 'C')
w.field('緯度', 'C')
w.field('精度', 'C')
w.field('地址', 'C')
w.field('地理位置', 'C')
w.field('抓取時間', 'C')
for recordRow in recordRows:
x = float(recordRow[5])
y = float(recordRow[4])
w.point(x,y)
w.record(recordRow[0],recordRow[1],recordRow[2],recordRow[3],recordRow[4],recordRow[5],recordRow[6],recordRow[7],recordRow[8],encoding='UTF-8')
w.close()
if __name__ == '__main__':
'''獲取當前日期,得到一個datetime對象如:(2019, 7, 2, 23, 12, 23, 424000)'''
'''#將獲取到的datetime對象僅取日期如:2019-7-2'''
today = datetime.today()
today_date = datetime.date(today)
writeToShp('shapefile/point_' + str(today_date))
print('succeed')
4.屬性表亂碼問題
問題:導出的shp用ArcGIS打開,屬性表發生亂碼。
解決:
1.python文件編碼設爲UTF-8 #encoding:utf-8
2.寫屬性表時編碼設爲UTF-8 encoding='UTF-8'
3.cmd運行命令(關鍵):
reg add HKEY_CURRENT_USER\Software\ESRI\Desktop10.2\Common\CodePage /v dbfDefault /t REG_SZ /d UTF-8 /f
5.成果總結
1.導出shp的過程比較簡單,主要是使用開源庫,不需要從底層寫起。
2.創建字段時需要根據字段的屬性設置對應編碼(“C”,“F”,還是其他)
3.使用ArcGIS查看效果,調試代碼。