# city-json **Repository Path**: jsz315/city-json ## Basic Information - **Project Name**: city-json - **Description**: 一个基于腾讯地图 API 的省市区地址选择器项目,支持数据抓取和前端交互式选择。使用腾讯地图 API 抓取省市区街道数据(含经纬度)并保存为 JSON - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-01-08 - **Last Updated**: 2026-01-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 省市区地址选择器项目 一个基于腾讯地图 API 的省市区地址选择器项目,支持数据抓取和前端交互式选择。 ## 预览 ### 数据抓取工具 ![获取省份数据](./fetch-data.png) ### 省市区选择器 ![省市区选择](./provinces.png) ## 项目概述 本项目提供了完整的中文省市区地址选择解决方案,包括: - **数据抓取脚本**:使用腾讯地图 API 抓取省市区街道数据(含经纬度)并保存为 JSON - **后端服务**:Express 服务器提供 REST API 接口,代理腾讯地图 API - **前端选择器**:多个前端页面实现省市区街道四级联动选择功能 ## 功能特性 - ✅ **数据抓取**:批量抓取省市区街道数据,包含经纬度信息 - ✅ **数据缓存**:将抓取的数据保存为 JSON 文件,支持离线使用 - ✅ **多级联动**:支持省市区三级联动或省市区街道四级联动 - ✅ **经纬度信息**:每个行政区划都包含精确的经纬度坐标 - ✅ **实时查询**:通过后端 API 实时查询最新行政区划数据 - ✅ **响应式设计**:前端页面支持移动端和桌面端 - ✅ **错误处理**:完善的错误处理和用户提示 ## 项目结构 ``` city-json/ ├── fetch_guangxi_qqmap.js # 腾讯地图数据抓取脚本(命令行方式) ├── fetch-data.html # 交互式数据抓取工具(推荐) ├── merge_provinces.js # 合并省份数据脚本 ├── server.js # Express 后端服务器 ├── city.html # 腾讯地图省市区街道四级联动选择器(实时API) ├── provinces.html # 省市区街道四级联动选择器(本地数据) ├── qqmap_data/ # 抓取的腾讯地图数据目录 │ ├── [省份名]_city_district_street.json # 各省份的完整数据(含街道) │ └── provinces.json # 合并后的所有省份数据(由 merge_provinces.js 生成) ├── package.json # 项目依赖配置 ├── pnpm-lock.yaml # 依赖锁定文件 └── README.md # 项目说明文档 ``` ## 快速开始 ### 1. 安装依赖 ```bash # 使用 npm 安装依赖 npm install # 或使用 pnpm pnpm install ``` ### 2. 配置 API Key #### 腾讯地图 API Key 可以通过以下方式配置: 1. 环境变量:`export QQ_MAP_KEY=你的腾讯地图API密钥` 2. 在 `fetch-data.html` 页面中直接输入 获取腾讯地图 API Key: - 访问 [腾讯位置服务控制台](https://lbs.qq.com/console/) - 注册并登录账号 - 创建应用并获取 WebService API Key ### 3. 启动服务 ```bash # 启动后端服务器 npm start # 或使用开发模式(自动重启) npm run dev ``` 服务默认运行在 `http://localhost:3000` ### 4. 使用交互式数据抓取工具 **推荐方式**:使用交互式页面抓取数据 ```bash # 启动服务后,在浏览器中打开 npm run open # 或直接访问 http://localhost:3000/fetch-data.html ``` ![获取省份数据](./fetch-data.png) 功能说明: 1. **查看已抓取的省份**:页面会自动显示已抓取的省份列表 2. **加载省份列表**:输入腾讯地图 API Key 后,点击"加载省份列表" 3. **选择省份**:从列表中选择要抓取的省份(已抓取的省份会标记为"已抓取") 4. **开始抓取**:点击"开始抓取数据"按钮,系统会自动抓取该省份的所有市区街道数据 5. **保存结果**:抓取完成后,数据会自动保存为 JSON 文件到 `qqmap_data/` 目录 **传统方式**:使用命令行脚本抓取数据 ```bash # 设置 API Key 环境变量 export QQ_MAP_KEY=你的腾讯地图API密钥 # 执行抓取脚本(需要修改脚本中的省份ID) npm run fetch ``` ### 5. 合并省份数据(可选) 如果需要在本地使用所有省份数据,可以合并已抓取的省份数据: ```bash # 合并 qqmap_data 目录下所有省份数据到 provinces.json npm run merge ``` 脚本会自动: - 扫描 `qqmap_data/` 目录下所有 `*_city_district_street.json` 文件 - 读取每个省份的完整数据 - 合并为一个数组并保存到 `provinces.json` ### 6. 使用前端选择器 #### 方式一:实时 API 选择器(`city.html`) **使用场景**:需要实时获取最新数据,或只使用部分省份数据 - 确保后端服务正在运行 - 打开 `city.html` 文件 - 输入腾讯地图 API Key 并点击"初始化" - 选择省市区街道,支持四级联动 - 数据实时从后端 API 获取 #### 方式二:本地数据选择器(`provinces.html`) ![省市区选择](./provinces.png) **使用场景**:已抓取并合并了省份数据,需要离线使用或快速选择 **前提条件**:需要先运行 `npm run merge` 生成 `provinces.json` - 确保已运行合并脚本生成 `provinces.json` 文件 - 直接打开 `provinces.html` 文件(无需后端服务) - 选择省市区街道,支持四级联动 - 数据从本地 JSON 文件加载,响应更快 ## NPM 脚本命令 项目提供了便捷的 npm 脚本命令: ```bash # 启动后端服务器 npm start # 启动开发服务器(自动重启) npm run dev # 使用命令行方式抓取数据(需要设置环境变量) npm run fetch # 合并已抓取的省份数据到 provinces.json npm run merge # 在浏览器中打开数据抓取工具页面 npm run open # 在浏览器中打开腾讯地图选择器(实时API) npm run open:city # 在浏览器中打开本地数据选择器 npm run open:provinces ``` ## API 接口说明 ### 后端 API 端点 #### 腾讯地图接口 - `GET /api/qqmap/getchildren?key=API_KEY&id=父级ID` - 获取下级行政区划 - `id` 为空:返回所有省份 - `id=省编码`:返回该省下所有城市 - `id=市编码`:返回该市下所有区县 - `id=区县编码`:返回该区县下所有街道/乡镇 - `GET /api/qqmap/provinces?key=API_KEY` - 获取所有省份列表 - `POST /api/qqmap/fetch-province` - 抓取省份数据并保存为 JSON - 请求体:`{ "provinceId": "省份ID", "apiKey": "API密钥" }` #### 数据管理接口 - `GET /api/fetched-provinces` - 获取已抓取的省份列表 #### 工具接口 - `GET /api/health` - 健康检查接口 ### 数据格式 #### 腾讯地图数据格式 ```json { "id": "110000", "name": "北京", "fullname": "北京市", "location": { "lat": 39.904989, "lng": 116.405285 } } ``` ## 数据抓取功能详解 ### 交互式抓取工具(推荐) 使用 `fetch-data.html` 页面进行数据抓取,功能包括: 1. **查看已抓取的省份**:自动扫描 `qqmap_data/` 目录,显示已抓取的省份列表 2. **加载省份列表**:从腾讯地图 API 获取所有省份,已抓取的省份会自动标记 3. **选择省份**:点击要抓取的省份(未抓取的省份可点击选择) 4. **抓取数据**:点击"开始抓取数据"按钮,系统会: - 获取该省份的所有城市 - 获取每个城市的所有区县 - 获取每个区县的所有街道/乡镇 - 每次请求间隔 2 秒(避免 API 频率限制) - 保存为 JSON 文件到 `qqmap_data/` 目录 5. **实时日志**:显示抓取过程的详细日志 6. **进度显示**:显示抓取进度条 **优点**: - 可视化界面,操作简单 - 自动识别已抓取的省份,避免重复抓取 - 实时显示抓取进度和日志 - 支持选择任意省份进行抓取 ### 命令行抓取脚本 `fetch_guangxi_qqmap.js` 脚本的工作流程: 1. **获取省份列表**:调用腾讯地图 API 获取所有省份 2. **获取城市数据**:依次获取每个省份下的所有城市 3. **获取区县数据**:依次获取每个城市下的所有区县 4. **获取街道数据**:依次获取每个区县下的所有街道/乡镇 5. **数据整合**:将所有数据整合成层级结构 6. **保存文件**:将结果保存为 JSON 文件 **特点**: - 每次请求间隔 2 秒,避免触发 API 频率限制 - 支持错误重试和跳过机制 - 输出完整的层级结构,包含经纬度信息 - 自动创建输出目录 **注意**:脚本中硬编码了省份ID,需要修改才能抓取其他省份。 ### 合并省份数据脚本 `merge_provinces.js` 脚本的工作流程: 1. **扫描数据目录**:自动扫描 `qqmap_data/` 目录下所有 `*_city_district_street.json` 文件 2. **读取省份数据**:读取每个省份的完整数据(省市区街道) 3. **验证数据格式**:检查数据是否包含必需的字段(province、cities) 4. **合并数据**:将所有省份数据合并为一个数组 5. **排序**:按省份名称排序(中文排序) 6. **保存文件**:将合并后的数据保存到 `qqmap_data/provinces.json` **特点**: - 自动识别所有省份数据文件 - 完整的错误处理和日志输出 - 统计信息显示(省份数、城市数、区县数、街道数) - 支持增量合并(新抓取的省份会自动包含) **使用场景**: - 需要离线使用所有省份数据 - 使用 `provinces.html` 本地选择器 - 将多个省份数据整合为一个文件 ## 使用示例 ### 使用腾讯地图选择器 ```javascript // 通过后端代理接口调用 async function getChildrenDistricts(parentId = '') { const url = `/api/qqmap/getchildren?key=${qqMapKey}&id=${parentId}`; const response = await fetch(url); const data = await response.json(); return data.result[0]; // 返回第一级数组 } // 获取省份 const provinces = await getChildrenDistricts(''); // 获取城市 const cities = await getChildrenDistricts('110000'); // 获取区县 const districts = await getChildrenDistricts('110100'); ``` ### 读取本地 JSON 数据 #### 读取单个省份数据 ```javascript // 使用 fetch 加载单个省份的 JSON 文件 fetch('./qqmap_data/guangxi_city_district_street.json') .then(response => response.json()) .then(data => { console.log('省份:', data.province); console.log('城市数量:', data.cities.length); // 使用数据填充选择器 }); ``` #### 读取合并后的所有省份数据 ```javascript // 使用 fetch 加载合并后的 provinces.json fetch('./qqmap_data/provinces.json') .then(response => response.json()) .then(provinces => { console.log('省份数量:', provinces.length); provinces.forEach(provinceData => { console.log(provinceData.province.fullname, provinceData.cities.length, '个城市'); }); // 使用数据填充选择器(如 provinces.html) }); ``` ### 工作流程示例 **完整的数据处理流程**: ```bash # 1. 启动后端服务 npm start # 2. 使用交互式工具抓取省份数据 npm run open # 在浏览器中选择并抓取需要的省份 # 3. 合并所有已抓取的省份数据 npm run merge # 4. 使用本地数据选择器(无需后端) npm run open:provinces ``` ## 注意事项 1. **API 频率限制**: - 腾讯地图 API 有 QPS 限制,抓取脚本已设置 2 秒间隔 - 请合理使用 API,避免触发频率限制 2. **API Key 安全**: - 不要将 API Key 提交到版本控制系统 - 生产环境建议使用环境变量或配置文件管理 - 可以考虑在服务器端代理,避免前端直接调用 3. **数据更新**: - 行政区划数据会不定期更新 - 建议定期重新抓取数据以获取最新信息 - 实时查询接口始终返回最新数据 4. **浏览器兼容性**: - 需要支持 ES6+ 语法的现代浏览器 - 建议使用 Chrome、Firefox、Safari、Edge 最新版本 5. **跨域问题**: - 前端页面需要后端服务运行在同一域名下 - 或配置 CORS 允许跨域访问 ## 开发说明 ### 依赖包 - `express` - Web 服务器框架 - `axios` - HTTP 客户端 - `cors` - 跨域资源共享中间件 - `nodemon` - 开发时自动重启(开发依赖) ### 脚本命令 ```bash # 启动开发服务器(自动重启) pnpm run dev # 启动生产服务器 pnpm start # 运行测试(如果有) pnpm test ``` ## 使用示例 ### 使用交互式抓取工具 1. 启动后端服务: ```bash npm start ``` 2. 在浏览器中打开: ```bash npm run open # 或访问 http://localhost:3000/fetch-data.html ``` 3. 在页面中: - 输入腾讯地图 API Key - 点击"加载省份列表" - 选择要抓取的省份 - 点击"开始抓取数据" - 等待抓取完成,数据会自动保存 ### 使用命令行抓取脚本 ```bash # 设置环境变量 export QQ_MAP_KEY=你的腾讯地图API密钥 # 执行抓取(需要先修改脚本中的省份ID) npm run fetch ``` ## 常见问题 **Q: 抓取数据时提示 API Key 错误?** A: 请确保: 1. API Key 已正确配置 2. API Key 已开通 WebService API 权限 3. API Key 未过期或被禁用 **Q: 前端选择器无法加载数据?** A: 请检查: 1. 后端服务是否正在运行 2. API Key 是否正确配置 3. 浏览器控制台是否有错误信息 4. 网络连接是否正常 **Q: 如何查看已抓取的省份?** A: 使用交互式抓取工具页面,页面会自动显示已抓取的省份列表。也可以查看 `qqmap_data/` 目录下的 JSON 文件。 **Q: 数据抓取很慢怎么办?** A: 数据抓取需要调用大量 API,每 2 秒请求一次是为了避免触发频率限制。如果需要加快速度,可以适当减小 `REQUEST_INTERVAL`,但需注意不要超过 API 限制。一个省份的数据通常需要几分钟到十几分钟不等,具体取决于该省份的城市和区县数量。 ## 贡献 欢迎提交 Issue 和 Pull Request! ## 许可证 MIT License ## 相关链接 - [腾讯位置服务 API 文档](https://lbs.qq.com/service/webService/webServiceGuide/webServiceOverview) - [Express.js 官方文档](https://expressjs.com/)