What the Andie Swim scraper collects
Reads Andie Swim collection listings, keyword lookups and single products from the store's own JSON endpoints, with prices, was-prices, discounts and which sizes are actually in stock. One row per product (or per variant in product mode), written to JSON and CSV with a run-metadata sidecar.
Collection listing
Input: A collection URL (/collections/{handle})One row per product: price, was-price, discount, product type, tags, and how many variants exist versus how many are available.
Keyword search
Input: A search queryOne row per matching product from the store's keyword lookup, with the same product columns as a listing.
Single product (per variant)
Input: A product URL (/products/{handle})One row per size/colour variant with its own SKU, price and in-stock flag — the only mode that tells you which sizes are buyable.
Another market
Input: A market-prefixed URL plus --localeThe same listing read in a different market, with that market's own prices and currency recorded on every row.
From zero to Andie Swim data in 3 steps
Install
Clone the repository and install one browser engine. Python 3.9+.
$ git clone https://github.com/2scraper/andieswim-scraper.git && cd andieswim-scraper $ python3 -m venv .venv && . .venv/bin/activate $ pip install -r requirements.txt -r requirements-playwright.txt $ python3 -m playwright install chromium
Run a scraper
Pick what you need and run it. Every flag is documented in the README.
$ python3 playwright_scraper.py --url "https://andieswim.com/collections/one-pieces" --pages 3$ python3 playwright_scraper.py --mode search --query "bikini top"$ python3 playwright_scraper.py --mode product --url "https://andieswim.com/products/the-amalfi-flat-black-classic"$ python3 playwright_scraper.py --locale en-gb --url "https://andieswim.com/en-gb/collections/one-pieces"Get structured data
Rows land in JSON or CSV (
--format), with a.meta.jsonsidecar recording status, pages fetched and why the run stopped.
Andie Swim data fields
34 columns per row in a predictable schema. The most useful ones:
| Field | What it holds |
|---|---|
sku | Shopify product id on a listing row; the variant's own SKU string in product mode |
title | Product title as the store writes it |
price | Current price as a number |
currency | ISO currency of the market the row came from |
original_price | Was-price when the product is discounted |
discount_pct | Discount computed from price and was-price |
in_stock | Availability; null means not stated, never out of stock |
variants_total | Number of size/colour variants |
variants_available | How many of those variants are in stock |
base_sku | The style code shared by a product's variants |
product_type | Store product type, e.g. One Piece |
handle | The product's URL handle |
tags | The store's own product tags (fabric, coverage, colour family…) |
locale | Market the row was read from, e.g. en-us |
size | Variant size (product mode) |
color | Variant colour (product mode) |
[
{
"source": "andieswim.com",
"scraped_at": "2026-09-18T14:27:25.416031+00:00",
"url": "https://andieswim.com/products/the-tulum-one-piece-botanical-pine-classic",
"sku": "7022167785544",
"title": "The Tulum One Piece - Botanical - Pine - Classic",
"brand": "Andie",
"price": 142.0,
"currency": "USD",
"in_stock": true,
"image_url": "https://cdn.shopify.com/s/files/1/0024/2289/8758/files/AO805-PINE_2630_v2.webp?v=178369…",
"category": "One Piece",
"price_source": "products_json",
"page": 1,
"position": 1,
"mode": "listing",
"locale": "en-us",
"product_id": "7022167785544",
"handle": "the-tulum-one-piece-botanical-pine-classic",
"base_sku": "AO805",
"product_type": "One Piece",
"original_price": null,
"discount_pct": null,
"price_max": null,
"price_varies": false,
"variants_total": 5,
"variants_available": 5,
"tags": "andie::master => the-tulum-one-piece | AS PF 2026 | badge:new | bust-support:medium bus…",
"published_at": "2026-07-14T07:48:52-04:00",
"collection": "one-pieces",
"sort": "collection-default",
"variant_id": null,
"variant_title": null,
"color": null,
"size": null
},
{
"source": "andieswim.com",
"scraped_at": "2026-09-18T14:27:25.416151+00:00",
"url": "https://andieswim.com/products/the-amalfi-flat-black-classic",
"sku": "4251267858502",
"title": "The Amalfi One Piece - Eco Nylon - Black - Classic",
"brand": "Andie",
"price": 112.0,
"currency": "USD",
"in_stock": true,
"image_url": "https://cdn.shopify.com/s/files/1/0024/2289/8758/files/AO292-BLK_1.jpg?v=1777297032",
"category": "One Piece",
"price_source": "products_json",
"page": 1,
"position": 5,
"mode": "listing",
"locale": "en-us",
"product_id": "4251267858502",
"handle": "the-amalfi-flat-black-classic",
"base_sku": "AO292",
"product_type": "One Piece",
"original_price": null,
"discount_pct": null,
"price_max": null,
"price_varies": false,
"variants_total": 7,
"variants_available": 7,
"tags": "andie::coverage => medium | andie::master => the-amalfi-one-piece | badge:core | bust-s…",
"published_at": "2019-10-14T01:10:42-04:00",
"collection": "one-pieces",
"sort": "collection-default",
"variant_id": null,
"variant_title": null,
"color": null,
"size": null
}
]First 2 of 7 rows from a real run — sample_output.json. Long values shortened here.
Handles what breaks naive Andie Swim scrapers
Reads the store's own JSON, not the painted grid
A collection page's HTML carries no product grid and product pages publish no Product JSON-LD, so the engines read the same JSON endpoints the storefront consumes — stable on every route.
Per-size stock, not just 'buyable'
Product mode reads the endpoint that publishes per-variant availability, so you see exactly which sizes are in stock rather than a single listing-level flag.
Misspelt collections caught
An unknown collection handle answers HTTP 200 with an empty list; every run checks the handle against the store's collection index and reports unknown_collection instead of 'empty'.
Market-correct prices
Prices are set per market, not converted. The market is taken from the URL path and recorded on every row, avoiding the client-side geolocation rewrite that makes HTML pages change currency after load.
Scraping infrastructure included
The same tested core runs every 2scraper repository, so the hard parts work the same way on every site.
CAPTCHA handling
Detects the challenge a page really serves and, with a 2Captcha key, solves it only when it blocks the data — a capped number of solves per page.
Proxy rotation
Single proxy or a pool from a file, rotated on blocks with a fresh browser per exit. Credentials stay out of argv and logs.
Fingerprints
Optional complete device identity from the 2Captcha Fingerprint API — user agent, client hints, locale and timezone that agree with each other.
Honest run metadata
Every run writes a .meta.json sidecar and distinct exit codes: complete, blocked, empty and partial are never confused, and a failed run never overwrites good data.
Diff two runs
diff_runs.py compares two complete Andie Swim snapshots by id — new, removed and changed rows for monitoring.
What teams do with Andie Swim data
Size-level stock tracking
Watch which sizes of each style sell out and come back, using per-variant in_stock rows.
Discount monitoring
Track was-prices and discount percentages across a collection over time and diff runs to spot new markdowns.
Cross-market price comparison
Compare the same SKU across markets — titles are identical everywhere, so a join on sku is exact and gaps reflect pricing policy.
Assortment and catalogue analysis
Map product types, fabrics and coverage tags across collections, or track newly published styles via published_at.
Free to run. Pay only for what the site requires.
Runs with no key, proxy or account
Nothing on the read path is gated: measured Sep 2026 from a datacenter address with no key, no proxy and no fingerprint, every request returned HTTP 200 and no challenge ever appeared. A different market is usually just a path prefix like /en-gb/. The paid 2Captcha products add volume from many addresses (residential proxies for --concurrency), a specific exit country if you want the store's geolocation to agree, and the Scraper API path for running without a local browser.
Optional 2Captcha services — captcha solving, the Scraping Browser API, residential proxies and fingerprints — work behind one key.
Good to know
- Ratings are not in the output: the review widget's stars are hidden in the grid and absent from every JSON route.
- There is no --sort flag; the JSON endpoint ignores sort parameters.
- in_stock is published per variant only in product mode.
2scraper vs. hosted scraper APIs
| 2scraper | Typical hosted API | |
|---|---|---|
| Code | Open source, MIT — read and patch it | Closed |
| Cost | Free; optional services billed only when used | Subscription or per request / per result |
| Runs on | Your machine, server or CI | The vendor's infrastructure |
| Output | JSON/CSV files + run metadata | API responses |
| When the site changes | Fix it yourself or open an issue / PR | Wait for the vendor |
Andie Swim scraper FAQ
Do I need a proxy or a 2Captcha key?
No. The README measured every route as ungated from an ordinary datacenter address. Proxies only help with volume or a specific exit country.
Which pages can it scrape?
Collection listings, keyword searches and single product pages, read through the store's own JSON endpoints.
What output formats are supported?
JSON and CSV with the same field order, plus a <out>.meta.json sidecar recording status, stop reason, failed pages, market and currency.
How do I get prices for another country?
Use the market-prefixed URL with --locale, e.g. --locale en-gb with an /en-gb/ URL. Prices are set per market, not converted.
Why does a collection return fewer products than its products_count?
The store's products_count is not a count of products a visitor can reach; the scraper records it in the sidecar with a warning and plans nothing from it.
Is scraping Andie Swim legal?
The tool reads public catalogue data and never touches checkout. Follow the site's terms, its robots.txt and the law where you operate.