Overview
The Local Business Profile Scraper is a business profile scraper: a standalone desktop bot that types a category search into a map platform, scrolls the results pane to the end, then visits every listing’s own profile page and extracts eleven detail fields into the Business_Details dataset. Where a results-card scraper stops at names and ratings, this bot goes one level deeper - phone numbers, websites, menus, amenities, price ranges and plus codes all live on the individual profile pages, and that is exactly where the run goes to get them.
What does the Local Business Profile Scraper do?
The run happens in two phases. Phase one works on the search results page: the bot fills the map search box with the term you provide, presses Enter, waits for result cards to render, and scrolls the results pane until it stops growing. It then extracts every listing’s profile URL into the Map_Search_URLs dataset. Phase two iterates over those URLs one by one: for each profile page it waits for the heading to render, then extracts the eleven Business_Details fields - including a parsed amenities list and the numeric rating and review count - and appends the row.
Because everything runs on your own machine, your research footprint stays yours: which categories you are mapping, which cities you are prospecting, which competitors you are benchmarking never passes through a third-party service’s dashboard or logs.
One honesty note, in the same spirit as its sibling listing: the selectors shipped in this configuration target the current public markup of a major map platform and are illustrative examples for the reader’s own permitted target. They are not an affiliation, not an endorsement, and not a guarantee - when a platform redesigns its profile pages, a run ends with empty fields rather than invented ones.
Who uses a business profile scraper?
The local lead-generation freelancer asks “which plumbers in this city publish a phone number but have no website?” and needs phone and website columns side by side to spot exactly that gap. The market researcher asks “what is the density and rating distribution of coffee shops across these three districts?” and needs category, rating and review count per profile. The franchise development team asks “which territories have weak amenity coverage?” and needs the parsed amenities list. The local-SEO consultant asks “what does the profile data of the top-ranked businesses actually contain?” and needs a dated, defensible artifact - a dataset they produced themselves - rather than a screenshot.
How does a local business data extractor run work, step by step?
Every command in the run links to its reference page. First, fill types your prompted search_term variable - ${search_term}, default “coffee shops” - into the map search box, clearing any existing text first, and its then chain fires a press of the Enter key to submit the search. Second, wait_for_selector blocks until the first result card renders, so extraction never races the page. Third, infinite_scroll drives the results pane with a 1500 ms delay per step and an unbounded scroll count - it stops on its own when the pane height stops changing. Fourth, extract_data pulls every profile link into Map_Search_URLs. Finally a for_each loop iterates that dataset: for each item, goto navigates to ${item.PlaceURL}, a second wait_for_selector confirms the profile heading loaded, and a second extract_data appends the eleven-field record to Business_Details.
What does the output look like?
The table mirrors the published sample row exactly:
| Title | Category | Amenities | Phone | Website | Menu | Price_Range | Rating | Reviews_Count | Address | Plus_Code |
|---|---|---|---|---|---|---|---|---|---|---|
| Blue Door Coffee House | Coffee shop | Wi-Fi, outdoor seating, wheelchair accessible | +1 555 010 2030 | https://bluedoorcoffee.example.com | https://bluedoorcoffee.example.com/menu | $$ | 4.5 | 1284 | 482 Example Ave, Springfield | 8FVC2G3M+4X |
Title is the business name from the profile heading. The run waits for this heading before extracting, so an empty Title is a strong signal the page never rendered properly.
Category is the platform’s own classification. Filter on it after the run - map searches routinely mix in adjacent categories.
Amenities is parsed out of the profile’s about section into one label per line and joined; it captures feature labels like Wi-Fi or wheelchair access, never review content.
Phone and Website are the public contact fields, cleaned of their accessibility-label prefixes by replace transformations. Both are legitimately empty on many profiles - that absence is itself useful lead-generation signal.
Menu is the menu link where the business publishes one. Mostly relevant for food and drink categories; expect empty elsewhere.
Price_Range is the first bucket of the displayed price histogram, kept verbatim.
Rating and Reviews_Count are the aggregate signals, extracted by regex from the star label and review label - numbers only, review text is never collected.
Address is the published street address, prefix-cleaned. Combine it with Title when merging runs, since this release has no deduplication key.
Plus_Code is the open-location code for the entrance, useful for territories where street addressing is unreliable.
Can a maps detail page scraper build a lead list?
Yes - with one boundary stated plainly. A maps detail page scraper gives you the raw prospect row: who, where, what category, how well rated, and the two contact channels the business chose to publish (phone and website). What this release does not do is enrich: it extracts no email addresses, resolves no social profiles, and validates nothing against third-party databases. The output is a clean starting list, not a finished campaign file, and any outreach from it is your decision and your compliance burden.
How is this different from a business directory scraper?
A business directory scraper works against paginated HTML directories with numbered pages and stable cards. Map results are different animals: they render continuously inside a scrolling pane, the interesting data hides on individual profile pages rather than in the cards, and key fields are wrapped in accessibility labels that need transformation to clean. This bot is built for that shape - unbounded scroll detection, a URL-collection phase, and a per-profile visit loop - which is why it collects fields a card-level scraper never sees.
How does it compare to hosted collection and manual research?
Copy-pasting profiles by hand produces a handful of rows an hour and no consistency at all. Hosted collection services and metered platforms will do the visiting for you, but the structure is the opposite of this bot: they charge per request or per month, the data lands in their cloud under their retention terms, and your search history - your prospects, your territories - lives on their servers. Here the marginal cost of a bigger search is your own time and bandwidth, the datasets stay on your disk, and the workflow configuration is yours to keep, modify and re-run. The trade is real: no dashboards, no built-in scheduling, no history. You get an artifact and a workflow you own outright.
How do you set it up on Windows, macOS and Linux?
Download the launcher for your operating system from this page. On Windows, run the .exe; SmartScreen may ask for confirmation on first launch - verify the published checksum, then “More info” and “Run anyway” proceeds. On macOS, Gatekeeper may quarantine the download; right-click and choose Open, or clear the flag with xattr -d com.apple.quarantine /path/to/LocalBusinessProfileScraper and launch normally. On Linux, the launcher is a shell script: chmod +x ./local-business-profile-scraper then ./local-business-profile-scraper. At first run it prompts for a single field - the search term, such as “dentists in Austin” - and starts the two-phase run. To repeat a search weekly, schedule the launcher with your OS scheduler (Task Scheduler, cron, or launchd) and pass the same term.
What do I check when a run returns zero rows or missing fields?
Work in order. Zero rows from Map_Search_URLs: did the search actually return results in an ordinary browser, or did a consent wall, region lock or challenge greet the fresh session? Did the scroll phase end immediately because the results-pane container no longer matches a redesigned page? Every profile row present but fields empty: the profile-page markup most likely changed - check one profile URL from Map_Search_URLs by hand and see whether the page still shows the fields. A few scattered empty phones or websites: completely normal, not a failure. Fewer results than the map shows interactively: the scroll detection stopped when the pane stopped growing; re-run once before concluding anything. The contract is that failure is loud - empty values and zero rows, never fabricated data.
What are the bot’s limits?
It collects only what a logged-out visitor sees on search cards and profile pages. No review text, no owner responses, no photos, no opening hours in this release. It has no email extraction and no enrichment step. It ships without proxy rotation or CAPTCHA solving enabled - if a challenge stops the run, the run stops; nothing bypasses it. One run covers one search term, unbounded: there is no visit cap, so scope control means narrowing your query. It is a snapshotter, not a monitor - nothing re-runs or alerts on its own. And Business_Details carries no deduplication key, so merging runs is your step, on Title plus Address.
What is responsible lead generation data collection?
A sole trader’s name, phone number and address are personal data in most jurisdictions, so establish your lawful basis under GDPR, UK GDPR or your local equivalent before any outreach to collected contacts; honour opt-outs immediately and permanently; and never use the output for spam. Review the map platform’s terms with open eyes - automated collection may conflict with them, and the decision to run is yours to own. Keep the collection boundary where this bot sets it: aggregate ratings and counts, published contact channels, never review text. Keep request volume at what a patient human could sustain, and let the acceptable-use policy govern every run.