Travel Review Scraper for Hotels, Restaurants and Attractions
ProxyField's Web Scraping API is designed to fetch the public review pages of hotels, restaurants and attractions on travel review and booking sites for $0.50 per 1,000 successful results over plain HTTP, or $0.20 from 10,000 results in one purchase, and $2.00 per 1,000 with JS rendering for blocks that load with scripts, such as hotel price offers. The API is in development and offered through Contact sales; to run your own travel review scraper today, start on ProxyField residential proxies with the Easy Trial: 1 GB for $2.95.
Through the sales team on our 24/7 live chat
| Fetch | Entry | Volume, from |
|---|---|---|
| HTTP | $0.50 | $0.20 |
| JS rendering | $2.00 | $1.00 |
Billed on successful results only.
Every review of a list of hotels, with date and rating, in three steps. (1) Check the route first: where a site offers an official API or a partner feed, read what it returns and under which display rules, and read the site's terms, because many travel sites forbid automated collection of their pages without written permission. (2) Find how the site numbers its review pages and where each review's rating and date sit; many pages also describe their reviews in a schema.org block (application/ld+json). (3) This page gives a Python loop over the review pages that writes rating, ISO date, title and text per review, leaves reviewer names out and checks the total against the review count the page states.
Every review for a list of hotels: official feed or public pages
| Item | Route 1: the site's official API or partner feed | Route 2: the public review pages |
|---|---|---|
| Reviews per place | What the site chooses to share, often a few recent reviews | Every review the pages list, page by page |
| Fields | Set by the API: usually rating, date, title and text | Rating, date of stay or visit, date written, title, text, owner's reply |
| Place lookup | The API's search, by name or address | The place's page URL |
| Access | An approved key or a partner agreement, under the site's display rules | The site's terms; many forbid automated collection without written permission |
| Cost | Set by the site | Your proxy traffic per GB, or $0.50 per 1,000 pages on the Web Scraping API (in development) |
Read moreShow less
Every review from the public pages in Python
This script reads every review page of each place in a list and writes one CSV row per review: place, review id, rating, date (YYYY-MM-DD), title and text. It reads the reviews from the schema.org Review objects in the page's application/ld+json blocks, and on the first page the place's reviewCount (aggregateRating), so at the end it prints how many reviews it collected against that count. Reviewer names are personal data, so it leaves them out. It goes through ProxyField residential proxies with a new IP on every request and waits 3 to 6 seconds between pages. Only use it on pages the site's terms let you collect (see the terms and the law).
How it pages: the first page is the place's URL itself; open page 2 in your browser, see how the address changes (a page number or an offset, in the query or the path) and set page_url() to the same pattern. The loop stops when a page has no reviews, or when it sees only reviews it already has (past the last page, a site can send you back to an earlier one).
import csv, hashlib, json, random, time
from datetime import datetime
import requests
from bs4 import BeautifulSoup
# Your list: place -> the URL of its first review page (placeholders: use pages you may collect)
PLACES = {
"Example Hotel": "https://reviews.example.com/hotel/12345/example-hotel",
"Other Hotel": "https://reviews.example.com/hotel/67890/other-hotel",
}
PROXY = "http://<login>-country-us:<password>@gate.proxyfield.io:7000" # new IP on every request
HEADERS = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", "Accept-Language": "en-US,en;q=0.9"}
def page_url(url, n):
# Copy the site's own pattern from page 2 in your browser, e.g. "?page=2" or "?offset=10".
return url if n == 1 else f"{url}?page={n}"
def fetch(url):
for attempt in range(3):
r = requests.get(url, proxies={"http": PROXY, "https": PROXY}, headers=HEADERS, timeout=30)
if r.status_code == 200:
return r.text
time.sleep(10 * (attempt + 1)) # wait; the next try gets a new IP
return None
def objects(html):
"""Every schema.org object in the page's application/ld+json blocks, nested ones included."""
out = []
for block in BeautifulSoup(html, "html.parser").select('script[type="application/ld+json"]'):
try:
queue = [json.loads(block.string or "")]
except ValueError:
continue
for x in queue: # the list grows while the loop walks it, so nested objects follow in page order
if isinstance(x, list):
queue.extend(x)
elif isinstance(x, dict):
out.append(x)
queue.extend(v for v in x.values() if isinstance(v, (dict, list)))
return out
def is_type(x, name):
t = x.get("@type")
return name in (t if isinstance(t, list) else [t])
def review_count(objs):
for x in objs:
agg = x.get("aggregateRating")
if isinstance(agg, dict):
count = str(agg.get("reviewCount") or agg.get("ratingCount") or "").replace(",", "")
if count.isdigit():
return int(count)
return None
def iso(value):
value = str(value or "")
if len(value) >= 10 and value[4] == "-" and value[7] == "-":
return value[:10] # already ISO, with or without a time
for fmt in ("%B %d, %Y", "%b %d, %Y", "%d %B %Y"):
try:
return datetime.strptime(value, fmt).strftime("%Y-%m-%d")
except ValueError:
pass
return value # unknown format: keep the raw text
def reviews(objs):
for x in objs:
if not is_type(x, "Review"):
continue
rating = x.get("reviewRating") if isinstance(x.get("reviewRating"), dict) else {}
row = {"rating": rating.get("ratingValue", ""), "date": iso(x.get("datePublished")),
"title": x.get("name", ""), "text": x.get("reviewBody", "")}
rid = x.get("@id") or x.get("url") or hashlib.sha1(json.dumps(row, sort_keys=True).encode()).hexdigest()[:16]
yield {"review_id": rid, **row}
with open("travel_reviews.csv", "w", newline="", encoding="utf-8") as f:
out = csv.DictWriter(f, ["place", "review_id", "rating", "date", "title", "text"])
out.writeheader()
for place, url in PLACES.items():
seen, n, total = set(), 1, None
while True:
html = fetch(page_url(url, n))
if html is None:
print(f"{place}: stopped at page {n}, page not fetched")
break
objs = objects(html)
if n == 1:
total = review_count(objs)
rows = [r for r in reviews(objs) if r["review_id"] not in seen]
if not rows:
break # no reviews, or only reviews we already have: last page passed
for r in rows:
seen.add(r["review_id"])
out.writerow({"place": place, **r})
n += 1
time.sleep(random.uniform(3, 6))
note = "" if total in (None, len(seen)) else " <- mismatch: check the language filter and the stop point"
print(f"{place}: {len(seen)} reviews collected, page states {total}{note}")What to expect: one line per place in the form <place>: <n> reviews collected, page states <count>. A mismatch has two usual causes: the review list was filtered to one language while the count covers all of them, or the loop stopped early on a page it could not fetch (the "stopped at page" line says which). If the first run writes no rows, the site shows its reviews only as HTML: save one page (open("page.html", "w").write(html)), find the element that wraps a single review, and read the rating, the date and the text from it with Beautiful Soup selectors in place of reviews().
Traffic: ProxyField bills per GB, so measure the traffic of a few review pages before you size a purchase. ProxyField residential proxies cost $2.95/GB for 1 GB, $2.79 from 10 GB and down to $1.95/GB from 1,000 GB, with no subscription; the traffic never expires, and all purchases are final. You get 412M+ residential IPs in 195+ countries, targeting by country, region (state) and city, and a new IP on every request or a sticky session from 30 s to 36 h.
The same loop through the Web Scraping API (the API's design)
With the Web Scraping API you keep the parser and replace fetch(): the API is designed to fetch each review page and retry blocked requests on new IPs, which are not billed. Each response says whether it was billed (X-Billed) and carries the target's status (X-Target-Status). The API is in development and offered through Contact sales; parameters: API documentation.
API = "https://api.proxyfield.io/v1/scrape"
KEY = "<api_key>"
def fetch(url):
r = requests.post(API, headers={"Authorization": f"Bearer {KEY}"},
json={"url": url, "render": False, "country": "us", "output": "html"},
timeout=130)
if r.status_code != 200 or r.headers.get("X-Target-Status") != "200":
return None # not delivered: not billed (a target's 404 or 410 is a billed result)
return r.textCost for the question's case: 200 hotels × 50 review pages = 10,000 results. At $0.50 per 1,000 that is $5.00; bought as 10,000 results in one purchase, the volume price of $0.20 applies, so $2.00. For big lists, a batch takes up to 1,000 URLs in one request and calls your server back as each job finishes; results are kept 48 hours.
Travel review data on public pages
Travel review and booking sites publish ratings, reviews and rankings of hotels, restaurants and attractions, and many compare hotel prices from booking sites. Most of it is visible to logged-out visitors; writing reviews, saving trips and messages need an account.
| Page type | What the public page usually shows |
|---|---|
| Hotel page | Rating, review count, ranking in the city, amenities, price offers for your dates, reviews |
| Restaurant page | Rating, ranking, cuisines, price range, address, hours, reviews |
| Attraction or tour page | Rating, ranking, duration, tours on sale, reviews |
| City lists | Ranked hotels, restaurants or things to do, with links |
| Reviews | Title, text, rating, date of stay or visit, trip type, reviewer's public name, owner's reply, a set number per page |
Reviewer names are personal data, so store them only where your purpose needs them. The Web Scraping API returns the page itself as HTML, Markdown or plain text, or a JSON envelope with the status code, the final URL, the headers, the cookies and the content; it has no parsed review fields, so your parser reads them.
How the Web Scraping API fetches a travel review page
You send the URL of a public review page and choose plain HTTP or JS rendering; the API returns the page. By design, the API takes a POST to https://api.proxyfield.io/v1/scrape with your API key in an Authorization: Bearer <api_key> header and a JSON body: url, render (false for plain HTTP, true for JS rendering), country and output (html, markdown, text or json). For hotel price offers, which load with scripts, wait_for takes a CSS selector to wait for with rendering. Parameter reference: API documentation.
# The request the Web Scraping API takes (in development; access through Contact sales)
curl https://api.proxyfield.io/v1/scrape \
-H "Authorization: Bearer <api_key>" \
-H "Content-Type: application/json" \
-d '{"url": "https://reviews.example.com/hotel/12345/example-hotel", "render": false, "country": "us", "output": "json"}'Example response (shortened; content is the page's HTML):
{
"metadata": {"id": "req_67f39e5e538354dc", "api": "web_scrape", "status": "success", "billed": true},
"status_code": 200,
"final_url": "https://reviews.example.com/hotel/12345/example-hotel",
"content_type": "text/html; charset=utf-8",
"content": "<!DOCTYPE html><html lang=\"en-US\">…</html>"
}Pricing: $0.50 per 1,000 review pages, from $0.20
Travel review pages cost the Web Scraping API's price: $0.50 per 1,000 successful results over plain HTTP, or $0.20 from 10,000 results in one purchase, and $2.00 per 1,000 with JS rendering, or $1.00 from 10,000. You pay only for successful results.
Billed: a page delivered to you, including a target's 404 or 410 and a sign-in page the site serves with a 200 status. Not billed: blocked and timed-out requests, error responses and our internal retries. Every response says whether it was billed.
| Choice | Price per 1,000 successful results | Use it for |
|---|---|---|
| Plain HTTP | $0.50, from $0.20 | Reviews, ratings, rankings and business details, which are usually in the HTML |
| JS rendering | $2.00, from $1.00 | Hotel price offers for your dates and other blocks that load with scripts |
| Workload (30-day month) | Results | Plain HTTP at $0.50 | JS rendering at $2.00 |
|---|---|---|---|
| 200 competing hotels, newest reviews weekly (4 runs) | 800 | $0.40 | $1.60 |
| 50,000 reviews of a city's restaurants (10 per page), once | 5,000 | $2.50 | $10 |
| Full review history of 200 hotels, 50 review pages each, once | 10,000 | $5.00, or $2.00 at $0.20 | $20, or $10 at $1.00 |
| 1,000 hotels' price offers, daily (JS rendering) | 30,000 | — | $60, or $30 at $1.00 |
Payment and balance: the same crypto balance as proxies, which never expires; there is no subscription or monthly fee. Contact sales through the sales team on our 24/7 live chat. All prices: pricing.
Through the sales team on our 24/7 live chat
An official review API or a scraper?
Some travel review sites offer an official API or a partner feed to approved developers: usually a place's basic details with a few of its reviews, under display rules such as showing the site's branding and linking back. That suits a site that shows a hotel's rating badge. Full review histories, rankings across a city and competitors' price offers are usually only on the public pages, under the site's terms (see the terms and the law below).
| Item | An official API or partner feed | Web Scraping API (in development) |
|---|---|---|
| Who can use it | Approved developers or partners | ProxyField customers, through Contact sales |
| Data | What the site chooses to share, often a few recent reviews per place | Any public page you send, returned as HTML, Markdown, text or JSON |
| Rules | The site's display and branding terms | Public pages only, and follow the site's terms |
| Cost | Set by the site | $0.50 per 1,000 successful results, from $0.20 |
What makes travel review pages hard to collect
Travel sites often run strict bot protection: fast request rates, datacenter IPs and clients without normal browser headers get a challenge page instead of reviews. Price offers depend on dates and load with scripts, and many travel sites run a separate site per country, each with its own currency and language. Where a site allows your collection, keep the rate low (a few seconds between requests per IP), fix the country of every check and store the date of each reading. Error codes explained: errors.
What teams use travel review data for
- Reputation monitoring new reviews and ratings for your own hotels, restaurants or tours.
- Competitive analysis competitors' ratings, rankings and what guests praise or criticize.
- Review analytics sentiment and topics across thousands of reviews in a city or chain.
- Rate checks which booking sites offer a hotel and at what price for given dates.
Posting, buying or editing reviews is not data collection; fake engagement is forbidden under ProxyField's acceptable use policy. Proxies for other travel work: travel proxies.
Is it legal to scrape travel review sites?
Most travel review and booking sites set rules for automated access in their terms of use, and many bar accessing or copying their content with robots, spiders, scrapers or other automated means without written permission; some also name AI systems. Collecting a site's pages against its terms breaches those terms, separate from whether it breaks a law; the permitted routes are the site's official API or partner feed under its display rules, or its written permission. Read the terms and the robots.txt of every site before you collect. Review texts belong to their authors and can be protected by copyright, and reviewer names are personal data under GDPR in the EU and UK: analyse reviews rather than republish them, and keep names out. The wider answer is in Is Web Scraping Legal? US, EU and UK Rules (2026) and Web Scraping Law in the UK and EU.
ProxyField's acceptable use policy allows collecting public web data and market research, and forbids fake engagement and accessing data behind logins you are not entitled to. ProxyField's rule for every site: public pages only, and follow the site's terms. This is not legal advice.
More scrapers
- Yelp scraper public Yelp business pages and reviews.
- Review scraper reviews from software and service review sites.
- Expedia scraper hotel rates, rentals and guest reviews.
- Airbnb scraper hotel rates, rentals and guest reviews.
- Flight and hotel scraper Booking.com, Skyscanner, Kayak and other travel sites.
- All scraper APIs
Travel review scraper FAQ
24/7 support by live chat, including help with setup and integration.
What is a travel review scraper?
ProxyField's Web Scraping API, in development and offered through Contact sales, is designed to work as a travel review scraper: you send a public hotel, restaurant or attraction review page and get the page back, for $0.50 per 1,000 successful results over plain HTTP, or $0.20 from 10,000 results in one purchase. In general, a travel review scraper is any tool that collects ratings, rankings, reviews and price offers from the public pages of travel review and booking sites.
How do I scrape every review for a list of hotels with Python, with each review's date and rating?
Loop over each hotel's review pages, read every review's rating, date, title and text, and stop when a page brings no new reviews; the script on this page does that and checks the total against the page's reviewCount. Before you run it, check the site's official API and its terms: many sites forbid automated collection of their pages without written permission. For 200 hotels × 50 pages, the Web Scraping API's design prices that at 10,000 results: $5.00, or $2.00 at the volume price.
Does a travel site's official API return every review?
Often not: official APIs and partner feeds tend to return a place's details with a few recent reviews, under display rules. Check what the API returns for a place you know before you plan around it. Older reviews are often only on the public review pages.
How do I scrape a travel review site?
First check the route: the site's official API or partner feed, or the site's written permission for its public pages. Then start from a city list or the pages of the places you track, fetch each page, read the rating, ranking and reviews, and follow the review pages to the last one. Keep the rate low and fix the country of every request.
What data can I scrape from travel review sites?
Ratings, review counts, rankings in a city, business details such as address, cuisines and amenities, review titles, texts, dates and owner replies, and hotel price offers from booking sites. Saved trips, messages and anything behind a login are out of scope.
What does a hotel and restaurant review scraper collect?
The reviews on each place's pages: title, text, rating, date of stay or visit, trip type and the owner's reply. Teams use it to track their own reviews and to analyse what guests say about competitors.
How do I scrape travel reviews with Python?
Fetch each review page with requests through a residential proxy, read the reviews from the page's schema.org Review objects or parse the review cards with Beautiful Soup, and step through the review pages until a page has no new reviews. The script on this page writes the rating, date (YYYY-MM-DD), title and text of every review to a CSV, and compares the count with the page's reviewCount.
How do I find how a site numbers its review pages?
Open a place's reviews in your browser, go to page 2 and compare the address with page 1: most sites add a page number or an offset to the query or the path. Set page_url() in the script to that pattern. If page 2 loads without the address changing, the reviews come from a background request, which the browser's network tab shows.
What are the limitations when scraping travel review sites?
Many sites' terms forbid automated collection without written permission, and official APIs often return only a few recent reviews per place. Technically, expect strict bot protection against fast or datacenter traffic, price offers that load with scripts and depend on dates, separate country sites with their own currency and language, and layouts that change from time to time.
What's the rate limit for scraping travel review sites?
Travel sites rarely publish a rate limit for their public pages; they challenge or block clients that send too many requests from one IP. Where your collection is allowed, keep several seconds between requests per IP; the script on this page waits 3 to 6 seconds between pages.
Show 11 more questionsShow fewer questions
How do I handle JavaScript when scraping travel review pages?
Reviews, ratings and business details are usually in the HTML, so plain HTTP covers most pages. Use JS rendering or a headless browser only for hotel price offers and other blocks that load with scripts; on ProxyField's Web Scraping API (in development) that costs $2.00 per 1,000 successful results, or $1.00 from 10,000 results in one purchase.
Can I scrape travel reviews from a specific country?
Yes: use the country's version of the site and send the requests through IPs in that country, which sets the currency of price offers and the order of reviews by language. ProxyField residential proxies offer targeting by country, region (state) and city, with 412M+ residential IPs in 195+ countries.
Which programming languages can I use for a travel review scraper?
Any language that can send HTTP requests through a proxy: Python with requests and Beautiful Soup is the most common, and Node.js, Go and Java work the same way. For price offers that need a browser, use Playwright, Puppeteer or Selenium.
How do I get structured JSON from a travel review page?
Read the page's application/ld+json blocks first: many review pages describe the place, its aggregateRating and its reviews there. Otherwise parse the reviews into JSON yourself: title, text, rating, dates and reply, one record per review with the page URL.
Can I scrape travel reviews without writing code?
For a few pages of reviews, a browser extension that exports the visible reviews to CSV is enough. For regular pulls across many places, an automation tool with an HTTP step can call an API and write the results to a spreadsheet.
Can I run a travel review scraper on a schedule?
Yes: run your script or API calls on a schedule, such as weekly for new reviews and daily for price offers, and store each result with the date of the check. A weekly check of the newest reviews for 200 hotels is 800 pages a month, $0.40 over plain HTTP on the Web Scraping API.
Should I use a travel site's official API or a scraper?
Use the site's official API or partner feed whenever what it returns and its display rules fit your use: it is the permitted route. Full review histories, rankings across a city and competitors' price offers are usually only on the public pages, and collecting them automatically often needs the site's written permission.
How is travel review data used for competitive analysis?
Teams compare their ratings and rankings with competitors in the same city, read what guests praise or criticize in competitors' reviews, and track which booking sites offer competing hotels at what price. Repeating the check monthly shows how positions move.
How do I collect reviews from several travel sites in one pipeline?
Run one pipeline with a parser per site: send every URL through the same scraping API or proxy pool, and store the results in one table keyed by place and date. Booking and rental search pages often need JS rendering, while most review pages do not.
Should I store reviewer names?
Only where your purpose needs them: reviewer names are personal data under GDPR in the EU and UK. The script on this page leaves them out and keeps the rating, date, title and text of each review.
Do travel review sites allow scraping in their terms?
Many do not: their terms bar access with robots, spiders, scrapers or other automated means without written permission, so collecting even public pages that way breaches those terms. Read each site's terms and robots.txt before you collect; whether a breach also breaks a law is a separate question, and this is not legal advice.
Related pages
Start collecting public pages with the Web Scraping API
Billed on successful results only. Contact sales for the Web Scraping API and the volume you need, or run your own scraper on residential proxies. 24/7 live chat helps with setup and integration.