1. 场景和需求:
在局域网开发的web项目,不能连接公网
1 需要使用离线地图展示设备点位;
2 需要实现地图的城市范围内的离线搜索,可以检索到百度地图上的点位,类似与百度地图首页的搜索功能,但是把搜索限定在指定城市或区域;
离线地图的实现不在此做讲解,其他一些博客讲解的比较详细,可以搜索一下
这里重点讲一下离线地图的poi数据获取
2. 实现思路:
两种实现方法
- 从百度地图或者高德地图, 根据地图厂商的poi分类和检索接口,根据接口获取数据后保存起来,数据整理后保存到数据库,搜索时根据关键词做模糊搜索
- 从地图页面爬取poi数据
1. 根据接口检索
以百度地图为例:
百度地图poi分类:
https://lbsyun.baidu.com/index.php?title=open/poitags
地点检索api:
https://lbsyun.baidu.com/cms/jsapi/reference/jsapi_reference_3_0.html#a7b33
根据检索poi方法
// 在北京市范围内检索中关村
var map = new BMap.Map("container");
map.centerAndZoom(new BMap.Point(116.404, 39.915), 14);
var local = new BMap.LocalSearch("北京市",
{renderOptions: {map: map,autoViewport: true},pageCapacity: 8});
local.search("中关村");
搜索时可用百度地图poi二级分类做检索,遍历poi关键词检索后差不多能把整个城市的数据保存下来
缺点:个人账号有调用次数和频率限制,企业账号价格过高,对仅需要离线数据来说,得不偿失
2. 从地图页面爬取,遍历二级poi分类,先搜索城市,将地图锁定在城市范围内,在输入poi关键字,搜索翻页后保存数据,最后导出到excel或数据库中,就可以根据数据来进行离线地图搜索
实现:此处使用node+puppeteer+node-xlsx,使用自动化测试爬虫的方式获取数据
代码
const puppeteer = require('puppeteer');
const axios = require('axios');
var xlsx = require('node-xlsx');
var fs = require('fs');
// 结果数组, 存储转码后存到excel或者数据库中
let data = []
// excel 一个工作表的一行,即表头行, 真实数据在data数组中push即可
let edata = [
{
name: 'sheet1',
data: [
[
'名称',
'地址',
'经纬度未转码',
'电话',
'经度',
'维度',
'uid',
]
]
}
]
async function run () {
// 启动浏览器
const browser = await puppeteer.launch({
headless: false, // 不配置则默认为true 启动无头浏览器, false则显式启动浏览器
// executablePath: "C:\Users\90798\AppData\Local\Google\Chrome\Application\chrome.exe"
args: ['--start-maximized'], // 启动时浏览器最大化显示
defaultViewport: null,
});
const page = await browser.newPage(); // 打开新页面
page.setViewport({ width:0, height:0});
await page.goto('https://map.baidu.com/', { timeout: 8000 }); // 跳转站点
// await page.waitForTimeout(3000);
let loginDia = await page.waitForSelector('#passport-login-pop') // 登录对话框
console.log('--------> loginDia', loginDia)
// Query for an element handle.
// const element = await page.waitForSelector('div > .class-name'); // 查询页面元素
const element = await page.waitForSelector('input#sole-input'); // 查询页面元素
console.log('____element', element)
// await page.click('#TANGRAM__PSP_39__closeBtn') // 登录对话框 关闭按钮
let loginDiaCloseIcon = await page.waitForSelector('#TANGRAM__PSP_39__closeBtn')
await loginDiaCloseIcon.click(); // Just an example.
await page.type('input#sole-input', '白沙黎族自治县')
await page.click('#search-button')
// await page.type(element, '白沙黎族自治县')
// let btn = await page.waitForSelector('#search-button'); // 查询页面元素
// Do something with element...
// await btn.click(); // Just an example.
await page.on('response', async response => {
console.log('response.url', response.url())
try {
// console.log('response.json', await response.json())
let resData = await response.json()
if(resData.content && Array.isArray(resData.content) && resData.place_info){
resData.content.map(it => {
data.push([ it.name, it.addr, it.geo.substring(it.geo.lastIndexOf('|')+1).replaceAll(';', ''), (it.tel || ''), it.uid ])
})
}
} catch (error) {
console.log('----------> error', error)
}
if (response.url() == "https://capuk.org/ajax_search/capmoneycourses"){
console.log('XHR response received');
console.log(response.json());
}
const divHandle = await page.evaluateHandle(() => {
let overflowDiv = document.querySelector('.poi-wrapper');
overflowDiv && (overflowDiv.scrollTop = 999)
return overflowDiv;
});
});
// await page.waitForTimeout(3000);
await new Promise((res, rej) => { setTimeout(() => { res() }, 3000)})
//清空输入框的值
await page.$eval('input#sole-input',input => input.value='' );
await page.type('input#sole-input', '酒店', {delay: 100})
await page.click('#search-button')
// await page.waitForTimeout(3000);
const poll = async () => {
// let down = await page.$('.close-btn-download-banner')
// try {
// down && down.click()
// } catch (error) {
// console.log('----------> down.click error', error)
// }
// await page.waitForSelector('.leadDownloadCard', {hidden: true});
// page.waitFor(() => !document.querySelector('#leadDownloadCard'));
// page.$('.close-btn-download-banner').then(data => {
// if(data){
// data.click()
// }
// })
await page.$eval('body', () => {
$('.close-btn-download-banner').click()
})
setTimeout(async () => {
let nextPageBtn = await page.waitForSelector('[tid=toNextPage]')
let hasNoNext = await page.$('.next.next-none')
if(nextPageBtn && !hasNoNext){
await nextPageBtn.click()
poll()
}else{
console.log('分页查询完成 data', data)
turn()
}
}, 3000)
}
poll()
};
// 保存到excel中
function turn(){
}
示例: