// ==UserScript==
// @name google map scraper
// @namespace http://google.com/
// @version 2025-05-22
// @description google map result
// @author Web Automation Lover
// @match https://www.google.com/maps/search/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=xiaohongshu.com
// @require https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.16.9/xlsx.full.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js
// @grant none
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
window.jsonArr = [];
const button = document.createElement('button');
button.innerText = 'Click to Export (0)';
button.style.marginLeft = '10px';
button.style.backgroundColor = '#f0f0f0';
button.style.border = '1px solid #ccc';
button.style.borderRadius = '5px';
button.style.padding = '5px 10px';
button.style.fontSize = '14px';
button.style.cursor = 'pointer';
button.style.transition = 'background-color 0.3s';
button.addEventListener('mouseenter', () => {
button.style.backgroundColor = '#e0e0e0';
});
button.addEventListener('mouseleave', () => {
button.style.backgroundColor = '#f0f0f0';
});
button.addEventListener('click', function() {
const ws = XLSX.utils.json_to_sheet(window.jsonArr);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');
const wbout = XLSX.write(wb, { type: 'binary', bookType: 'xlsx' });
const s2ab = function(s) {
const buf = new ArrayBuffer(s.length);
const view = new Uint8Array(buf);
for (let i = 0; i < s.length; i++) view[i] = s.charCodeAt(i) & 0xFF;
return buf;
};
const blob = new Blob([s2ab(wbout)], { type: 'application/octet-stream' });
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'data.xlsx';
a.click();
});
function updateButtonText() {
button.innerText = 'Click to Export (' + window.jsonArr.length + ')';
}
const injectButton = () => {
const targetDiv = document.querySelectorAll('#assistive-chips > div > div > div > div > div > div > div > div > div')[1];
if (targetDiv && !document.querySelector('#my-custom-button')) {
button.id = 'my-custom-button';
targetDiv.appendChild(button);
}
};
setInterval(injectButton, 1000);
const originalOpen = XMLHttpRequest.prototype.open;
const originalSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function(method, url) {
this._url = url;
return originalOpen.apply(this, arguments);
};
XMLHttpRequest.prototype.send = function() {
this.addEventListener('load', function() {
if (this._url.includes('/search?tbm=map')) {
var rspJson = JSON.parse(this.responseText.replace(`/*""*/`,""));
var e = rspJson.d;
var cleanedData = e.replace(`)]}'`, "");
let parsedData = JSON.parse(cleanedData);
let dataList = parsedData[0][1];
let filteredData = dataList.filter(item => {
return item?.[14] !== undefined;
});
if (!filteredData || filteredData.length < 1) {
filteredData = parsedData[64];
}
if (filteredData) {
var formatedData = formatAllData(filteredData)
window.jsonArr.push(...formatedData)
console.log('song jsonArr:' + window.jsonArr.length)
updateButtonText()
}
}
});
return originalSend.apply(this, arguments);
};
function formatAllData(allDataList) {
return allDataList.map(d => formatDataItem(d)).filter(d => d.name)
}
function formatDataItem(item) {
const fieldConfig = {
fullAddress: [39],
placeId: [78],
kgmid: [89],
categories: [13],
feature: [32, 0, 1],
cid: [10],
featuredImage: [37, 0, 0, 6, 0],
phones: [],
icon: [122, 0, 1],
name: [11],
latitude: [9, 2],
longitude: [9, 3],
reviewCount: [4, 8],
reviewURL: [4, 3, 0],
averageRating: [4, 7],
street: [183, 0, 0, 1, 1],
municipality: [183, 1, 3],
openingHours: [],
website: [7, 0],
domain: [7, 1]
}
const resultData = {}
Object.keys(fieldConfig).forEach(key => {
resultData[key] = handleSingleField(fieldConfig[key])
})
resultData.phones = handleSingleField([178, 0, 1])?.map(d => d?.[0])
resultData.openingHours = handleSingleField([34, 1])?.map(d => [`${d[0]}:[${d[1]}]`])?.join(', ')
resultData.googleMapsURL = "https://www.google.com/maps?cid=".concat(resultData.cid)
resultData.googleKnowledgeURL = "https://www.google.com/search?kgmid=".concat(resultData.kgmid, "&kponly")
resultData.phones = resultData.phones?.join?.(', ')
resultData.categories = resultData.categories?.join?.(', ')
resultData.street = resultData.street?.join?.(', ')
function handleSingleField(config) {
const itemData = item[1]
if (!itemData) {
return
}
if (!config || !config.length) {
return
}
let currentData = itemData
for (let i = 0; i < config.length; i++) {
currentData = currentData?.[config[i]]
}
return currentData
}
return resultData
}
})();