Search 715,559 business listings by city and category, with phone numbers, websites, addresses and ratings, and export the results to CSV. Free, no signup. Built end to end by Mohamed Abdelhalim, from the scraper to the database to this site.
Each run took one city through five stages on GitHub Actions with no manual steps. Collection stopped on October 15, 2026, so the data is frozen, but the whole pipeline still runs on demand.
Selenium with undetected-chromedriver searches every category in a city, scrolls the results and opens each profile. User agents rotate and the browser restarts every few queries.
Maps URLs collapse to a stable place ID, websites lose tracking parameters, ratings and review counts are parsed, and duplicates are dropped.
Listings without a phone are revisited, and every number is normalized to E.164 using the country of the city that was searched.
Rows are upserted in batches into Postgres on Supabase, keyed on the profile URL, so a re-run refreshes listings instead of duplicating them.
A Flask app on Vercel serves the search tool, a CSV export, and one server-rendered page for every city and category with enough listings.
The whole thing runs on a free Postgres instance. These are the choices that made 715,559 rows searchable without paying for a bigger one.
A statement-level AFTER INSERT trigger keeps lead_combos up to date with one row per city and category. The city list, the category counts, the stats on this page, and the sitemap all read from it instead of counting hundreds of thousands of rows.
Searches match an exact city from a dropdown, never a fuzzy text match, so (category, query_location, rating desc) turns any page of results into a single index range scan.
Upserting on the profile URL means a failed run can simply be repeated, and re-scraping a city updates it in place. The rotation position lives in a database table, so runs never commit to the repo.
Row level security is on for every table. The public role can read listings and the aggregate tables and nothing else, and exports are sanitized against spreadsheet formula injection.
Normalized to international format, with call and WhatsApp links in the tool.
The business site when the listing has one, with tracking parameters removed.
The street address and a direct link to the Google Maps profile.
Star rating, plus review count for listings collected or refreshed since October 2026.
60 categories across 336 cities, countries and US states.
The top 100 rows of any search, with duplicate removal and column picking.
No signup. Pick a city, pick a category, export the list.