<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: datalume</title>
    <description>The latest articles on DEV Community by datalume (@datalume).</description>
    <link>https://dev.to/datalume</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4206181%2F0ce52632-8101-48ff-a257-ec97fc716183.jpeg</url>
      <title>DEV Community: datalume</title>
      <link>https://dev.to/datalume</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/datalume"/>
    <language>en</language>
    <item>
      <title>I scraped Google Hotels for a competitor rate calendar — and found the trap that breaks most of them</title>
      <dc:creator>datalume</dc:creator>
      <pubDate>Thu, 29 Oct 2026 11:51:54 +0000</pubDate>
      <link>https://dev.to/datalume/i-scraped-google-hotels-for-a-competitor-rate-calendar-and-found-the-trap-that-breaks-most-of-them-5581</link>
      <guid>https://dev.to/datalume/i-scraped-google-hotels-for-a-competitor-rate-calendar-and-found-the-trap-that-breaks-most-of-them-5581</guid>
      <description>&lt;p&gt;I wanted a simple thing: &lt;strong&gt;the nightly price of 5 competing hotels for every date of the next few weeks&lt;/strong&gt;, plus which booking site sells each one cheapest. The kind of table a hotel revenue manager checks every morning.&lt;/p&gt;

&lt;p&gt;Google Hotels already shows all of this — it just doesn't let you export it. So I scraped it. Here's what I learned, including one trap that makes most "rate calendars" useless.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trap: Google re-ranks hotels for every date
&lt;/h2&gt;

&lt;p&gt;My first attempt was the obvious one: search "hotels in Shinjuku, Tokyo" for 7 consecutive check-in dates and keep the results.&lt;/p&gt;

&lt;p&gt;Then I checked how stable that list is. With the top 50 hotels per date over 7 dates, I got &lt;strong&gt;148 different hotels — and only 3 of them appeared on all 7 dates&lt;/strong&gt;. The same hotel can be #2 on one date, #42 on another, and missing on a third.&lt;/p&gt;

&lt;p&gt;That's fine for browsing, but for rate shopping it's fatal: your "calendar" ends up full of holes exactly where you need the comparison.&lt;/p&gt;

&lt;p&gt;The fix is to stop asking "which hotels are in Shinjuku?" and ask "&lt;strong&gt;what does &lt;em&gt;this exact&lt;/em&gt; hotel cost on each date?&lt;/strong&gt;" — lock each competitor to its Google Hotels ID once, then look up that same ID for every check-in date.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup (Python, ~15 lines)
&lt;/h2&gt;

&lt;p&gt;I packaged this as an Apify Actor (&lt;a href="https://apify.com/datalume/google-hotels-scraper" rel="noopener noreferrer"&gt;Google Hotels Scraper&lt;/a&gt;) so I don't have to babysit proxies or parsing. You give it your competitive set and a date range:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;apify_client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ApifyClient&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ApifyClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;YOUR_APIFY_TOKEN&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;run_input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hotels&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Keio Plaza Hotel Tokyo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hotel Gracery Shinjuku&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Shinjuku Granbell Hotel&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Mitsui Garden Hotel Jingugaien Tokyo PREMIER&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MIMARU TOKYO SHINJUKU WEST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;location&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tokyo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;        &lt;span class="c1"&gt;# helps pick the right hotel for each name
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;checkIn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2026-11-12&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dateRangeDays&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="c1"&gt;# up to 60
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;adults&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;currency&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;USD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;includeOffers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;# every booking site's price, not just Google's headline price
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;datalume/google-hotels-scraper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;default_dataset_id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;iterate_items&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The run took &lt;strong&gt;41 seconds&lt;/strong&gt; and returned &lt;strong&gt;35 rows (5 hotels × 7 dates) — no gaps&lt;/strong&gt;. Each row has the hotel, the date, and an &lt;code&gt;offers&lt;/code&gt; list with 19–38 booking sites (Booking.com, Expedia, Agoda, Trip.com, the official site…), so about 1,000 site prices in total.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The rate calendar
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;calendar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pivot_table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;checkIn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lowestOfferPricePerNight&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cheapest price per night (USD, 2 adults, names shortened):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Hotel&lt;/th&gt;
&lt;th&gt;Thu 11-12&lt;/th&gt;
&lt;th&gt;Fri 11-13&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Sat 11-14&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;Sun 11-15&lt;/th&gt;
&lt;th&gt;Mon 11-16&lt;/th&gt;
&lt;th&gt;Tue 11-17&lt;/th&gt;
&lt;th&gt;Wed 11-18&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hotel Gracery Shinjuku&lt;/td&gt;
&lt;td&gt;176&lt;/td&gt;
&lt;td&gt;226&lt;/td&gt;
&lt;td&gt;228&lt;/td&gt;
&lt;td&gt;191&lt;/td&gt;
&lt;td&gt;191&lt;/td&gt;
&lt;td&gt;153&lt;/td&gt;
&lt;td&gt;225&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Keio Plaza&lt;/td&gt;
&lt;td&gt;269&lt;/td&gt;
&lt;td&gt;259&lt;/td&gt;
&lt;td&gt;270&lt;/td&gt;
&lt;td&gt;246&lt;/td&gt;
&lt;td&gt;245&lt;/td&gt;
&lt;td&gt;257&lt;/td&gt;
&lt;td&gt;251&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MIMARU Shinjuku West&lt;/td&gt;
&lt;td&gt;421&lt;/td&gt;
&lt;td&gt;420&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;682&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;453&lt;/td&gt;
&lt;td&gt;333&lt;/td&gt;
&lt;td&gt;336&lt;/td&gt;
&lt;td&gt;333&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mitsui Garden Jingugaien&lt;/td&gt;
&lt;td&gt;223&lt;/td&gt;
&lt;td&gt;249&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;354&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;242&lt;/td&gt;
&lt;td&gt;235&lt;/td&gt;
&lt;td&gt;232&lt;/td&gt;
&lt;td&gt;229&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shinjuku Granbell&lt;/td&gt;
&lt;td&gt;147&lt;/td&gt;
&lt;td&gt;145&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;228&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;117&lt;/td&gt;
&lt;td&gt;118&lt;/td&gt;
&lt;td&gt;133&lt;/td&gt;
&lt;td&gt;125&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The Saturday spike jumps out immediately: MIMARU +62% vs. Friday, Granbell +57%, Mitsui Garden +42% — while Keio Plaza barely moves. If you were pricing a hotel in this set, that's exactly the signal you'd want before the weekend fills up.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Which booking site is cheapest?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lowestOfferProvider&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;value_counts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cheapest site&lt;/th&gt;
&lt;th&gt;Hotel-nights&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;klook&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vio.com&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;KAYAK.com&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HyperAir.com&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;trivago DEALS&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Not Booking.com, not Expedia: a single OTA had the lowest price for &lt;strong&gt;18 of 35&lt;/strong&gt; hotel-nights. In 4 cases the hotel's own website was the cheapest.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Official site vs. the cheapest OTA (rate parity)
&lt;/h2&gt;

&lt;p&gt;Each offer has an &lt;code&gt;isOfficialSite&lt;/code&gt; flag, so comparing the direct price with the market takes two lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;officialSite&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;offers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;offs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pricePerNight&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;offs&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;isOfficialSite&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;officialVsCheapestPct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;officialSite&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lowestOfferPricePerNight&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Hotel Gracery Shinjuku:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Cheapest site&lt;/th&gt;
&lt;th&gt;Cheapest&lt;/th&gt;
&lt;th&gt;Official site&lt;/th&gt;
&lt;th&gt;Official vs. cheapest&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;11-12&lt;/td&gt;
&lt;td&gt;klook&lt;/td&gt;
&lt;td&gt;$176&lt;/td&gt;
&lt;td&gt;$225&lt;/td&gt;
&lt;td&gt;+27%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11-13&lt;/td&gt;
&lt;td&gt;Vio.com&lt;/td&gt;
&lt;td&gt;$226&lt;/td&gt;
&lt;td&gt;$292&lt;/td&gt;
&lt;td&gt;+29%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11-14&lt;/td&gt;
&lt;td&gt;klook&lt;/td&gt;
&lt;td&gt;$228&lt;/td&gt;
&lt;td&gt;$281&lt;/td&gt;
&lt;td&gt;+23%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11-15&lt;/td&gt;
&lt;td&gt;klook&lt;/td&gt;
&lt;td&gt;$191&lt;/td&gt;
&lt;td&gt;$215&lt;/td&gt;
&lt;td&gt;+13%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11-16&lt;/td&gt;
&lt;td&gt;Trip.com&lt;/td&gt;
&lt;td&gt;$191&lt;/td&gt;
&lt;td&gt;$215&lt;/td&gt;
&lt;td&gt;+13%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11-17&lt;/td&gt;
&lt;td&gt;klook&lt;/td&gt;
&lt;td&gt;$153&lt;/td&gt;
&lt;td&gt;$215&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+41%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11-18&lt;/td&gt;
&lt;td&gt;official site&lt;/td&gt;
&lt;td&gt;$225&lt;/td&gt;
&lt;td&gt;$225&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;On 6 of 7 nights someone undercut the direct rate, by up to 41%. (The official price was usually within a few dollars of Booking.com — the undercutting came from smaller OTAs.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One honest caveat:&lt;/strong&gt; sites don't always quote the same room type. In my data one hotel's official site showed $1,045 on a Saturday while the cheapest OTA was $228 — not a parity violation, just a much bigger room. For strict like-for-like checks, turn on &lt;code&gt;includeRooms&lt;/code&gt; and compare the same room name.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost
&lt;/h2&gt;

&lt;p&gt;The Actor charges per row: $0.004 per hotel-date with booking-site prices ($0.0015 without). This run was 35 rows → &lt;strong&gt;$0.14&lt;/strong&gt;. A month for 5 competitors (150 rows) is about $0.60, and you can schedule it to run every morning in Apify. Hotel-dates that Google doesn't show (e.g. sold out) come back as &lt;code&gt;priceStatus: "notListed"&lt;/code&gt; and aren't charged.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Don't build a competitor calendar from a city search — Google re-ranks per date and you'll get holes. Pin the hotels.&lt;/li&gt;
&lt;li&gt;"Cheapest site" is surprisingly concentrated; it's worth knowing which OTA that is in your market.&lt;/li&gt;
&lt;li&gt;Rate parity checks need a room-type sanity check before you send anyone an angry email.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I run datalume, the publisher of the &lt;a href="https://apify.com/datalume/google-hotels-scraper" rel="noopener noreferrer"&gt;Google Hotels Scraper&lt;/a&gt; Actor used here. Both the Actor and this article were built with AI assistance; every number comes from a real run on Oct 29, 2026 (Google Hotels, US) and was checked against the raw data. Questions welcome in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>webscraping</category>
      <category>datascience</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
