Initial travel knowledge graph release
This commit is contained in:
144
scripts/amap_js_api_probe.mjs
Normal file
144
scripts/amap_js_api_probe.mjs
Normal file
@@ -0,0 +1,144 @@
|
||||
import http from "node:http";
|
||||
import { spawn } from "node:child_process";
|
||||
import { readFileSync } from "node:fs";
|
||||
|
||||
function readEnvKey(path, key) {
|
||||
const txt = readFileSync(path, "utf8");
|
||||
for (const line of txt.split(/\r?\n/)) {
|
||||
if (line.trim().startsWith(`${key}=`)) return line.split("=").slice(1).join("=").trim();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function httpJson(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.get(url, (res) => {
|
||||
let data = "";
|
||||
res.on("data", (chunk) => (data += chunk));
|
||||
res.on("end", () => {
|
||||
try {
|
||||
resolve(JSON.parse(data));
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
}).on("error", reject);
|
||||
});
|
||||
}
|
||||
|
||||
class Cdp {
|
||||
constructor(wsUrl) {
|
||||
this.ws = new WebSocket(wsUrl);
|
||||
this.seq = 1;
|
||||
this.pending = new Map();
|
||||
this.ws.onmessage = (event) => {
|
||||
const msg = JSON.parse(event.data);
|
||||
if (msg.id && this.pending.has(msg.id)) {
|
||||
const { resolve, reject } = this.pending.get(msg.id);
|
||||
this.pending.delete(msg.id);
|
||||
if (msg.error) reject(new Error(JSON.stringify(msg.error)));
|
||||
else resolve(msg.result);
|
||||
}
|
||||
};
|
||||
}
|
||||
async open() {
|
||||
await new Promise((resolve, reject) => {
|
||||
this.ws.onopen = resolve;
|
||||
this.ws.onerror = reject;
|
||||
});
|
||||
}
|
||||
call(method, params = {}) {
|
||||
const id = this.seq++;
|
||||
this.ws.send(JSON.stringify({ id, method, params }));
|
||||
return new Promise((resolve, reject) => this.pending.set(id, { resolve, reject }));
|
||||
}
|
||||
close() {
|
||||
this.ws.close();
|
||||
}
|
||||
}
|
||||
|
||||
async function wait(ms) {
|
||||
await new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const key = readEnvKey("/Users/xuexue/new2/.env", "AMAP_JS_KEY");
|
||||
const security = readEnvKey("/Users/xuexue/new2/.env", "AMAP_SECURITY_JSCODE");
|
||||
if (!key || !security) throw new Error("missing AMap JS key/security");
|
||||
|
||||
const chrome = spawn(
|
||||
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
||||
[
|
||||
"--headless=new",
|
||||
"--disable-gpu",
|
||||
"--no-first-run",
|
||||
"--no-default-browser-check",
|
||||
"--remote-debugging-port=9229",
|
||||
"--user-data-dir=/tmp/znkg-amap-cdp-profile",
|
||||
"http://localhost:8102/admin/plaza/graph",
|
||||
],
|
||||
{ stdio: "ignore" },
|
||||
);
|
||||
try {
|
||||
let pages = null;
|
||||
for (let i = 0; i < 30; i += 1) {
|
||||
try {
|
||||
pages = await httpJson("http://127.0.0.1:9229/json");
|
||||
if (pages?.[0]?.webSocketDebuggerUrl) break;
|
||||
} catch {}
|
||||
await wait(300);
|
||||
}
|
||||
if (!pages?.[0]?.webSocketDebuggerUrl) throw new Error("Chrome CDP not ready");
|
||||
const cdp = new Cdp(pages[0].webSocketDebuggerUrl);
|
||||
await cdp.open();
|
||||
await cdp.call("Runtime.enable");
|
||||
await wait(800);
|
||||
const expr = `
|
||||
(async () => {
|
||||
window._AMapSecurityConfig = { securityJsCode: ${JSON.stringify(security)} };
|
||||
await new Promise((resolve, reject) => {
|
||||
if (window.AMap) return resolve();
|
||||
const s = document.createElement('script');
|
||||
s.src = 'https://webapi.amap.com/maps?v=2.0&key=${encodeURIComponent(key)}&plugin=AMap.PlaceSearch,AMap.Driving';
|
||||
s.onload = resolve;
|
||||
s.onerror = () => reject(new Error('amap script load failed'));
|
||||
document.head.appendChild(s);
|
||||
});
|
||||
const place = await new Promise((resolve, reject) => {
|
||||
const ps = new AMap.PlaceSearch({ city: '安顺市', pageSize: 3, extensions: 'all' });
|
||||
ps.search('黄果树风景名胜区', (status, result) => {
|
||||
if (status === 'complete') resolve(result.poiList?.pois || []);
|
||||
else reject(new Error(status + ':' + JSON.stringify(result)));
|
||||
});
|
||||
});
|
||||
const first = place[0] || {};
|
||||
const driving = await new Promise((resolve, reject) => {
|
||||
const d = new AMap.Driving();
|
||||
d.search([106.630153,26.647661], [first.location.lng, first.location.lat], (status, result) => {
|
||||
if (status === 'complete') resolve(result.routes?.[0] || {});
|
||||
else reject(new Error(status + ':' + JSON.stringify(result)));
|
||||
});
|
||||
});
|
||||
return {
|
||||
placeCount: place.length,
|
||||
firstName: first.name,
|
||||
firstId: first.id,
|
||||
firstLocation: first.location ? [first.location.lng, first.location.lat].join(',') : '',
|
||||
firstPhotos: (first.photos || []).length,
|
||||
distance: driving.distance,
|
||||
time: driving.time,
|
||||
};
|
||||
})()
|
||||
`;
|
||||
const out = await cdp.call("Runtime.evaluate", { expression: expr, awaitPromise: true, returnByValue: true });
|
||||
console.log(JSON.stringify(out, null, 2));
|
||||
cdp.close();
|
||||
} finally {
|
||||
chrome.kill();
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user