社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

获得中国长城的shp的python爬虫代码

GISAI • 2 月前 • 169 次点击  
"""
 OpenStreetMap Overpass API 获取中国长城数据,转换为 Shapefile
"""
import requests
import geopandas as gpd
from shapely.geometry import LineString
import os

OUTPUT_DIR = r"C:\Users\yl\Desktop\GIS"

def fetch_great_wall():
# Overpass API endpoints
urls = [
"https://overpass-api.de/api/interpreter",
"https://lz4.overpass-api.de/api/interpreter",
"https://overpass.kumi.systems/api/interpreter",
    ]

长城在 OSM 中的标签
bbox "36,105,45,125"

# Overpass QL 查询
overpass_query f"""
    [out:json][timeout:300];
    (
      way["name"~"长城"]({bbox});
      way["man_made"="wall"]({bbox});
      way["barrier"="wall"]["historic"="yes"]({bbox});
      relation["name"~"长城"]({bbox});
    );
    out body;
    >;
    out skel qt;
    """

print("正在查询 Overpass API...")
    print(f"查询范围{bbox}")

data None
    for url in urls:
try:
            print(f"尝试{url}")
response = requests.post(
url
data=overpass_query.encode('utf-8'),
timeout=300,
headers={
'Content-Type''text/plain',
'Accept''application/json, text/javascript, */*; q=0.01',
'User-Agent''GreatWallDownloader/1.0'
}
            )
            print(f"状态码{ response.status_code}")
if response.status_code == 200:
data response.json()
break
        except Exception as e:
            print(f"错误{e}")
continue

    if data is None:
        print("所有 API 端点都失败了")
return False

elements data.get('elements', [])
ways = [for in elements if e['type'] == 'way']
nodes = {n['id']: (n['lon'], n['lat']) for in elements if e['type'] == 'node' for in [e]}
relations = [for in elements if e['type'] == 'relation']

    print(f"找到{len(ways)way, {len(nodes)个节点{len(relations)relation")

geometries = []
properties = []

处理 ways
for way in ways:
node_ids = [n['ref'if isinstance(n, dict) else for in way.get('nodes', [])]
coords = []
for nid in node_ids:
if isinstance(nid, int) and nid in nodes:
coords .append(nodes[nid])
elif isinstance(nid, dict) and 'lat' in nid and 'lon' in nid:
coords.append((nid['lon'], nid['lat']))

if len(coords) >= 2:
tags way.get('tags', {})
name tags.get('name''')
geometries.append(LineString(coords))
properties.append({
'name'name,
'historic'tags.get('historic'''),
'man_made'tags.get('man_made'''),
'barrier'tags.get('barrier'''),
'tourism'tags.get('tourism'''),
'osm_id'way['id'],
            })

处理 relations 中的 ways
for rel in relations:
tags rel.get('tags', {})
name tags.get('name''')
        print(f"  Relation: {name} (type={tags.get('type','')})")

for member in rel.get('members', []):
if member.get('type') == 'way':
member_ref member.get('ref')
way = next((for in ways if w['id'] == member_ref), None)
if way:
node_ids = [n['ref'if isinstance(n, dict) else for in way.get('nodes', [])]
coords = []
for nid in node_ids:
if isinstance(nid, int) and nid in nodes:
coords.append(nodes[nid])
elif isinstance(nid, dict) and 'lat' in nid and 'lon' in nid:
coords.append((nid['lon'], nid['lat']))
if len(coords) >= 2:
way_tags way.get('tags', {})
geometries.append(LineString(coords))
properties.append({
'name'name or way_tags.get('name'''),
'relation_type'tags.get('type'''),
'historic'way_tags.get('historic'''),
'osm_id'way['id'],
                        })

if not geometries:
        print("未找到长城数据")
return False

gdf = gpd.GeoDataFrame(propertiesgeometry=geometriescrs="EPSG:4326")

保存 GeoJSON
geojson_path = os.path.join(OUTPUT_DIR, "great_wall.geojson")
gdf.to_file(geojson_pathdriver="GeoJSON"encoding="utf-8")
    print(f"\n已保存 GeoJSON: {geojson_path}")

保存 Shapefile
shp_path = os.path.join(OUTPUT_DIR, "great_wall.shp")
gdf.to_file(shp_pathencoding="utf-8")
    print(f"已保存 Shapefile: {shp_path}")

    print(f"\n共 {len(gdf)条线段")
bounds  gdf.total_bounds
    print(f"范围经度 [{bounds[0]:.2f}{bounds[2]:.2f}], 纬度 [{bounds[1]:.2f}{bounds[3]:.2f}]")

显示前几条记录
print("\n5条记录:")
    print(gdf[['name''historic''man_made']].head(5).to_string())

return True

if __name__ == "__main__":
    fetch_great_wall()


Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/196664