从gadm下载世界各国的行政边界
从gadm下载世界各国的行政边界
ytkzGADM: 全球行政区划数据库
GADM主页:https://gadm.org/
GADM,全称Database of Global Administrative Areas,是一个高精度的全球行政区划数据库。其包含了全球所有国家和地区的国界、省界、市界、区界等多个级别的行政区划边界数据。
警告
GADM提供的中国国界数据不符合中国的领土主张,省界、市界、区界等数据也不一定是最新的版本。在正式刊物中发表使用此类数据的图件时需格外谨慎。
数据下载
GADM提供了两种下载方式:
- 下载全球所有国家和地区的所有数据 https://gadm.org/download_world.html
- 按国家下载 https://gadm.org/download_country.html
由于全球数据量巨大,建议根据需要按照国家下载数据。
需要说明的是,GADM 中对country 的定义为“any entity with an ISO country code”。因而如果想要下载完整的中国数据,实际上需要下载China、Hong Kong、Macao和Taiwan 四个数据。
由于GADM提供的中国国界数据不符合我国领土主张,本文以美国数据为例介绍数据下载及使用。
数据格式及转换
对于每个数据,GADM提供了5种不同的格式:
- Geopackage:可以被GDAL/OGR、ArcGIS、QGIS等软件读取
- Shapefile:可直接用于ArcGIS等软件
- KMZ:可直接在Google Earth中打开
- R (sp):可直接用于R语言绘图
- R (sf):可直接用于R语言绘图
如果在安装GMT时,GMT已经正确链接了GDAL库,则Shapefile格式的数据可以直接用于绘图。实际绘图时,可能只想要一小部分数据(比如某个省/州的界线),这种情况下,则需要将数据转换成纯文本文件,以方便从数据中提取出需要的部分。
python 爬虫,下载各国的行政边界
目标地址是 https://gadm.org/download_country.html
按F12,分析网站接口。
找到了changeCountry()这个函数
function changeCountry() {
var x = document.getElementById("countrySelect").value
if (x == "") {
document.getElementById("gpkg").innerHTML ="";
document.getElementById("shp").innerHTML ="";
// document.getElementById("json").innerHTML = "";
document.getElementById("kmz").innerHTML = "";
document.getElementById("crs").innerHTML = "";
document.getElementById("img").src = "";
} else {
var version = 4.1
var vers = 41
var a = x.split("_");
var base = "https://geodata.ucdavis.edu/gadm/gadm4.1/";
document.getElementById("gpkg").innerHTML ="<a href=" + base + "gpkg/gadm" + vers + "_" + a[0] + ".gpkg>Geopackage</a>";
document.getElementById("shp").innerHTML ="<a href=" + base + "shp/gadm" + vers + "_" + a[0] + "_shp.zip>Shapefile</a>";
var n = parseInt(a[2]);
var kmztxt = "KMZ: <a href=" + base + "kmz/gadm" + vers + "_" + a[0] + "_0.kmz>level-0</a>";
var jsontxt = "GeoJSON: <a href=" + base + "json/gadm" + vers + "_" + a[0] + "_0.json>level-0</a>";
for (i = 1; i < n; i++) {
jsontxt += ", <a href=" + base + "json/gadm" + vers + "_" + a[0] + "_" + i.toString() + ".json.zip>level" + i.toString() +"</a>";
}
for (i = 1; i < n; i++) {
kmztxt += ", <a href=" + base + "kmz/gadm" + vers + "_" + a[0] + "_" + i.toString() + ".kmz>level" + i.toString() +"</a>";
}
document.getElementById("json").innerHTML = jsontxt;
document.getElementById("kmz").innerHTML = kmztxt;
document.getElementById("img").src = "https://geodata.ucdavis.edu/gadm/gadm" + version + "/png/" + a[0] + "_adm.png";
document.getElementById("crs").innerHTML = 'The coordinate reference system is <a href="https://en.wikipedia.org/wiki/Geographic_coordinate_system">longitude/latitude</a> and the <a href="https://en.wikipedia.org/wiki/World_Geodetic_System">WGS84</a> datum.<br>Description of <a href="/formats.html">file formats</a>.';
}
}
从这个函数中,得到以下信息:
1 x是countrySelect的value值
2 countrySelect是Country单选框中的国家名字
3 a[0]是x中的下横线前的国家缩写字母
4 目标文件的下载地址是
"https://geodata.ucdavis.edu/gadm/gadm4.1/kmz/gadm/41_" + a[0] + "_shp.zip
开始编码
明确目标:自动的下载各国的行政边界shape文件。
编程语言:python
需要科学上网
完整代码如下:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2023/11/14 19:26
# @File : download_gadm.py
import requests
import os, re
proxies = {'http': 'socks5h://127.0.0.1:7890',
'https': 'socks5h://127.0.0.1:7890'
}
class download_gadm():
def __init__(self):
self.url = 'https://gadm.org/download_country.html'
self.proxies = proxies
self.headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36'
}
def request_save(self,outpath):
if os.path.exists(outpath):
pass
else:
# create a new folder
os.makedirs(outpath)
html = requests.get(url=self.url, headers=self.headers, proxies=self.proxies).text
country_lists = re.findall(r'<option value="(.*)">', html)
for countrys in country_lists:
try:
if '_' in countrys:
try:
country_abbreviation = countrys.split('_')[0]
country_name = countrys.split('_')[1]
url = self.target_url(country_abbreviation)
print(url)
context = requests.get(url=url, headers = self.headers, proxies=self.proxies)
with open(outpath + f'/{country_name}.zip', 'wb') as f:
f.write(context.content)
print('completed download %s'%country_name)
except Exception as e:
print(e)
else:
print('空值')
except:
try:
country_abbreviation = countrys.split('_')[0]
country_name = countrys.split('_')[1]
url = self.target_url(country_abbreviation)
print(url)
context = requests.get(url=url, headers=self.headers)
with open(outpath + f'/{country_name}.zip', 'wb') as f:
f.write(context.content)
print('completed download %s' % country_name)
except Exception as e:
print(e)
def target_url(self, country):
r'https://geodata.ucdavis.edu/gadm/gadm4.1/shp/gadm41_AUS_shp.zip'
url = r'https://geodata.ucdavis.edu/gadm/gadm4.1/shp/gadm41_%s_shp.zip'%country
return url
if __name__ == '__main__':
outpath = r'D:\gadm'
download_gadm().request_save(outpath)
方便使用
为了方便使用,用pyside6写一个前端,结合以上代码打包为exe文件。
代码如下:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2023/12/13 22:15
# @File : world_map_gui.py
import os
import re
import sys
import requests
from PySide6.QtCore import Signal, QThread
from PySide6.QtGui import QIcon
from PySide6.QtWidgets import QApplication, QGridLayout, QPushButton, QTextEdit, QDialog, QLineEdit
proxies = {'http': 'socks5h://127.0.0.1:7890',
'https': 'socks5h://127.0.0.1:7890'
}
class MapDownload(QThread):
_signal = Signal()
text_signal = Signal(str)
def __init__(self, savepath, *args, **kwargs):
QThread.__init__(self, *args, **kwargs)
self.savepath = savepath
self.url = 'https://gadm.org/download_country.html'
self.proxies = proxies
self.headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36'
}
def target_url(self, country):
r'https://geodata.ucdavis.edu/gadm/gadm4.1/shp/gadm41_AUS_shp.zip'
url = r'https://geodata.ucdavis.edu/gadm/gadm4.1/shp/gadm41_%s_shp.zip' % country
return url
def run(self):
if os.path.exists(self.savepath):
pass
else:
# create a new folder
os.makedirs(self.savepath)
html = requests.get(url=self.url, headers=self.headers, proxies=self.proxies).text
country_lists = re.findall(r'<option value="(.*)">', html)
for countrys in country_lists:
try:
if '_' in countrys:
try:
country_abbreviation = countrys.split('_')[0]
country_name = countrys.split('_')[1]
url = self.target_url(country_abbreviation)
context = requests.get(url=url, headers=self.headers, proxies=self.proxies)
with open(self.savepath + f'/{country_name}.zip', 'wb') as f:
f.write(context.content)
self.text_signal.emit('已下载 %s' % country_name)
print('completed download %s' % country_name)
except Exception as e:
print(e)
else:
print('空值')
except:
try:
country_abbreviation = countrys.split('_')[0]
country_name = countrys.split('_')[1]
url = self.target_url(country_abbreviation)
print(url)
context = requests.get(url=url, headers=self.headers)
with open(self.savepath + f'/{country_name}.zip', 'wb') as f:
f.write(context.content)
self.text_signal.emit('completed download %s' % country_name)
print('completed download %s' % country_name)
except Exception as e:
print(e)
self._signal.emit()
class Ui_MainWindow(QDialog):
def __init__(self):
super(Ui_MainWindow, self).__init__()
self.setupUi(self)
# TypeError: native Qt signal instance 'clicked' is not callable
self.pushButton.clicked.connect(self.download_map)
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(400, 300)
MainWindow.setMinimumSize(400, 300)
self.gridLayout = QGridLayout()
self.gridLayout.setObjectName("gridLayout")
self.setLayout(self.gridLayout)
# 图标
self.setWindowTitle('世界各国矢量下载')
self.setWindowIcon(QIcon(':/pic/icon1.png'))
self.pushButton = QPushButton()
self.pushButton.setText('运行')
self.pushButton.setObjectName("pushButton")
self.savepathtext = QLineEdit()
self.savepathtext.setPlaceholderText('输入保存路径')
self.messageTE = QTextEdit()
self.messageTE.setObjectName("text")
self.gridLayout.addWidget(self.savepathtext, 0, 1, 1, 1)
self.gridLayout.addWidget(self.pushButton, 0, 2, 1, 1)
self.gridLayout.addWidget(self.messageTE, 1, 1, 1, 1)
def download_map(self):
save_path = str(self.savepathtext.text())
if save_path != "":
# 按钮不可选
self.pushButton.setDisabled(True)
self.savepathtext.setDisabled(True)
self.thread = MapDownload(save_path)
self.thread._signal.connect(self.completed)
self.thread.start()
self.thread.text_signal.connect(self.messageTE.append)
def completed(self):
self.messageTE.append('下载完成')
self.savepathtext.setDisabled(False)
self.pushButton.setEnabled(True)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Ui_MainWindow()
window.show()
app.exec()
最后
在公众号回复“gdam”获取下载后的数据。该数据不包括咱们中国的矢量,这个教程也只是作为分享。