Add Scraper for a New Website
You are helping the user add support for scraping property listings from a new website. This is a multi-step process that requires creating a mapping file, capturing a test fixture, and wiring everything up.
Inputs
The user will provide $ARGUMENTS which should be a URL of a sample listing page from the target website, or just the website name. If no URL is provided, ask for one.
Step-by-step workflow
Phase 1: Gather information
- Get a sample URL if the user didn't provide one
- Determine the scraper name — derive from the hostname (e.g.
www.example-realty.com → example_realty). Use lowercase, underscores for separators, keep it short. Ask the user to confirm the name.
- Get the HTML — Ask the user how they want to provide the HTML:
- If the site is static (no JS rendering needed), we can fetch it directly
- If the site is JS-heavy (React/Vue/Angular SPA), the user should save the page from their browser ("Save As" → "Web Page, HTML Only") and provide the file path
- They can also pipe it:
curl ... | npm run capture-fixture -- --stdin --url <url>
Phase 2: Analyze the HTML and create the mapping
Capture the fixture using the capture-fixture utility:
cd astro-app
# For URL fetch:
npm run capture-fixture -- <url> --name <scraper_name>
# For local file:
npm run capture-fixture -- --file <path> --url <url> --name <scraper_name> --no-extract
Analyze the saved HTML fixture at astro-app/test/fixtures/<name>.html. Look for:
- Title: Usually in
<h1>, <title>, or og:title meta tag
- Price: Look for price elements, currency symbols,
itemprop="price" microdata
- Address/Location: Address strings, postal codes,
og: meta tags, or structured data
- Coordinates: Often in
<script> tags as JSON (lat/lng), or in meta tags
- Bedrooms/Bathrooms: Usually near icons or labels like "bed", "bath", "BR"
- Images:
<img> tags in gallery sections, or og:image meta tags
- Reference/ID: Property ID in URL path, hidden inputs, or
data- attributes
- For sale/rent: Status indicators, URL patterns (
/to-rent/, /for-sale/)
- Description:
meta[name=description] or content sections
- Area/Size: Square footage/meters, usually near bed/bath counts
Create the mapping JSON at config/scraper_mappings/<name>.json. Follow the format described in the reference file at .claude/skills/add-scraper/reference.md.
Key rules:
- Each field must appear in exactly ONE section. If the same field appears in multiple sections, the last one processed wins (processing order: defaultValues → images → features → intFields → floatFields → textFields → booleanFields)
- Always add
cssCountId: "0" when a CSS selector might match multiple elements
- Use
cssAttr to read attribute values (e.g. content from meta tags)
- Use
scriptRegEx for data embedded in <script> tags
- Use
urlPathPart to extract segments from the URL path
- Prefer class-based or ID-based selectors over
nth-child chains
Phase 3: Validate and register
Run the capture-fixture utility again with extraction enabled to preview results:
cd astro-app
npm run capture-fixture -- --file test/fixtures/<name>.html --url <source_url> --name <name> --force
Review the extraction preview. If fields are wrong:
- Check selectors against the actual HTML
- Fix the mapping JSON
- Re-run capture-fixture to verify
Add to the hostname map — Add entries for the new hostname to:
astro-app/scripts/capture-fixture.ts in the HOSTNAME_MAP constant
astro-app/src/lib/services/url-validator.ts in the LOCAL_HOST_MAP constant
Add to the test manifest — Copy the manifest stub from capture-fixture output into astro-app/test/fixtures/manifest.ts. Review and adjust expected values — remove fields that are zero/empty and not meaningful, ensure types are correct (integers vs strings vs booleans).
Run the test suite to verify everything passes:
cd astro-app && npx vitest run
Phase 4: Summary
- Present a summary of all files created/modified and offer to commit the changes.
Important notes
- The mapping file format is JSON but parsed with JSON5 (comments are allowed)
- The
name field in the mapping must match the scraper name used everywhere else
defaultValues always produce strings (e.g. "true" not true)
stripPunct removes . and , only — not currency symbols
stripString removes the first occurrence of an exact substring, runs after split
- Cheerio converts
<br> to \n, never \r
parseFloat/parseInt return 0 on failure, not an error
Existing scrapers for reference
These scrapers are already configured: uk_rightmove, uk_zoopla, uk_onthemarket, uk_jitty, es_idealista, es_fotocasa, es_pisos, pt_idealista, ie_daft, us_realtor, us_forsalebyowner, us_mlslistings, us_wyomingmls, in_realestateindia, de_immoscout, au_domain, au_realestate.
See config/scraper_mappings/ for their mapping files and astro-app/test/fixtures/manifest.ts for expected values.
Converted and distributed by TomeVault — claim your Tome and manage your conversions.
1---2name: add-scraper3description: Add support for scraping property listings from a new website. Use when the user wants to add a new scraper, create a new mapping, or support a new property listing site. Use when this capability is needed.4---56# Add Scraper for a New Website78You are helping the user add support for scraping property listings from a new website. This is a multi-step process that requires creating a mapping file, capturing a test fixture, and wiring everything up.910## Inputs1112The user will provide `$ARGUMENTS` which should be a URL of a sample listing page from the target website, or just the website name. If no URL is provided, ask for one.1314## Step-by-step workflow1516### Phase 1: Gather information17181. **Get a sample URL** if the user didn't provide one192. **Determine the scraper name** — derive from the hostname (e.g. `www.example-realty.com` → `example_realty`). Use lowercase, underscores for separators, keep it short. Ask the user to confirm the name.203. **Get the HTML** — Ask the user how they want to provide the HTML:21 - If the site is static (no JS rendering needed), we can fetch it directly22 - If the site is JS-heavy (React/Vue/Angular SPA), the user should save the page from their browser ("Save As" → "Web Page, HTML Only") and provide the file path23 - They can also pipe it: `curl ... | npm run capture-fixture -- --stdin --url <url>`2425### Phase 2: Analyze the HTML and create the mapping26274. **Capture the fixture** using the capture-fixture utility:28 ```bash29 cd astro-app30 # For URL fetch:31 npm run capture-fixture -- <url> --name <scraper_name>32 # For local file:33 npm run capture-fixture -- --file <path> --url <url> --name <scraper_name> --no-extract34 ```35365. **Analyze the saved HTML fixture** at `astro-app/test/fixtures/<name>.html`. Look for:37 - **Title**: Usually in `<h1>`, `<title>`, or `og:title` meta tag38 - **Price**: Look for price elements, currency symbols, `itemprop="price"` microdata39 - **Address/Location**: Address strings, postal codes, `og:` meta tags, or structured data40 - **Coordinates**: Often in `<script>` tags as JSON (lat/lng), or in meta tags41 - **Bedrooms/Bathrooms**: Usually near icons or labels like "bed", "bath", "BR"42 - **Images**: `<img>` tags in gallery sections, or `og:image` meta tags43 - **Reference/ID**: Property ID in URL path, hidden inputs, or `data-` attributes44 - **For sale/rent**: Status indicators, URL patterns (`/to-rent/`, `/for-sale/`)45 - **Description**: `meta[name=description]` or content sections46 - **Area/Size**: Square footage/meters, usually near bed/bath counts47486. **Create the mapping JSON** at `config/scraper_mappings/<name>.json`. Follow the format described in the reference file at `.claude/skills/add-scraper/reference.md`.4950 Key rules:51 - Each field must appear in exactly ONE section. If the same field appears in multiple sections, the last one processed wins (processing order: defaultValues → images → features → intFields → floatFields → textFields → booleanFields)52 - Always add `cssCountId: "0"` when a CSS selector might match multiple elements53 - Use `cssAttr` to read attribute values (e.g. `content` from meta tags)54 - Use `scriptRegEx` for data embedded in `<script>` tags55 - Use `urlPathPart` to extract segments from the URL path56 - Prefer class-based or ID-based selectors over `nth-child` chains5758### Phase 3: Validate and register59607. **Run the capture-fixture utility again** with extraction enabled to preview results:61 ```bash62 cd astro-app63 npm run capture-fixture -- --file test/fixtures/<name>.html --url <source_url> --name <name> --force64 ```65668. **Review the extraction preview**. If fields are wrong:67 - Check selectors against the actual HTML68 - Fix the mapping JSON69 - Re-run capture-fixture to verify70719. **Add to the hostname map** — Add entries for the new hostname to:72 - `astro-app/scripts/capture-fixture.ts` in the `HOSTNAME_MAP` constant73 - `astro-app/src/lib/services/url-validator.ts` in the `LOCAL_HOST_MAP` constant747510. **Add to the test manifest** — Copy the manifest stub from capture-fixture output into `astro-app/test/fixtures/manifest.ts`. Review and adjust expected values — remove fields that are zero/empty and not meaningful, ensure types are correct (integers vs strings vs booleans).767711. **Run the test suite** to verify everything passes:78 ```bash79 cd astro-app && npx vitest run80 ```8182### Phase 4: Summary838412. Present a summary of all files created/modified and offer to commit the changes.8586## Important notes8788- The mapping file format is JSON but parsed with JSON5 (comments are allowed)89- The `name` field in the mapping must match the scraper name used everywhere else90- `defaultValues` always produce strings (e.g. `"true"` not `true`)91- `stripPunct` removes `.` and `,` only — not currency symbols92- `stripString` removes the first occurrence of an exact substring, runs after split93- Cheerio converts `<br>` to `\n`, never `\r`94- `parseFloat`/`parseInt` return `0` on failure, not an error9596## Existing scrapers for reference9798These scrapers are already configured: uk_rightmove, uk_zoopla, uk_onthemarket, uk_jitty, es_idealista, es_fotocasa, es_pisos, pt_idealista, ie_daft, us_realtor, us_forsalebyowner, us_mlslistings, us_wyomingmls, in_realestateindia, de_immoscout, au_domain, au_realestate.99100See `config/scraper_mappings/` for their mapping files and `astro-app/test/fixtures/manifest.ts` for expected values.101102---103> Converted and distributed by [TomeVault](https://tomevault.io/claim/realestatewebtools) — claim your Tome and manage your conversions.104<!-- tomevault:4.0:skill_md:2026-04-11 -->