
Map
- 38 installs
- 760 repo stars
- Updated July 15, 2026
- countbot-ai/countbot
Plan driving, walking, cycling, and transit routes and search POIs like attractions and restaurants via the Amap (Gaode) API.
About
A CLI wrapping the Amap (Gaode) Maps API for multi-mode route planning and POI search. A developer uses it when an agent needs routes, trip planning, or place recommendations.
- Driving, walking, cycling, and transit route planning
- POI search for attractions and restaurants; needs an Amap API key
Map by the numbers
- 38 all-time installs (skills.sh)
- Ranked #1,158 of 2,715 Automation & Workflows skills by installs in the Skillselion catalog
- Data as of Jul 31, 2026 (Skillselion catalog sync)
npx skills add https://github.com/countbot-ai/countbot --skill mapAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 38 |
|---|---|
| repo stars | ★ 760 |
| Last updated | July 15, 2026 |
| Repository | countbot-ai/countbot ↗ |
What it does
Plan driving, walking, cycling, and transit routes and search POIs like attractions and restaurants via the Amap (Gaode) API.
Files
地图路线规划与 POI 搜索
基于高德地图 API 的路线规划和 POI 搜索服务。
配置
编辑 skills/map/scripts/config.json,填写高德地图 API Key:
{
"amap_key": "YOUR_AMAP_KEY"
}AI 调用示例
用户说"我想去东莞玩3天":
# 1. 搜索景点
python3 skills/map/scripts/map.py attractions --city 东莞 --page-size 20 --json
# 2. 查询景点间路线
python3 skills/map/scripts/map.py driving --origin "旗峰公园" --destination "可园博物馆" --origin-city 东莞 --dest-city 东莞用户说"东莞有什么好吃的":
python3 skills/map/scripts/map.py restaurants --city 东莞 --page-size 20 --json用户说"从天安门到鸟巢坐地铁怎么走":
python3 skills/map/scripts/map.py transit --origin "天安门" --destination "鸟巢" --city1 010 --city2 010命令行参考
路线规划
# 驾车
python3 skills/map/scripts/map.py driving --origin "起点" --destination "终点" --origin-city 城市 --dest-city 城市
# 步行
python3 skills/map/scripts/map.py walking --origin "起点" --destination "终点" --origin-city 城市 --dest-city 城市
# 公交(需要城市编码)
python3 skills/map/scripts/map.py transit --origin "起点" --destination "终点" --city1 编码 --city2 编码
# 显示详细步骤
python3 skills/map/scripts/map.py driving --origin "起点" --destination "终点" --show-stepsPOI 搜索
# 景点搜索(风景名胜 + 博物馆)
python3 skills/map/scripts/map.py attractions --city 城市 --page-size 20
# 餐厅搜索(排除快餐)
python3 skills/map/scripts/map.py restaurants --city 城市 --page-size 20
# 通用搜索
python3 skills/map/scripts/map.py search --keywords 关键词 --city 城市常用城市编码
| 城市 | 编码 | 城市 | 编码 |
|---|---|---|---|
| 北京 | 010 | 上海 | 021 |
| 广州 | 020 | 深圳 | 0755 |
| 东莞 | 0769 | 杭州 | 0571 |
注意事项
- 支持地址名称或经纬度坐标作为起终点,系统自动识别
- 建议提供城市参数以提高地址解析准确性
- 公交路线必须提供城市编码
- 所有搜索命令支持
--json输出
{
"amap_key": ""
}{
"amap_key": "your_amap_api_key_here"
}
# -*- coding: utf-8 -*-
"""高德地图路线规划核心模块"""
import requests
import json
import os
import re
from typing import Dict, List, Optional, Tuple
# 修复 Windows CMD 下的编码问题
if os.name == 'nt': # Windows
os.environ['PYTHONIOENCODING'] = 'utf-8'
class MapManager:
"""高德地图管理器"""
def __init__(self, api_key: str):
"""初始化地图管理器
Args:
api_key: 高德地图API Key
"""
self.api_key = api_key
self.base_url = "https://restapi.amap.com/v5/direction"
self.geocode_url = "https://restapi.amap.com/v3/geocode/geo"
self.poi_search_url = "https://restapi.amap.com/v5/place/text"
self.poi_around_url = "https://restapi.amap.com/v5/place/around"
def _is_coordinate(self, location: str) -> bool:
"""判断是否为坐标格式
Args:
location: 位置字符串
Returns:
是否为坐标格式
"""
# 匹配经纬度格式:数字,数字
pattern = r'^-?\d+\.?\d*,-?\d+\.?\d*$'
return bool(re.match(pattern, location.strip()))
def geocode(self, address: str, city: Optional[str] = None) -> Tuple[str, str]:
"""地理编码:将地址转换为坐标
Args:
address: 地址描述
city: 城市名称(可选,用于提高准确性)
Returns:
(经纬度坐标, 格式化地址)
"""
params = {
'key': self.api_key,
'address': address,
'output': 'json'
}
if city:
params['city'] = city
try:
response = requests.get(self.geocode_url, params=params, timeout=10)
response.raise_for_status()
data = response.json()
if data.get('status') == '1' and data.get('geocodes'):
geocode = data['geocodes'][0]
location = geocode.get('location', '')
formatted_address = geocode.get('formatted_address', address)
if not location:
raise Exception(f"无法获取地址坐标: {address}")
return location, formatted_address
else:
raise Exception(f"地理编码失败: {data.get('info', '未知错误')}")
except requests.exceptions.RequestException as e:
raise Exception(f"地理编码请求失败: {str(e)}")
def smart_location(self, location: str, city: Optional[str] = None) -> Tuple[str, str]:
"""智能位置解析:自动判断是坐标还是地址
Args:
location: 位置(可以是坐标或地址)
city: 城市名称(可选)
Returns:
(经纬度坐标, 显示名称)
"""
if self._is_coordinate(location):
return location, location
else:
coord, formatted_addr = self.geocode(location, city)
return coord, formatted_addr
def _make_request(self, endpoint: str, params: Dict) -> Dict:
"""发送API请求
Args:
endpoint: API端点
params: 请求参数
Returns:
API响应数据
"""
params['key'] = self.api_key
params['output'] = 'json'
try:
response = requests.get(f"{self.base_url}/{endpoint}", params=params, timeout=10)
response.raise_for_status()
data = response.json()
if data.get('status') == '1':
return data
else:
raise Exception(f"API错误: {data.get('info', '未知错误')}")
except requests.exceptions.RequestException as e:
raise Exception(f"请求失败: {str(e)}")
def driving_route(self,
origin: str,
destination: str,
strategy: int = 32,
waypoints: Optional[str] = None,
avoidpolygons: Optional[str] = None,
plate: Optional[str] = None,
cartype: int = 0,
ferry: int = 0,
show_fields: Optional[str] = None,
origin_city: Optional[str] = None,
dest_city: Optional[str] = None) -> Dict:
"""驾车路线规划
Args:
origin: 起点 (可以是经纬度或地址)
destination: 终点 (可以是经纬度或地址)
strategy: 驾车策略 (默认32-高德推荐)
waypoints: 途经点 (多个用;分隔)
avoidpolygons: 避让区域
plate: 车牌号
cartype: 车辆类型 (0-燃油, 1-纯电, 2-插混)
ferry: 是否使用轮渡 (0-使用, 1-不使用)
show_fields: 返回字段控制
origin_city: 起点城市(用于地理编码)
dest_city: 终点城市(用于地理编码)
Returns:
路线规划结果(包含origin_name和dest_name字段)
"""
# 智能解析起点和终点
origin_coord, origin_name = self.smart_location(origin, origin_city)
dest_coord, dest_name = self.smart_location(destination, dest_city)
params = {
'origin': origin_coord,
'destination': dest_coord,
'strategy': strategy,
'cartype': cartype,
'ferry': ferry
}
if waypoints:
params['waypoints'] = waypoints
if avoidpolygons:
params['avoidpolygons'] = avoidpolygons
if plate:
params['plate'] = plate
if show_fields:
params['show_fields'] = show_fields
result = self._make_request('driving', params)
# 添加地址信息到结果中
result['origin_name'] = origin_name
result['dest_name'] = dest_name
return result
def walking_route(self,
origin: str,
destination: str,
alternative_route: Optional[int] = None,
show_fields: Optional[str] = None,
isindoor: int = 0,
origin_city: Optional[str] = None,
dest_city: Optional[str] = None) -> Dict:
"""步行路线规划
Args:
origin: 起点 (可以是经纬度或地址)
destination: 终点 (可以是经纬度或地址)
alternative_route: 返回路线条数 (1-3)
show_fields: 返回字段控制
isindoor: 是否需要室内算路 (0-不需要, 1-需要)
origin_city: 起点城市(用于地理编码)
dest_city: 终点城市(用于地理编码)
Returns:
路线规划结果
"""
# 智能解析起点和终点
origin_coord, origin_name = self.smart_location(origin, origin_city)
dest_coord, dest_name = self.smart_location(destination, dest_city)
params = {
'origin': origin_coord,
'destination': dest_coord,
'isindoor': isindoor
}
if alternative_route:
params['alternative_route'] = alternative_route
if show_fields:
params['show_fields'] = show_fields
result = self._make_request('walking', params)
result['origin_name'] = origin_name
result['dest_name'] = dest_name
return result
def bicycling_route(self,
origin: str,
destination: str,
alternative_route: Optional[int] = None,
show_fields: Optional[str] = None) -> Dict:
"""骑行路线规划
Args:
origin: 起点经纬度
destination: 终点经纬度
alternative_route: 返回路线条数 (1-3)
show_fields: 返回字段控制
Returns:
路线规划结果
"""
params = {
'origin': origin,
'destination': destination
}
if alternative_route:
params['alternative_route'] = alternative_route
if show_fields:
params['show_fields'] = show_fields
return self._make_request('bicycling', params)
def electrobike_route(self,
origin: str,
destination: str,
alternative_route: Optional[int] = None,
show_fields: Optional[str] = None) -> Dict:
"""电动车路线规划
Args:
origin: 起点经纬度
destination: 终点经纬度
alternative_route: 返回路线条数 (1-3)
show_fields: 返回字段控制
Returns:
路线规划结果
"""
params = {
'origin': origin,
'destination': destination
}
if alternative_route:
params['alternative_route'] = alternative_route
if show_fields:
params['show_fields'] = show_fields
return self._make_request('electrobike', params)
def transit_route(self,
origin: str,
destination: str,
city1: str,
city2: str,
strategy: int = 0,
alternative_route: int = 5,
nightflag: int = 0,
show_fields: Optional[str] = None,
date: Optional[str] = None,
time: Optional[str] = None) -> Dict:
"""公交路线规划
Args:
origin: 起点 (可以是经纬度或地址)
destination: 终点 (可以是经纬度或地址)
city1: 起点城市编码
city2: 终点城市编码
strategy: 换乘策略 (0-推荐, 1-最经济, 2-最少换乘, 3-最少步行, 4-最舒适)
alternative_route: 返回方案条数 (1-10)
nightflag: 是否考虑夜班车 (0-不考虑, 1-考虑)
show_fields: 返回字段控制
date: 请求日期 (格式: YYYY-MM-DD)
time: 请求时间 (格式: HH-MM)
Returns:
路线规划结果
"""
# 智能解析起点和终点(公交使用city1/city2作为城市参数)
origin_coord, origin_name = self.smart_location(origin, city1)
dest_coord, dest_name = self.smart_location(destination, city2)
params = {
'origin': origin_coord,
'destination': dest_coord,
'city1': city1,
'city2': city2,
'strategy': strategy,
'AlternativeRoute': alternative_route,
'nightflag': nightflag
}
if show_fields:
params['show_fields'] = show_fields
if date:
params['date'] = date
if time:
params['time'] = time
result = self._make_request('transit/integrated', params)
result['origin_name'] = origin_name
result['dest_name'] = dest_name
return result
def format_driving_result(self, result: Dict, show_steps: bool = False, simple: bool = True) -> str:
"""格式化驾车路线结果
Args:
result: API返回的原始结果
show_steps: 是否显示详细路线步骤(需要API返回navi字段)
simple: 是否使用简洁模式(默认True,只显示推荐路线)
Returns:
格式化后的文本
"""
if result.get('status') != '1':
return f"查询失败: {result.get('info', '未知错误')}"
route = result.get('route', {})
paths = route.get('paths', [])
if not paths:
return "未找到路线"
output = []
# 显示地址信息
origin_name = result.get('origin_name', route.get('origin', ''))
dest_name = result.get('dest_name', route.get('destination', ''))
output.append(f"{origin_name} -> {dest_name}")
# 简洁模式:只显示第一条(推荐)路线
if simple:
path = paths[0]
distance = float(path.get('distance', 0))
if 'cost' in path:
cost = path['cost']
duration = int(cost.get('duration', 0))
tolls = cost.get('tolls', '0')
output.append(f"[驾车] 距离 {distance/1000:.1f}公里 | 耗时 {duration//60}分钟 | 过路费 {tolls}元")
else:
output.append(f"[驾车] 距离 {distance/1000:.1f}公里")
restriction = path.get('restriction', '0')
if restriction == '1':
output.append(f"[注意] 该路线有限行路段")
else:
# 完整模式:显示所有路线
output.append(f"共找到 {len(paths)} 条路线\n")
for idx, path in enumerate(paths, 1):
distance = float(path.get('distance', 0))
output.append(f"方案 {idx}:")
output.append(f" 距离: {distance/1000:.2f} 公里")
if 'cost' in path:
cost = path['cost']
duration = int(cost.get('duration', 0))
tolls = cost.get('tolls', '0')
output.append(f" 耗时: {duration//60} 分钟")
output.append(f" 过路费: {tolls} 元")
restriction = path.get('restriction', '0')
if restriction == '1':
output.append(f" [注意] 该路线有限行路段")
output.append("")
# 显示详细路线步骤(仅在show_steps=True时)
if show_steps and 'steps' in paths[0]:
output.append(f"\n详细路线指引:")
steps = paths[0]['steps']
# 只显示前10步,避免输出过长
max_steps = min(10, len(steps))
for step_idx, step in enumerate(steps[:max_steps], 1):
instruction = step.get('instruction', '')
road_name = step.get('road_name', '')
step_distance = float(step.get('step_distance', 0))
if road_name:
output.append(f" {step_idx}. {instruction} ({road_name}, {step_distance/1000:.1f}km)")
else:
output.append(f" {step_idx}. {instruction} ({step_distance/1000:.1f}km)")
if len(steps) > max_steps:
output.append(f" ... 还有 {len(steps) - max_steps} 步(使用--show-all查看完整路线)")
return "\n".join(output)
def format_walking_result(self, result: Dict, show_steps: bool = False, simple: bool = True) -> str:
"""格式化步行路线结果
Args:
result: API返回的原始结果
show_steps: 是否显示详细路线步骤
simple: 是否使用简洁模式(默认True)
Returns:
格式化后的文本
"""
if result.get('status') != '1':
return f"查询失败: {result.get('info', '未知错误')}"
route = result.get('route', {})
paths = route.get('paths', [])
if not paths:
return "未找到路线"
output = []
origin_name = result.get('origin_name', route.get('origin', ''))
dest_name = result.get('dest_name', route.get('destination', ''))
output.append(f"{origin_name} -> {dest_name}")
# 简洁模式
if simple:
path = paths[0]
distance = float(path.get('distance', 0))
if 'cost' in path:
cost = path['cost']
duration = int(cost.get('duration', 0))
output.append(f"[步行] 距离 {distance/1000:.1f}公里 | 步行约 {duration//60}分钟")
else:
output.append(f"[步行] 距离 {distance/1000:.1f}公里")
else:
output.append(f"共找到 {len(paths)} 条路线\n")
for idx, path in enumerate(paths, 1):
distance = float(path.get('distance', 0))
output.append(f"方案 {idx}: {distance/1000:.2f}公里")
if 'cost' in path:
duration = int(path['cost'].get('duration', 0))
output.append(f" 耗时: {duration//60}分钟")
output.append("")
return "\n".join(output)
def format_transit_result(self, result: Dict, show_steps: bool = False, simple: bool = True) -> str:
"""格式化公交路线结果
Args:
result: API返回的原始结果
show_steps: 是否显示详细换乘步骤
simple: 是否使用简洁模式(默认True,只显示推荐路线)
Returns:
格式化后的文本
"""
if result.get('status') != '1':
return f"查询失败: {result.get('info', '未知错误')}"
route = result.get('route', {})
transits = route.get('transits', [])
if not transits:
return "未找到路线"
output = []
origin_name = result.get('origin_name', route.get('origin', ''))
dest_name = result.get('dest_name', route.get('destination', ''))
output.append(f"{origin_name} -> {dest_name}")
# 简洁模式:只显示推荐路线
if simple:
transit = transits[0]
distance = float(transit.get('distance', 0))
if 'cost' in transit:
cost = transit['cost']
duration = int(cost.get('duration', 0))
transit_fee = cost.get('transit_fee', '0')
output.append(f"[公交] 距离 {distance/1000:.1f}公里 | 耗时 {duration//60}分钟 | 票价 {transit_fee}元")
# 简要显示换乘信息
if 'segments' in transit:
bus_lines = []
for segment in transit['segments']:
if 'bus' in segment:
bus = segment['bus']
for busline in bus.get('buslines', []):
bus_lines.append(busline.get('name', ''))
if bus_lines:
output.append(f" 换乘: {' → '.join(bus_lines)}")
else:
output.append(f"共找到 {len(transits)} 条路线\n")
for idx, transit in enumerate(transits[:3], 1): # 最多显示3条
distance = float(transit.get('distance', 0))
output.append(f"方案 {idx}: {distance/1000:.1f}公里")
if 'cost' in transit:
duration = int(transit['cost'].get('duration', 0))
transit_fee = transit['cost'].get('transit_fee', '0')
output.append(f" 耗时: {duration//60}分钟 | 票价: {transit_fee}元")
output.append("")
return "\n".join(output)
def search_poi(self, keywords: str, city: Optional[str] = None, types: Optional[str] = None, page_size: int = 10) -> Dict:
"""POI搜索 - 用于旅游规划
Args:
keywords: 搜索关键词(如"景点"、"美食"、"酒店")
city: 城市名称或编码
types: POI类型编码(如"110000"表示风景名胜,多个用|分隔)
常用类型:
- 110000: 风景名胜(推荐用于景点搜索)
- 050000: 餐饮服务
- 100000: 住宿服务
- 140000: 科教文化(博物馆等)
page_size: 返回结果数量(1-25)
Returns:
POI搜索结果
"""
params = {
'key': self.api_key,
'keywords': keywords,
'page_size': min(page_size, 25),
'output': 'json'
}
if city:
params['region'] = city
if types:
params['types'] = types
try:
response = requests.get(self.poi_search_url, params=params, timeout=10)
response.raise_for_status()
data = response.json()
if data.get('status') == '1':
return data
else:
raise Exception(f"POI搜索失败: {data.get('info', '未知错误')}")
except requests.exceptions.RequestException as e:
raise Exception(f"POI搜索请求失败: {str(e)}")
def search_attractions(self, city: str, page_size: int = 20) -> Dict:
"""搜索景点(只返回风景名胜类POI)
Args:
city: 城市名称
page_size: 返回结果数量(1-25)
Returns:
景点搜索结果
"""
# 使用类型编码110000(风景名胜)来精确搜索景点
return self.search_poi(
keywords="景点",
city=city,
types="110000|140100", # 风景名胜 | 博物馆
page_size=page_size
)
def search_restaurants(self, city: str, page_size: int = 20) -> Dict:
"""搜索餐厅(排除快餐)
Args:
city: 城市名称
page_size: 返回结果数量(1-25)
Returns:
餐厅搜索结果
"""
# 使用类型编码050100(中餐厅)、050200(外国餐厅)
return self.search_poi(
keywords="餐厅",
city=city,
types="050100|050200", # 中餐厅 | 外国餐厅
page_size=page_size
)
def format_poi_result(self, result: Dict, simple: bool = True) -> str:
"""格式化POI搜索结果
Args:
result: POI搜索结果
simple: 是否使用简洁模式
Returns:
格式化后的文本
"""
if result.get('status') != '1':
return f"搜索失败: {result.get('info', '未知错误')}"
pois = result.get('pois', [])
if not pois:
return "未找到相关地点"
output = []
output.append(f"找到 {len(pois)} 个地点:\n")
for idx, poi in enumerate(pois, 1):
name = poi.get('name', '')
address = poi.get('address', '')
type_name = poi.get('type', '')
if simple:
output.append(f"{idx}. {name}")
if address:
output.append(f" {address}")
else:
output.append(f"{idx}. {name}")
output.append(f" 类型: {type_name}")
output.append(f" 地址: {address}")
# 显示距离(如果有)
if 'distance' in poi:
distance = float(poi['distance'])
output.append(f" 距离: {distance/1000:.1f}公里")
output.append("")
return "\n".join(output)
def load_config(config_path: str = None) -> Dict:
"""加载配置文件"""
if config_path is None:
config_path = os.path.join(os.path.dirname(__file__), 'config.json')
if not os.path.exists(config_path):
raise FileNotFoundError(
f"配置文件不存在: {config_path}\n"
f"请复制 config.json.example 为 config.json 并填写您的高德地图API Key"
)
with open(config_path, 'r', encoding='utf-8') as f:
return json.load(f)
def save_config(config: Dict, config_path: str = None):
"""保存配置文件"""
if config_path is None:
config_path = os.path.join(os.path.dirname(__file__), 'config.json')
with open(config_path, 'w', encoding='utf-8') as f:
json.dump(config, f, ensure_ascii=False, indent=2)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""高德地图路线规划命令行工具"""
import argparse
import sys
import json
import os
from map_manager import MapManager, load_config
# 修复 Windows CMD 下的编码问题
if sys.platform == 'win32':
# 设置环境变量强制使用 UTF-8
os.environ['PYTHONIOENCODING'] = 'utf-8'
def main():
parser = argparse.ArgumentParser(description='高德地图路线规划工具')
subparsers = parser.add_subparsers(dest='command', help='路线规划类型')
# 驾车路线规划
driving_parser = subparsers.add_parser('driving', help='驾车路线规划')
driving_parser.add_argument('--origin', required=True, help='起点 (地址或经纬度)')
driving_parser.add_argument('--destination', required=True, help='终点 (地址或经纬度)')
driving_parser.add_argument('--origin-city', help='起点城市 (用于地址解析)')
driving_parser.add_argument('--dest-city', help='终点城市 (用于地址解析)')
driving_parser.add_argument('--strategy', type=int, default=32, help='驾车策略 (默认32-高德推荐)')
driving_parser.add_argument('--waypoints', help='途经点 (多个用;分隔)')
driving_parser.add_argument('--plate', help='车牌号')
driving_parser.add_argument('--cartype', type=int, default=0, choices=[0, 1, 2],
help='车辆类型 (0-燃油, 1-纯电, 2-插混)')
driving_parser.add_argument('--show-fields', help='返回字段控制 (如: cost,polyline)')
driving_parser.add_argument('--show-steps', action='store_true', help='显示详细路线步骤')
driving_parser.add_argument('--json', action='store_true', help='输出JSON格式')
# 步行路线规划
walking_parser = subparsers.add_parser('walking', help='步行路线规划')
walking_parser.add_argument('--origin', required=True, help='起点 (地址或经纬度)')
walking_parser.add_argument('--destination', required=True, help='终点 (地址或经纬度)')
walking_parser.add_argument('--origin-city', help='起点城市 (用于地址解析)')
walking_parser.add_argument('--dest-city', help='终点城市 (用于地址解析)')
walking_parser.add_argument('--alternative', type=int, choices=[1, 2, 3],
help='返回路线条数 (1-3)')
walking_parser.add_argument('--show-fields', help='返回字段控制')
walking_parser.add_argument('--show-steps', action='store_true', help='显示详细路线步骤')
walking_parser.add_argument('--json', action='store_true', help='输出JSON格式')
# 骑行路线规划
bicycling_parser = subparsers.add_parser('bicycling', help='骑行路线规划')
bicycling_parser.add_argument('--origin', required=True, help='起点经纬度')
bicycling_parser.add_argument('--destination', required=True, help='终点经纬度')
bicycling_parser.add_argument('--alternative', type=int, choices=[1, 2, 3],
help='返回路线条数 (1-3)')
bicycling_parser.add_argument('--show-fields', help='返回字段控制')
bicycling_parser.add_argument('--json', action='store_true', help='输出JSON格式')
# 电动车路线规划
electrobike_parser = subparsers.add_parser('electrobike', help='电动车路线规划')
electrobike_parser.add_argument('--origin', required=True, help='起点经纬度')
electrobike_parser.add_argument('--destination', required=True, help='终点经纬度')
electrobike_parser.add_argument('--alternative', type=int, choices=[1, 2, 3],
help='返回路线条数 (1-3)')
electrobike_parser.add_argument('--show-fields', help='返回字段控制')
electrobike_parser.add_argument('--json', action='store_true', help='输出JSON格式')
# 公交路线规划
transit_parser = subparsers.add_parser('transit', help='公交路线规划')
transit_parser.add_argument('--origin', required=True, help='起点 (地址或经纬度)')
transit_parser.add_argument('--destination', required=True, help='终点 (地址或经纬度)')
transit_parser.add_argument('--city1', required=True, help='起点城市编码')
transit_parser.add_argument('--city2', required=True, help='终点城市编码')
transit_parser.add_argument('--strategy', type=int, default=0,
help='换乘策略 (0-推荐, 1-最经济, 2-最少换乘, 3-最少步行)')
transit_parser.add_argument('--alternative', type=int, default=5,
help='返回方案条数 (1-10)')
transit_parser.add_argument('--nightflag', type=int, default=0, choices=[0, 1],
help='是否考虑夜班车 (0-不考虑, 1-考虑)')
transit_parser.add_argument('--show-fields', help='返回字段控制')
transit_parser.add_argument('--show-steps', action='store_true', help='显示详细换乘步骤')
transit_parser.add_argument('--json', action='store_true', help='输出JSON格式')
# POI搜索
search_parser = subparsers.add_parser('search', help='POI搜索')
search_parser.add_argument('--keywords', required=True, help='搜索关键词 (如: 景点, 美食, 酒店)')
search_parser.add_argument('--city', required=True, help='城市名称')
search_parser.add_argument('--types', help='POI类型编码 (如: 110000=风景名胜, 050100=中餐厅)')
search_parser.add_argument('--page-size', type=int, default=10, help='返回结果数量 (1-25)')
search_parser.add_argument('--json', action='store_true', help='输出JSON格式')
# 景点搜索(快捷方式)
attractions_parser = subparsers.add_parser('attractions', help='搜索景点(只返回风景名胜)')
attractions_parser.add_argument('--city', required=True, help='城市名称')
attractions_parser.add_argument('--page-size', type=int, default=20, help='返回结果数量 (1-25)')
attractions_parser.add_argument('--json', action='store_true', help='输出JSON格式')
# 餐厅搜索(快捷方式)
restaurants_parser = subparsers.add_parser('restaurants', help='搜索餐厅(排除快餐)')
restaurants_parser.add_argument('--city', required=True, help='城市名称')
restaurants_parser.add_argument('--page-size', type=int, default=20, help='返回结果数量 (1-25)')
restaurants_parser.add_argument('--json', action='store_true', help='输出JSON格式')
args = parser.parse_args()
if not args.command:
parser.print_help()
return 1
try:
# 加载配置
config = load_config()
manager = MapManager(config['amap_key'])
# 执行命令
if args.command == 'driving':
result = manager.driving_route(
origin=args.origin,
destination=args.destination,
origin_city=getattr(args, 'origin_city', None),
dest_city=getattr(args, 'dest_city', None),
strategy=args.strategy,
waypoints=args.waypoints,
plate=args.plate,
cartype=args.cartype,
show_fields=args.show_fields or ('cost,navi' if args.show_steps else 'cost')
)
if args.json:
print(json.dumps(result, ensure_ascii=False, indent=2))
else:
print(manager.format_driving_result(result, show_steps=args.show_steps))
elif args.command == 'walking':
result = manager.walking_route(
origin=args.origin,
destination=args.destination,
origin_city=getattr(args, 'origin_city', None),
dest_city=getattr(args, 'dest_city', None),
alternative_route=args.alternative,
show_fields=args.show_fields or ('cost,navi' if args.show_steps else 'cost')
)
if args.json:
print(json.dumps(result, ensure_ascii=False, indent=2))
else:
print(manager.format_walking_result(result, show_steps=args.show_steps))
elif args.command == 'bicycling':
result = manager.bicycling_route(
origin=args.origin,
destination=args.destination,
alternative_route=args.alternative,
show_fields=args.show_fields
)
if args.json:
print(json.dumps(result, ensure_ascii=False, indent=2))
else:
print(manager.format_walking_result(result))
elif args.command == 'electrobike':
result = manager.electrobike_route(
origin=args.origin,
destination=args.destination,
alternative_route=args.alternative,
show_fields=args.show_fields
)
if args.json:
print(json.dumps(result, ensure_ascii=False, indent=2))
else:
print(manager.format_walking_result(result))
elif args.command == 'transit':
result = manager.transit_route(
origin=args.origin,
destination=args.destination,
city1=args.city1,
city2=args.city2,
strategy=args.strategy,
alternative_route=args.alternative,
nightflag=args.nightflag,
show_fields=args.show_fields or ('cost' if not args.show_steps else 'cost')
)
if args.json:
print(json.dumps(result, ensure_ascii=False, indent=2))
else:
print(manager.format_transit_result(result, show_steps=args.show_steps))
elif args.command == 'search':
result = manager.search_poi(
keywords=args.keywords,
city=args.city,
types=args.types,
page_size=args.page_size
)
if args.json:
print(json.dumps(result, ensure_ascii=False, indent=2))
else:
print(manager.format_poi_result(result))
elif args.command == 'attractions':
result = manager.search_attractions(
city=args.city,
page_size=args.page_size
)
if args.json:
print(json.dumps(result, ensure_ascii=False, indent=2))
else:
print(manager.format_poi_result(result))
elif args.command == 'restaurants':
result = manager.search_restaurants(
city=args.city,
page_size=args.page_size
)
if args.json:
print(json.dumps(result, ensure_ascii=False, indent=2))
else:
print(manager.format_poi_result(result))
return 0
except Exception as e:
print(f"错误: {str(e)}", file=sys.stderr)
return 1
if __name__ == '__main__':
sys.exit(main())
Related skills
Automation & Workflowsworkflow