🏠 Home 

Greasy Fork is available in English.

Google Maps Reviews Scraper & Exporter

Scrapes reviews from Google Maps with a floating interface and improved functionality


安装此脚本?
 // ==UserScript==
// @name         Google Maps Reviews Scraper & Exporter
// @namespace    http://tampermonkey.net/
// @version      0.13
// @description  Scrapes reviews from Google Maps with a floating interface and improved functionality
// @author       sharmanhall
// @match        https://www.google.com/maps/place/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=google.com
// @grant        GM_addStyle
// @license      MIT
// ==/UserScript==
(function() {
'use strict';
// Add styles for floating panel
GM_addStyle(`
#review-scraper-panel {
position: fixed;
bottom: 20px;
right: 20px;
background-color: #fff;
border: 1px solid #ccc;
border-radius: 8px;
padding: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
z-index: 1000;
font-family: Arial, sans-serif;
}
#review-scraper-panel button {
background-color: #4285f4;
color: white;
border: none;
padding: 8px 12px;
margin: 5px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
#review-scraper-panel button:hover {
background-color: #3367d6;
}
#scraper-status {
margin-top: 10px;
font-size: 14px;
}
`);
// Create floating panel
const panel = document.createElement('div');
panel.id = 'review-scraper-panel';
panel.innerHTML = `
<button id="scrape-reviews">Scrape Reviews</button>
<button id="copy-to-clipboard">Copy to Clipboard</button>
<div id="scraper-status"></div>
`;
document.body.appendChild(panel);
const setStatus = (message) => {
document.getElementById('scraper-status').textContent = message;
};
const autoScroll = async () => {
setStatus('Scrolling to load reviews...');
let lastScrollHeight = 0, currentScrollHeight = document.documentElement.scrollHeight;
do {
lastScrollHeight = currentScrollHeight;
window.scrollTo(0, currentScrollHeight);
await new Promise(r => setTimeout(r, 2000));
currentScrollHeight = document.documentElement.scrollHeight;
} while(currentScrollHeight > lastScrollHeight);
window.scrollTo(0, 0);
};
const expandReviews = async () => {
setStatus('Expanding truncated reviews...');
const moreButtons = document.querySelectorAll("button.w8nwRe.kyuRq");
for (const button of moreButtons) {
button.click();
await new Promise(r => setTimeout(r, 500));
}
};
const scrapeReviews = async () => {
await autoScroll();
await expandReviews();
setStatus('Scraping reviews...');
const reviewDivs = document.querySelectorAll("div[data-review-id]");
const reviews = [];
const scrapedReviewIds = new Set();
for (const reviewDiv of reviewDivs) {
const reviewId = reviewDiv.getAttribute("data-review-id");
if (scrapedReviewIds.has(reviewId)) continue;
const review = {
reviewer_name: reviewDiv.querySelector("div.d4r55")?.textContent.trim() || '',
img_url: reviewDiv.querySelector("img.NBa7we")?.src.replace('=w36-h36-p-rp-mo-br100', '=s0') || '',
review_date: reviewDiv.querySelector("span.rsqaWe")?.textContent.trim() || '',
star_rating: parseInt(reviewDiv.querySelector("span.kvMYJc[role='img']")?.getAttribute("aria-label").match(/(\d+)/)?.[0] || '0', 10),
review_url: reviewDiv.querySelector("button[data-href]")?.getAttribute("data-href") || '',
review_content: reviewDiv.querySelector("span.wiI7pd")?.textContent.trim() || ''
};
scrapedReviewIds.add(reviewId);
reviews.push(review);
}
setStatus(`Scraped ${reviews.length} reviews.`);
return reviews;
};
const copyToClipboard = async () => {
const reviews = await scrapeReviews();
const contentToCopy = JSON.stringify(reviews, null, 2);
navigator.clipboard.writeText(contentToCopy).then(() => {
setStatus('Content copied to clipboard!');
}).catch(err => {
setStatus('Error copying to clipboard. See console for details.');
console.error("Could not copy content to clipboard: ", err);
});
};
document.getElementById('scrape-reviews').addEventListener('click', scrapeReviews);
document.getElementById('copy-to-clipboard').addEventListener('click', copyToClipboard);
})();