一覧に戻る

シェープファイルをGeoJSON形式に変換する

#Python#GIS#geojson#shapefile

##前提 zip圧縮されたシェープファイル群(.shp, .shx, .dbf)を、GeoJson形式で出力する関数です。 当然、シェープファイル群のファイル名が共通している必要があります。 また、.geojsonファイルを出力するのではなく、メモリ上で処理します。 事前にpyshp(shapefile)が必要になります。

##コード

import shapefile, io, zipfile

#zipファイルからshpファイルを探してファイル名を取得
def find_shpfile_inzip(zipped_shp):
	zip_infolist = zipped_shp.infolist()
	for info in zip_infolist:
		if not info.filename.startswith('__MACOSX/'): #Mac-ZIP対応
			if info.filename.endswith('.shp'):
				return info.filename

まずこのように、zip圧縮されたshapefileのファイル名を取得する関数を定義します。 この関数を用いて

#ZIP保存されたSHP群をGEOJSON形式で返す
def zipped_shp_to_geojson(zipped_shp):
	zipped_files = zipfile.ZipFile(zipped_shp)

	#zipファイルからshpファイルを探してファイル名を取得
	shp_name = find_shpfile_inzip(zipped_files)[:-4]

	#shapefile読み込みと適合判定
	try:
		shp_file_bytes = zipped_files.read(shp_name + '.shp')
		shx_file_bytes = zipped_files.read(shp_name + '.shx')
		dbf_file_bytes = zipped_files.read(shp_name + '.dbf')
	except:
		print("Imported file was not apropriate Shape-Zip-File.")
		return None

	geojson = dict(type="FeatureCollection", features=[])
	#pyshpはライブラリ内部でデコードするので、正しいエンコーディングでデコード出来るまでループ
	for codec in CODECS:
		try:
			reader = shapefile.Reader(shp=io.BytesIO(shp_file_bytes),
					                    shx=io.BytesIO(shx_file_bytes),
					                    dbf=io.BytesIO(dbf_file_bytes),encoding=codec)

			fields = reader.fields[1:]
			field_names = [field[0] for field in fields]
			for sr in reader.shapeRecords():
				atr = dict(zip(field_names, sr.record))
				geom = sr.shape.__geo_interface__
				geojson['features'].append(dict(type="Feature", \
				 geometry=geom, properties=atr))
			print(codec + 'encoding is correct.' )
			break
		except UnicodeDecodeError:
			print(codec + 'is not suitable for this file.')
			continue
	return geojson

これでgeojsonに変換されます。 エンコーディングについてはコメントのとおりです。pyshpではデフォルトだとUTF-8でデコードされますが、オープンデータで提供されるシェープファイルは、大半がcp932(Windows環境のShift-JIS)です。エンコーディングの指定が間違っているとUnicode errorが発生します。それならcp932を指定してデコードすれば良いのでは、と考えますが、当然ながらUTF-8等にも対応しておきたいところです。したがって、メジャーなエンコーディングのなかから適合するまでデコードし続けるようになっています(このモジュールの冒頭で、CODECS定数を定義してある)。