Travel fares · Hotel content data
Hotel content data collection for mapping and deduplication
Hotel content data collection gathers the descriptive side of a property from public pages: identity, location, room types, amenities, policies and photo metadata. Mapping teams use it to match the same hotel across suppliers and to keep listings accurate; it changes slowly, so it belongs on the cheapest pool.
Pay per GB · No subscription · Prices in EUR, excl. VAT
- €2.00
- per GB on ARC Fast, excl. VAT
- −44%
- at 1 TB (€1.12 / GB)
- 185+
- countries, city targeting
- Never
- expires — no subscription
Written for
- OTA content and mapping teams
- Bed bank supplier-integration teams
- Metasearch content teams
- Hotel brand-standards auditors
The short answer
- Content is not prices: it changes weekly or monthly, does not depend on the visitor's market much, and can run on rotating ISP exits.
- Where a hotel page carries schema.org structured data (Hotel, LodgingBusiness), it can hold check-in time, amenities, room count and pet policy. Read that first.
- Store photo metadata (URL, dimensions, perceptual hash), not photos. Hashes are enough for duplicate detection.
- In the EU, databases can carry a sui generis right, and site terms can restrict extraction from databases the Directive does not protect. Collect only what your use needs.
The problem
What goes wrong without the right IPs
The same hotel under five names
"Hotel Am Markt", "Am Markt Hotel & Spa" and a chain-branded name may be one property. Name matching alone fails; geo-coordinates, address, phone and room count together resolve most cases.
Room types explode across suppliers
One property can show a dozen room names across channels for four physical room types. Mapping needs bed configuration, size, view and occupancy as separate fields.
Amenities without a vocabulary
"Free Wi-Fi", "WiFi (complimentary)" and an icon with no text are the same amenity. Without a controlled vocabulary, amenity filters on your own site return nonsense.
Stale content is worse than none
A pool that closed last year or a pet policy that changed leads to complaints. Change detection on a schedule keeps content honest; a one-off crawl does not.
What to collect
What you can collect
- Identity
- Name, brand or chain, address, geo-coordinates, business phone, website. The keys for matching.
- Classification
- Star rating as displayed and its source; property type (hotel, aparthotel, guesthouse).
- Room types
- Raw room name, bed configuration, size, maximum occupancy, view, bathroom type.
- Amenities
- Property-level and room-level, raw label and mapped code, and whether stated as included or chargeable.
- Policies
- Check-in and check-out times, children, pets, deposit, accepted payment, smoking.
- Photo metadata
- Image URL, dimensions, caption or alt text, perceptual hash. Not the image file.
- Provenance
- Source URL, fetch time, content hash. Lets you show when a field changed and where it came from.
How it runs
How a collection run works
- 01
Discover properties from sitemaps
Hotel and chain sites usually list property pages in their sitemaps. Start there instead of paginating search results; it is lighter and complete.
- 02
Read structured data first
Extract JSON-LD from each page. Where it is present and complete, you need little HTML parsing.
Pull schema.org Hotel data from a property page24 linesimport json, requestsfrom bs4 import BeautifulSoupPROXIES = {"http": "http://USERNAME_pool-arcfast_country-de:PASSWORD@proxy.arcproxies.io:8000", "https": "http://USERNAME_pool-arcfast_country-de:PASSWORD@proxy.arcproxies.io:8000"}LODGING = {"Hotel", "LodgingBusiness", "Motel", "Hostel", "Resort", "BedAndBreakfast"}def lodging_jsonld(url: str) -> list[dict]: html = requests.get(url, proxies=PROXIES, timeout=30).text out = [] for tag in BeautifulSoup(html, "html.parser").find_all("script", type="application/ld+json"): try: data = json.loads(tag.string or "") except json.JSONDecodeError: continue items = data if isinstance(data, list) else data.get("@graph", [data]) for item in items: types = item.get("@type", []) types = [types] if isinstance(types, str) else types if LODGING & set(types): out.append({k: item.get(k) for k in ( "name", "address", "geo", "telephone", "starRating", "checkinTime", "checkoutTime", "numberOfRooms", "petsAllowed", "amenityFeature")}) return out - 03
Normalise into your vocabulary
Map amenity labels and room attributes to your own codes, keep raw values beside them, and record the language of the source page.
- 04
Match and deduplicate
Block candidates by geo-distance, then score name, address, phone and room count. The techniques are in deduplicating listings.
- 05
Detect changes
Re-crawl on a schedule, compare content hashes per field, and send only changed fields to review. Most pages will not have changed since last month.
Setup
Recommended setup
Content pages are numerous, static and largely the same for every visitor. Rotating ISP exits are the default; residential is the fallback for sites that serve content only to residential visitors.
| Plan | Role | Session | Targeting | Price |
|---|---|---|---|---|
ARC Basic Rotating ISP | Default for content crawls Rotating ISP IPs are the cheapest per GB and fast enough for large, mostly static crawls. | Rotating | Country of the site's main market | €0.75 / GB €0.59 at 1 TB (−21%) |
ARC Fast Rotating residential | Fallback and language versions Residential exits for sites that answer ISP ranges poorly, and for collecting the local-language version of descriptions. | Rotating, or sticky per page set | Country | €2.00 / GB €1.12 at 1 TB (−44%) |
http://USERNAME _pool-arc _country-de:PASSWORD@ proxy.arcproxies.io:8000Prices are list prices in EUR, excl. VAT. Volume discounts apply automatically at checkout — full ladder on the pricing page.
Connect
One connection string per market
The country, city and sticky session are tokens in the username. Change the token, change the market; keep the session handle, keep the IP.
http://USERNAME_pool-arcfast_country-de_session-k3f9a1x2_sesstime-10:PASSWORD@proxy.arcproxies.io:8000Swap _country-de for any market you quote. The full grammar is on the residential proxies page.
Illustration
What a monthly refresh of 200,000 properties costs
An illustration with round numbers — your pages, payloads and retry rate will differ. The arithmetic is the real price ladder.
Assumptions
- Properties
- 200,000
- Refresh
- monthly
- Pages per property
- 1 (rooms on the same page)
- Weight per page, HTML only
- 600 KB
- Bandwidth per month
- ≈ 120 GB
On ARC Basic
€81.60per month, excl. VAT
120 GB bought in one purchase at €0.68 / GB (−9% volume rung, applied automatically).
The same 120 GB on ARC Fast: €163.20 at €1.36 / GB. Route only the jobs that need it through the pricier pool.
Conditional requests (If-Modified-Since, ETag) and sitemap lastmod dates often let you skip unchanged pages altogether. Never download the images themselves; their URLs and hashes are enough for matching.
Bandwidth never expires, so a bigger single purchase is only ever cheaper per GB. See the ladder.
In depth
Hotel content data, in depth
What hotel pages publish as structured data
Schema.org defines Hotel as a type of LodgingBusiness with properties that map almost one-to-one onto a content model: amenityFeature, availableLanguage, checkinTime (the earliest someone may check in), checkoutTime, numberOfRooms, petsAllowed and starRating, alongside the usual name, address and geo fields.
One caveat matters for amenity data: schema.org notes that amenityFeature does not state whether the feature is included in the offer or available at extra cost. If your product shows "free parking", get that from the page text, not from the structured data.
Content data versus rate data
| Content | Rates | |
|---|---|---|
| Changes | Weekly to yearly | Several times a day |
| Depends on visitor market | Language mostly | Yes, see point of sale |
| Typical pool | Rotating ISP | Residential, sticky per shop |
| Key risk | Wrong matches, stale fields | Wrong market, missing restrictions |
Keep the two pipelines apart. Rates come from hotel rate shopping; content refreshes on its own slower schedule and feeds the mapping that rate data depends on.
Database rights, site terms and photos
The EU Database Directive gives the maker of a database who has made a substantial investment in obtaining, verifying or presenting its contents a right to prevent extraction or re-utilisation of the whole or a substantial part of it. In Ryanair v PR Aviation (C-30/14, 2015), the Court of Justice held that where a database is protected by neither copyright nor that right, the Directive does not stop the site owner from restricting its use by contract, for example through terms of use.
In practice: collect the fields your matching and accuracy work needs, not entire catalogues for republication; read each site's terms; treat photographs as someone else's work and keep only URLs and hashes. This is a description of the landscape, not legal advice.
Crawling content politely
- Use sitemaps and lastmod dates instead of re-crawling everything.
- Honour robots.txt; the reasoning is set out in respecting robots.txt.
- Send conditional requests and cache aggressively; content that has not changed should cost you nothing.
- Prefer supplier feeds and content APIs where you have a contract for them, and use public pages to fill gaps and verify.
Works with anything that takes a proxy URL
- Scrapy
- Python requests / httpx
Crawlee
- Crawl4AI
- Docker
FAQ
Questions
Something not covered? Write to contact@arcproxies.io.
What is hotel content mapping?
Hotel content mapping is matching the same property, and its room types, across different suppliers and channels, so one hotel appears once with consistent details. It relies on identity fields such as coordinates, address and phone, plus room attributes.
Do I need residential proxies to collect hotel content?
Usually not. Content pages change slowly and look the same to most visitors, so rotating ISP proxies are the cheaper default. Keep residential exits as a fallback and for local-language versions.
Should I store hotel photos?
Store photo URLs, dimensions, captions and perceptual hashes, not the images. Hashes are enough to detect duplicates and changes, and photographs are someone else's work.
How often should hotel content be refreshed?
Monthly for the full catalogue is common, with a faster cycle for properties that changed recently or have open quality complaints. Use sitemap dates and conditional requests to skip unchanged pages.
Is schema.org data on hotel pages reliable?
It is a good first source, but check it against the visible page. Fields can be out of date, and amenityFeature does not say whether an amenity is free or chargeable.
Sources & review
Last reviewed by the ARC Proxies team. Prices are read from the live catalog at build time.
- [1]Schema.org: Hotel (type definition, including properties from LodgingBusiness)
- [2]Schema.org: amenityFeature (property definition)
- [3]EUR-Lex: Directive 96/9/EC on the legal protection of databases, Article 7
- [4]EUR-Lex: Judgment of the Court of 15 January 2015, Ryanair Ltd v PR Aviation BV, Case C-30/14
Travel fares
More on travel fares
Get started
Buy a gigabyte and try it on your own targets.
No subscription, no sales call. Code WELCOME15 takes 15% off your first purchase, and whatever you do not use is still there next quarter.