A high-performance FastAPI service for scraping Google Maps data with parallel processing and comprehensive data extraction. Ideal for n8n users and automation workflows.
- β‘ 3x faster with parallel processing (3 workers)
- π Two extraction modes: Quick list or complete details
- π Full contact info: Phone, website, address, opening hours
- π‘οΈ Anti-detection: Random delays, realistic user-agent, WebDriver masking
- π³ Docker optimized: shm_size, single-process mode for stability
- π Multi-language support: en, fr, es, de, and more
- π n8n compatible: Ready-to-use with automation workflows
- Docker & Docker Compose
- 2 GB RAM minimum
- Port 8001 available
# Clone the repository
git clone https://github.com/conor-is-my-name/google-maps-scraper.git
cd google-maps-scraper
# Start with Docker
docker compose up -d
# Test the API
curl "http://localhost:8001/health"Expected response:
{
"status": "healthy",
"service": "google-maps-scraper"
}- GET
/scrape-get- Main endpoint for scraping (recommended for n8n) - POST
/scrape- Alternative POST endpoint with JSON body - GET
/health- Health check endpoint - GET
/- Service information
| Parameter | Type | Default | Required | Description |
|---|---|---|---|---|
query |
string | - | β | Search query (e.g., "hotels in 98392") |
max_places |
int | 10 | β | Maximum results (1-100) |
lang |
string | "en" | β | Language code (en, fr, es, de, etc.) |
headless |
bool | true | β | Run browser in headless mode |
details |
bool | false | β | Extract full details (phone, website, etc.) |
Fast extraction of basic information - ~2 seconds per place
Returns:
- β Name
- β URL
- β Rating
- β Review count
- β Category
curl "http://localhost:8001/scrape-get?query=restaurant%20paris&max_places=20&details=false"Use cases: Rankings, comparisons, quick lists
Complete extraction including contact information - ~2-3 seconds per place
Returns:
- β Name, URL, Rating, Review count, Category
- β Phone number
- β Website
- β Full address
- β Opening hours
curl "http://localhost:8001/scrape-get?query=restaurant%20paris&max_places=10&details=true"Use cases: Directory creation, CRM import, contact lists
| Places | Quick Mode | Full Details | Sequential (old) |
|---|---|---|---|
| 5 | ~10s | ~15s | ~45s |
| 10 | ~20s | ~30s | ~90s |
| 20 | ~40s | ~60s | ~180s |
Speedup: 2-3x faster than sequential scraping thanks to 3 parallel workers.
# Get 20 restaurants with ratings
curl "http://localhost:8001/scrape-get?query=restaurant%20paris&max_places=20&details=false&lang=en"Response:
{
"success": true,
"query": "restaurant paris",
"total_results": 20,
"results": [
{
"name": "Le Meurice",
"url": "https://www.google.com/maps/place/Le+Meurice/...",
"rating": "4.8",
"reviews_count": "1234",
"category": "French restaurant"
}
]
}# Get 10 restaurants with contact details
curl "http://localhost:8001/scrape-get?query=restaurant%20paris&max_places=10&details=true&lang=fr"Response:
{
"success": true,
"query": "restaurant paris",
"total_results": 10,
"results": [
{
"name": "Le Meurice",
"url": "https://www.google.com/maps/place/Le+Meurice/...",
"rating": "4.8",
"reviews_count": "1234",
"category": "French restaurant",
"phone": "+33 1 44 58 10 10",
"website": "https://www.dorchestercollection.com/paris/le-meurice",
"address": "228 Rue de Rivoli, 75001 Paris",
"hours": "Open Β· Closes 10:30 pm"
}
]
}Method: GET
URL: http://gmaps_scraper_api_service:8001/scrape-get
Query Parameters:
- query: {{ $json.search_query }}
- max_places: 20
- details: true
- lang: en
- headless: true
- Trigger β Schedule or Webhook
- HTTP Request β Google Maps Scraper
- Code β Parse and filter results
- Database β Store in PostgreSQL/MySQL
- Notification β Send to Slack/Email
Designed for: n8n-autoscaling
# Start service
docker compose up -d
# View logs
docker compose logs -f
# Stop service
docker compose down
# Rebuild after changes
docker compose down
docker compose build --no-cache
docker compose up -d
# Quick restart
docker compose restartdocker-compose.yml includes optimizations for stability:
services:
gmaps_scraper_api_service:
shm_size: '2gb' # Prevents "Page crashed" errors
environment:
- DISPLAY=:99 # Xvfb display
- PYTHONUNBUFFERED=1
volumes:
- /dev/shm:/dev/shm # Shared memory for Chromium
deploy:
resources:
limits:
cpus: '2'
memory: 2GTo adjust parallel processing (default: 3 workers):
Edit gmaps_scraper_server/scraper.py line ~217:
max_workers=3 # Increase to 5 max (higher = risk of detection)The scraper includes multiple protections:
- β Realistic User-Agent (Chrome 120)
- β
WebDriver masking (
navigator.webdriver = undefined) - β Random delays between actions (1-3 seconds)
- β
Chromium stealth arguments (
--disable-blink-features=AutomationControlled) - β Limited concurrency (3 workers max for normal behavior)
Recommended limits:
- Max 500 places/day per IP
- Min 60 seconds between requests
- Max 3-5 parallel workers
# Install dependencies
pip install -r requirements.txt
# Install Playwright browsers
playwright install chromium
# Run the API
uvicorn gmaps_scraper_server.main_api:app --reload --host 0.0.0.0 --port 8001The API will be available at http://localhost:8001
docker compose up --buildgoogle-maps-scraper/
βββ docker-compose.yml # Docker configuration
βββ Dockerfile # Docker image build
βββ requirements.txt # Python dependencies
βββ start.sh # Container startup script
βββ gmaps_scraper_server/
β βββ __init__.py
β βββ main_api.py # FastAPI endpoints
β βββ scraper.py # Scraping logic (parallel)
βββ debug_screenshots/ # Debug screenshots
Cause: Insufficient shared memory
Solution:
# In docker-compose.yml
shm_size: '2gb' # Increase to 4gb if neededPossible causes:
- Google structure changed β Update CSS selectors
- CAPTCHA detected β Reduce workers, wait 24h
- Invalid query β Check URL encoding
docker compose logs -fβ οΈ Rate limiting: Respect Google's terms. Max 500 places/day recommended.β οΈ Legal compliance: Check local laws regarding web scraping.β οΈ Responsible use: This tool is for educational and legitimate business purposes.β οΈ No guarantees: Google may change their structure at any time.
- β¨ Added parallel processing (3 workers) - 3x faster
- β¨ Added full details mode (phone, website, address, hours)
- β¨ Added random delays for anti-detection
- π§ Fixed "Page crashed" with
--single-process - π§ Improved data extraction reliability
- π Complete documentation and examples
- π Initial release with basic scraping
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
MIT License - Free to use, modify, and distribute.
Original project structure by @conor-is-my-name
Enhancements:
- Parallel processing implementation
- Full details extraction mode
- Anti-detection improvements
- Docker optimizations
- Comprehensive documentation
- π Issues: GitHub Issues
- π¬ Discussions: GitHub Discussions
Built with β€οΈ using FastAPI and Playwright