Py学习  »  Python

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

GISAI • 5 小时前 • 12 次点击  
"""
 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