~ / guides / How to Scrape Amazon: A Python Guide (Tested)

How to Scrape Amazon: A Python Guide (Tested)

MR
Marcus Reed
Founder & lead tester · about the author
the short version
  • A plain requests + BeautifulSoup scraper returns HTTP 200 on an Amazon product page and parses the title, rating (4.7), and review count (193,685).
  • The price came back empty in my test. Amazon hides the buybox behind a delivery-location session, so the field most people want is the field DIY scraping misses first.
  • At any volume Amazon throws CAPTCHAs and 503s and rotates page layouts, so a single IP and static selectors stop working fast.
  • For reliable price and stock at scale, route the page through a scraper API. I show the ChocoData universal endpoint, which renders JS and rotates IPs automatically.

Amazon is the most-scraped site on the consumer web and one of the most defended. Prices, ratings, review counts, and rank are the raw material for repricing tools, market research, and arbitrage. This guide builds a real Python scraper, tests it against a live listing, and shows exactly where DIY scraping holds up and where it breaks. I ran the code in June 2026 and pasted the real output below, including the part that did not work.

You can fetch a public Amazon product page with a script, and the legality depends on how you do it and what you take. The technical part is easy: a single product page returns HTTP 200 to a plain request, as my test below shows. The legal part has two layers worth separating.

On US computer-access law, scraping pages anyone can load without logging in sits on the safer side. In hiQ Labs v. LinkedIn, the Ninth Circuit held that scraping public profiles does not violate the Computer Fraud and Abuse Act, and the Supreme Court’s Van Buren decision narrowed the CFAA to something close to traditional hacking. So reading a public listing page with a bot is not, by itself, a federal computer crime.

Contract law is the live risk. Amazon’s Conditions of Use prohibit data mining, robots, and other automated data-gathering tools, and using the site means accepting those terms. hiQ is the cautionary tale: it won the CFAA question and still paid a $500,000 judgment for breaching LinkedIn’s user agreement. Two rules keep you on the lower-risk path. Stay on public pages and never script a logged-in account. Avoid collecting personal data, which pulls in the GDPR in Europe. I am a tester, not a lawyer, so get advice before any commercial scrape. My is web scraping legal pillar covers the full picture.

What data can you extract from an Amazon product page?

A product page carries most of the commercially useful fields, but they are not equally easy to reach. Some sit in static HTML that any parser reads on the first request. Others live in the buybox, which Amazon renders based on your session and delivery location, so a cold request often gets a 200 with those fields missing.

FieldSelector (typical)Reliable on first request?
Product title#productTitleYes
Star rating#acrPopover (title attr)Yes
Review count#acrCustomerReviewTextYes
Pricespan.a-price span.a-offscreenNo, gated by session/location
Availability#availabilityOften location-dependent
Images#landingImage (src / data attrs)Usually
ASINURL /dp/{ASIN} or detail tableYes (from the URL)
Bullet features#feature-bullets liUsually

The pattern to internalize: the descriptive, mostly-static fields parse fine, and the transactional fields (price, stock) are the ones Amazon protects. That ordering matters because price is usually the whole point of an Amazon scrape, and it is the first thing a naive scraper loses.

Method 1: scrape Amazon with requests and BeautifulSoup

A requests GET with a real browser User-Agent plus BeautifulSoup parsing is the simplest scraper, and it gets you partway. Here is the exact code I ran against a live Amazon listing (the Echo Dot, ASIN B09B8V1LZ3):

import requests
from bs4 import BeautifulSoup

HEADERS = {
    "User-Agent": (
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
        "AppleWebKit/537.36 (KHTML, like Gecko) "
        "Chrome/126.0.0.0 Safari/537.36"
    ),
    "Accept-Language": "en-US,en;q=0.9",
}

url = "https://www.amazon.com/dp/B09B8V1LZ3"
resp = requests.get(url, headers=HEADERS, timeout=30)
print("STATUS:", resp.status_code)

soup = BeautifulSoup(resp.text, "html.parser")

def text_or_none(selector):
    el = soup.select_one(selector)
    return el.get_text(strip=True) if el else None

title = text_or_none("#productTitle")
price = text_or_none("span.a-price span.a-offscreen")
popover = soup.select_one("#acrPopover")
rating = popover.get("title") if popover else None
reviews = text_or_none("#acrCustomerReviewText")

print("title:", title)
print("price:", price)
print("rating:", rating)
print("reviews:", reviews)

The real output:

STATUS: 200
title: Amazon Echo Dot (newest model) - Vibrant sounding speaker, Designed for Alexa+, Great for bedrooms, dining rooms and offices, Charcoal
price: None
rating: 4.7 out of 5 stars
reviews: (193,685)

Read that output carefully, because it is the honest result. The request succeeded (200), and the title, rating, and review count all parsed. The price came back None. That is not a broken selector. Amazon gates the buybox behind a delivery-location session, so a first, cookie-less request renders the page without a resolvable price block. I confirmed the availability element on the same page read “This item cannot be shipped to your selected delivery location,” which is the same gate showing up a different way.

So Method 1 is genuinely useful for catalog data (title, rating, review volume, features) and genuinely weak for the transactional fields. To get the price this way you would establish a session with a location cookie (Amazon sets one when you pick a ZIP), and even then a static request cannot run the JavaScript that hydrates parts of the page. For one product that is solvable with patience. The trouble starts when you scale.

How does Amazon block scrapers at scale?

Amazon’s defenses ramp up fast once one IP makes repeated requests, and a single machine running a loop hits them within a handful of pages. The single product fetch above worked. A thousand of them from the same address will not. These are the layers you run into:

DefenseWhat you seeTrigger
Session/location gating200 but empty price (my test)Cold request, no location cookie
Bot CAPTCHA”Enter the characters you see below” pageRepeated or fast requests from one IP
Rate limitingHTTP 503 / 429Request bursts
Layout rotationSelectors return NoneAmazon ships A/B page variants
IP fingerprintingHard blocksDatacenter IP ranges, missing headers

Two of these are subtle and bite even careful scrapers. The empty-price gate looks like success (200) but yields no price, so a naive crawler logs thousands of “successful” rows with the most important column blank. Layout rotation means Amazon serves several page templates, so a selector that works in one test returns None in production for a slice of requests. Hardcoding one selector and trusting a 200 status is how Amazon scrapers silently rot. The general playbook for surviving these defenses is in my scraping without getting blocked guide; the rest of this article is the Amazon-specific fix.

Method 2: scrape Amazon with a scraper API

A scraper API solves the two hard problems at once. It renders JavaScript through a real browser and routes the request through a rotating residential IP, so the price block resolves and you avoid blocks. You hand it the Amazon URL and get the data back instead of fighting cookies and CAPTCHAs yourself.

ChocoData is the service I use for this category. It exposes a universal endpoint (one URL for any site) plus 453 dedicated endpoints for common targets. Amazon does not have its own named dedicated endpoint in the docs, so the correct route is the universal endpoint with the full product URL, which is what that endpoint is built for. Here is the request shape, swapping the raw requests.get for the API:

import requests

API_KEY = "cd_live_YOUR_KEY"  # free tier: 1,000 requests/month, no card
target = "https://www.amazon.com/dp/B09B8V1LZ3"

endpoint = "https://api.chocodata.com/api/v1/universal/get"
params = {
    "api_key": API_KEY,
    "url": target,
    "parse": "html",   # get rendered HTML back, then parse as in Method 1
    "country": "us",   # US residential IP so pricing/availability resolve
}

resp = requests.get(endpoint, params=params, timeout=90)
print("STATUS:", resp.status_code)
# The rendered page comes back in the JSON payload; parse the same selectors
# as Method 1, but now the buybox is hydrated, so span.a-price .a-offscreen resolves.

The difference from Method 1 is what happens behind that one call. ChocoData fetches through a country-matched residential IP that rotates automatically and retries through a fresh IP when a block appears, and it can run optional JavaScript rendering for the dynamic parts of the page. The country=us parameter is the lever that makes the price resolve, because it gives Amazon a US delivery context instead of the unknown location my cold request had. Billing applies only to successful (2xx) responses at 5 credits each, so the empty-200 problem from Method 1 does not quietly drain your budget.

I did not paste live API output here because that requires a paid key, and I will not fake numbers. The endpoint path, parameters, free-tier limits, and billing model above come from the ChocoData docs. The honest claim is narrow: the universal endpoint takes a URL and returns the rendered page, which removes the two specific failures (empty price, IP blocks) I reproduced in Method 1.

Should you scrape Amazon yourself or use an API?

Use Method 1 for a handful of products and catalog fields; use a scraper API the moment you need price, stock, or volume. The decision comes down to which fields you need and how many pages you are pulling.

ScenarioDIY (requests + BS4)Scraper API
A few listings, title/rating/reviewsWorks, freeOverkill
Price and live availabilityMisses price (my test)Resolves with country IP
Hundreds or thousands of pagesBlocked fast (CAPTCHA, 503)Rotating IPs handle it
Survives Amazon layout changesYou maintain selectorsYou still parse, but get the page
CostFree until you get blockedFree tier, then per-request
Setup timeMinutesMinutes plus an API key

My honest take from the test: DIY scraping of Amazon is fine as a learning exercise and for descriptive data, and it falls short for the commercial fields right when a project gets serious. If you only need a product’s title and rating, Method 1 is enough and free. If you need accurate prices across many ASINs without babysitting blocks, the scraper API is the route that actually returns the data.

To go deeper on the building blocks, see the Python web scraping guide for the language fundamentals, BeautifulSoup for parsing, and Scrapy if you are crawling many pages and want a framework. The web scraping pillar ties the whole workflow together.

FAQ

Is it legal to scrape Amazon?

Scraping public Amazon listing pages (no login) is closer to the legal side after hiQ v. LinkedIn, which held that scraping public pages is not a CFAA violation. But Amazon's Conditions of Use prohibit data mining, robots, and automated extraction, so you can face a breach-of-contract claim. hiQ won the CFAA question and still paid $500,000 for breaching LinkedIn's user agreement. Avoid logged-in pages and personal data, and get legal advice for commercial use.

Why does my Amazon scraper return the title but not the price?

Amazon gates the buybox (the price block) behind a delivery-location and session. A first, cookie-less request often gets a 200 with the title and rating present but the price element missing or empty, which is exactly what I observed. You need to set a location cookie, render JavaScript, or use a scraper API that does both.

Does Amazon have an official API for product data?

Not a general public one. The Product Advertising API exists but requires an approved Associates account with qualifying sales, and the Selling Partner API is for sellers managing their own catalog. Neither gives open access to arbitrary product pages, which is why people scrape the HTML.

What is the best way to avoid getting blocked scraping Amazon?

Send a real browser User-Agent, keep request rates low, and never reuse one IP for bulk crawling. Past a few pages you need rotating residential IPs and JavaScript rendering. A scraper API bundles both, which is why it is the practical route for any Amazon job beyond a handful of listings.

MR
Marcus Reed
I've built and run web scrapers for the better part of a decade. On this site I put scraper APIs and scraping tools through real jobs against real targets, then write up what actually holds up.