<?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: Hugues Ishema</title>
    <description>The latest articles on DEV Community by Hugues Ishema (@ishemah).</description>
    <link>https://dev.to/ishemah</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%2F4156904%2F0782e442-9e42-455b-9aa3-312db7483cbb.jpg</url>
      <title>DEV Community: Hugues Ishema</title>
      <link>https://dev.to/ishemah</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ishemah"/>
    <language>en</language>
    <item>
      <title>How to scrape any public Telegram channel without the API (no phone number, no login)</title>
      <dc:creator>Hugues Ishema</dc:creator>
      <pubDate>Fri, 02 Oct 2026 12:37:05 +0000</pubDate>
      <link>https://dev.to/ishemah/how-to-scrape-any-public-telegram-channel-without-the-api-no-phone-number-no-login-46ih</link>
      <guid>https://dev.to/ishemah/how-to-scrape-any-public-telegram-channel-without-the-api-no-phone-number-no-login-46ih</guid>
      <description>&lt;p&gt;There are two usual ways to read a Telegram channel from code, and both are annoying:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bot API:&lt;/strong&gt; a bot only sees posts from channels &lt;strong&gt;where it's an admin&lt;/strong&gt;, so it can't read someone else's channel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MTProto (Telethon / Pyrogram):&lt;/strong&gt; works, but needs an &lt;code&gt;api_id&lt;/code&gt;/&lt;code&gt;api_hash&lt;/code&gt; from my.telegram.org, which is tied to &lt;strong&gt;your phone number&lt;/strong&gt;. You also manage a logged-in session, and risk your account if you scrape hard.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's a third way that most people miss: &lt;strong&gt;every public channel has a web preview at &lt;code&gt;https://t.me/s/&amp;lt;channel&amp;gt;&lt;/code&gt;&lt;/strong&gt;. It's plain HTML, needs no login or account, and contains the full post text, date, view count, reactions, photos, videos and link previews.&lt;/p&gt;

&lt;p&gt;Here's how it works, a 30-line Python scraper, and the gotchas I ran into.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the preview works
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;https://t.me/s/durov&lt;/code&gt; returns the &lt;strong&gt;20 newest posts&lt;/strong&gt;, ordered oldest-first on the page.&lt;/li&gt;
&lt;li&gt;Each post is a &lt;code&gt;div.tgme_widget_message&lt;/code&gt; with &lt;code&gt;data-post="durov/548"&lt;/code&gt; (channel/ID).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Paging back:&lt;/strong&gt; &lt;code&gt;https://t.me/s/durov?before=528&lt;/code&gt; returns the 20 posts before ID 528.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search inside the channel:&lt;/strong&gt; &lt;code&gt;https://t.me/s/durov?q=privacy&lt;/code&gt; (it combines with &lt;code&gt;before&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Channel stats:&lt;/strong&gt; the right column (&lt;code&gt;.tgme_channel_info&lt;/code&gt;) has the title, description, subscriber count ("10.5M subscribers") and photo/video/link counts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Private channels, groups, bots and users have no preview.&lt;/strong&gt; The request redirects to &lt;code&gt;t.me/&amp;lt;name&amp;gt;&lt;/code&gt; instead of returning posts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Useful selectors inside a post:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Selector&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Text&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.tgme_widget_message_text&lt;/code&gt; (keep the &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt; as newlines)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Date&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.tgme_widget_message_date time[datetime]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Views&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.tgme_widget_message_views&lt;/code&gt; ("1.9M")&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reactions&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.tgme_reaction&lt;/code&gt; (emoji or custom-emoji ID plus count)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Photos&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.tgme_widget_message_photo_wrap&lt;/code&gt; (URL in &lt;code&gt;background-image&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Videos&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.tgme_widget_message_video_player video[src]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Link preview&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.tgme_widget_message_link_preview&lt;/code&gt; (title, description, image)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Forwarded from&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.tgme_widget_message_forwarded_from_name&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  A minimal scraper (Python)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;bs4&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BeautifulSoup&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;channel_posts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Newest-first posts from a public Telegram channel&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s web preview (t.me/s/&amp;lt;channel&amp;gt;).&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://t.me/s/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;?before=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&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;User-Agent&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;Mozilla/5.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;
        &lt;span class="n"&gt;soup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BeautifulSoup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;html.parser&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.tgme_widget_message[data-post]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;reversed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;  &lt;span class="c1"&gt;# the page is oldest-first
&lt;/span&gt;            &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.tgme_widget_message_text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;views&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.tgme_widget_message_views&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data-post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.tgme_widget_message_date time&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;datetime&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;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="k"&gt;else&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;views&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;views&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;views&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&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;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# be polite
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;limit&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;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;channel_posts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;durov&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;)[:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;views&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][:&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&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; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output today:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;548 2026-09-11T16:04:02+00:00 1.9M 🤝 Telegram has become the sponsor of Codeforces — the larges
547 2026-09-06T17:40:39+00:00 2.81M 💸 In just one month, Telegram has awarded over $2,222,000 to
546 2026-08-31T16:30:15+00:00 3.18M 🏳️ Gram Wallet in Telegram is ready and is now accessible to
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Gotchas
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use the right &lt;code&gt;&amp;lt;time&amp;gt;&lt;/code&gt;.&lt;/strong&gt; Video posts contain other &lt;code&gt;&amp;lt;time&amp;gt;&lt;/code&gt; tags (durations), so a bare &lt;code&gt;select_one("time")["datetime"]&lt;/code&gt; crashes. Use &lt;code&gt;.tgme_widget_message_date time&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Views are rounded strings&lt;/strong&gt; ("1.9M", "14.3K"). Convert them before you sort or sum.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reactions can be custom emoji.&lt;/strong&gt; These have an &lt;code&gt;emoji-id&lt;/code&gt; instead of a Unicode character. Store the ID.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Message IDs have gaps&lt;/strong&gt; where posts were deleted. Page with &lt;code&gt;before=&amp;lt;smallest ID you have&amp;gt;&lt;/code&gt;, not &lt;code&gt;before=id-20&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Media URLs expire.&lt;/strong&gt; Photo and video links point to Telegram's CDN with tokens, so download during the run if you need them later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Some media isn't rendered&lt;/strong&gt; in the web preview (certain polls and stickers). The post still has its date, views and usually the text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stop by date, not by count&lt;/strong&gt;, when you only need recent posts. Check each post's date and break as soon as you pass your cutoff, instead of paging the whole history.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  If you don't want to maintain it
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I built this.&lt;/em&gt; The &lt;a href="https://apify.com/kuezi/telegram-channel-scraper" rel="noopener noreferrer"&gt;Telegram Channel Scraper on Apify&lt;/a&gt; does all of the above and returns clean JSON or CSV:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;views as numbers, reactions, photos, videos, documents, link previews, forwards, replies, polls, hashtags and mentions;&lt;/li&gt;
&lt;li&gt;channel stats;&lt;/li&gt;
&lt;li&gt;search inside channels, date filters, and a &lt;strong&gt;monitoring mode&lt;/strong&gt; that returns only new posts since the last run.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It costs &lt;strong&gt;$0.50 per 1,000 posts&lt;/strong&gt;, with no login and no proxy needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"channels"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"durov"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://t.me/telegram"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxMessagesPerChannel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dateFrom"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-01-01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"onlyNewMessages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Happy to answer questions about edge cases in the comments.&lt;/p&gt;

</description>
      <category>python</category>
      <category>webscraping</category>
      <category>telegram</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Booking.com ran ~40x more Google ads than Expedia last month. I pulled the ad counts for 8 travel brands.</title>
      <dc:creator>Hugues Ishema</dc:creator>
      <pubDate>Fri, 02 Oct 2026 12:33:42 +0000</pubDate>
      <link>https://dev.to/ishemah/bookingcom-ran-40x-more-google-ads-than-expedia-last-month-i-pulled-the-ad-counts-for-8-travel-40no</link>
      <guid>https://dev.to/ishemah/bookingcom-ran-40x-more-google-ads-than-expedia-last-month-i-pulled-the-ad-counts-for-8-travel-40no</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; I pulled Google's own ad counts for 8 travel brands from the &lt;strong&gt;Google Ads Transparency Center&lt;/strong&gt;: every ad shown in the &lt;strong&gt;US over the last 30 days&lt;/strong&gt; (2 Sep – 2 Oct 2026), split by platform and format.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Booking.com showed ~300k–400k distinct ads, about 40× Expedia (8k–9k).&lt;/strong&gt; Tripadvisor and Priceline were at 100k–200k each, and Kayak at 50k–60k.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Booking.com is almost entirely Search text ads.&lt;/strong&gt; It ran just &lt;strong&gt;29 video ads&lt;/strong&gt;. &lt;strong&gt;Expedia ran 2k–3k&lt;/strong&gt;, about 90× more, and Priceline ran &lt;strong&gt;none&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Booking.com also ran 20k–30k ads on Google Maps.&lt;/strong&gt; Kayak ran 0 there.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expedia Group refreshes its ads; Booking.com and Kayak barely do.&lt;/strong&gt; Among the first 400 ads Google lists for each brand, the number launched in the last 30 days was 84 for Vrbo, 71 for Hotels.com, 58 for Expedia, 1 for Booking.com and 0 for Kayak.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9rjet82ccztvjf2w57pw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9rjet82ccztvjf2w57pw.png" alt="Distinct Google ads shown in the US in 30 days" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Brand&lt;/th&gt;
&lt;th&gt;All ads (US, 30 days)&lt;/th&gt;
&lt;th&gt;Google Search&lt;/th&gt;
&lt;th&gt;YouTube*&lt;/th&gt;
&lt;th&gt;Google Maps&lt;/th&gt;
&lt;th&gt;Video format&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Booking.com&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;300k–400k&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;300k–400k&lt;/td&gt;
&lt;td&gt;90k–100k&lt;/td&gt;
&lt;td&gt;20k–30k&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;29&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tripadvisor&lt;/td&gt;
&lt;td&gt;100k–200k&lt;/td&gt;
&lt;td&gt;100k–200k&lt;/td&gt;
&lt;td&gt;10k–20k&lt;/td&gt;
&lt;td&gt;4k–5k&lt;/td&gt;
&lt;td&gt;100–200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Priceline&lt;/td&gt;
&lt;td&gt;100k–200k&lt;/td&gt;
&lt;td&gt;100k–200k&lt;/td&gt;
&lt;td&gt;30k–40k&lt;/td&gt;
&lt;td&gt;8k–9k&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kayak&lt;/td&gt;
&lt;td&gt;50k–60k&lt;/td&gt;
&lt;td&gt;50k–60k&lt;/td&gt;
&lt;td&gt;10k–20k&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;36&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Airbnb&lt;/td&gt;
&lt;td&gt;30k–40k&lt;/td&gt;
&lt;td&gt;30k–40k&lt;/td&gt;
&lt;td&gt;10k–20k&lt;/td&gt;
&lt;td&gt;100–200&lt;/td&gt;
&lt;td&gt;500–600&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vrbo&lt;/td&gt;
&lt;td&gt;9k–10k&lt;/td&gt;
&lt;td&gt;8k–9k&lt;/td&gt;
&lt;td&gt;700–800&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;600–700&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Expedia&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;8k–9k&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;5k–6k&lt;/td&gt;
&lt;td&gt;3k–4k&lt;/td&gt;
&lt;td&gt;800–900&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2k–3k&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hotels.com&lt;/td&gt;
&lt;td&gt;1k–2k&lt;/td&gt;
&lt;td&gt;900–1k&lt;/td&gt;
&lt;td&gt;400–500&lt;/td&gt;
&lt;td&gt;200–300&lt;/td&gt;
&lt;td&gt;400–500&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;* "YouTube" counts every ad shown on YouTube, including text ads in YouTube search. That's why it's much bigger than the video column.&lt;/p&gt;

&lt;p&gt;Google Shopping was small for everyone (25 ads or fewer per brand), and &lt;strong&gt;none of the 8 ran Google Play ads&lt;/strong&gt; in the US in this window.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi7dfnmavfuexzz3rdq80.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi7dfnmavfuexzz3rdq80.png" alt="Video ads by brand" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What stands out
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Booking.com plays a Search-volume game.&lt;/strong&gt; Hundreds of thousands of distinct text ads usually means programmatic ads: one per destination, hotel or search phrase. The few headlines I could read look templated, for example "Book Now, Change Later" and "Book for Tonight".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Expedia plays a video game.&lt;/strong&gt; Expedia had about 90× more video ads than Booking.com, and its sister brands Vrbo and Hotels.com lean on video too. Airbnb is the only other brand with hundreds of videos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Ads that never die.&lt;/strong&gt; Among the first 400 ads Google lists for Booking.com, half were first shown in January 2022 or earlier, and they were still running on 2 Oct 2026. The archive's earliest "first shown" dates are in October 2021, so many are probably older still. For Expedia, the median listed ad was about 7 months old.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Maps is a real channel for some brands and ignored by others.&lt;/strong&gt; Booking.com (20k–30k), Priceline (8k–9k) and Tripadvisor (4k–5k) advertise heavily on Google Maps. Kayak and Vrbo almost don't.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Pricing hooks are everywhere.&lt;/strong&gt; Priceline: "$39+ Room Deals - Last Minute Rooms". Tripadvisor: "The 10 Best Hotels (2026) - … Special Offer: Now From $58".&lt;/p&gt;

&lt;h2&gt;
  
  
  How I did it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Source:&lt;/strong&gt; the &lt;a href="https://adstransparency.google.com/" rel="noopener noreferrer"&gt;Google Ads Transparency Center&lt;/a&gt;, Google's public database of every ad from verified advertisers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filters:&lt;/strong&gt; country United States, ads shown from 2 Sep to 2 Oct 2026, one website at a time (&lt;code&gt;booking.com&lt;/code&gt;, &lt;code&gt;expedia.com&lt;/code&gt;, …). I repeated the query for each platform (Search, YouTube, Maps, Shopping, Play) and each format (text, image, video).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Counts:&lt;/strong&gt; these are the ad counts Google itself reports for each filter, which come as &lt;strong&gt;ranges&lt;/strong&gt; (e.g. "300000–400000"). They count &lt;strong&gt;distinct ads (creatives), not impressions or spend&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ad-level sample:&lt;/strong&gt; the first 400 ads Google lists per brand (3,200 in total), used for "first shown" dates and the new-ad counts. This sample follows Google's order, so it isn't random.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open data:&lt;/strong&gt; both CSVs (counts per brand × platform/format, plus the 3,200 ad records) are in &lt;a href="https://github.com/ISHEMAH/travel-price-studies" rel="noopener noreferrer"&gt;github.com/ISHEMAH/travel-price-studies&lt;/a&gt;, under CC BY 4.0.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Caveats
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Counts are not spend.&lt;/strong&gt; A brand with 300k programmatic text ads may spend less than one with 3k videos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A website search returns every advertiser that ran ads for that domain.&lt;/strong&gt; That's mostly the brand itself, plus a few resellers or partners (e.g. 13 different advertisers for airbnb.com, 386 of the 400 sampled ads from Airbnb, Inc.).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One country, one 30-day window, one collection day.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ad text is only partly available.&lt;/strong&gt; Google archives many text ads as images, so only some ads expose readable copy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Reproduce it (or watch your own competitors)
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I built the tool I used.&lt;/em&gt; It's the &lt;a href="https://apify.com/kuezi/google-ads-transparency-scraper" rel="noopener noreferrer"&gt;Google Ads Transparency Scraper on Apify&lt;/a&gt;. Give it advertiser names, IDs or websites, and it returns every ad with format, first and last shown, preview, link, and (optionally) the ad text, landing pages and YouTube video. It costs $1 per 1,000 ads.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"searchTargets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"booking.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"expedia.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"airbnb.com"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"country"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"US"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"platform"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"youtube"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lastDays"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxAdsPerTarget"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"includeAdDetails"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# pip install apify-client
&lt;/span&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="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;YOUR_APIFY_TOKEN&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&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;kuezi/google-ads-transparency-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="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;searchTargets&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;your-competitor.com&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;country&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;US&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;lastDays&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;onlyNewAds&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="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ad&lt;/span&gt; &lt;span class="ow"&gt;in&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;defaultDatasetId&lt;/span&gt;&lt;span class="sh"&gt;"&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;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ad&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;format&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;ad&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;firstShown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;ad&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;adUrl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it daily with &lt;code&gt;onlyNewAds: true&lt;/code&gt; and you get a feed of every new ad your competitors launch.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;More open travel data from the same tools:&lt;/em&gt; &lt;a href="https://dev.to/ishemah/i-compared-24-booking-sites-on-47-hotels-bookingcom-expedia-and-hotelscom-were-26-above-the-4egk"&gt;24 booking sites compared on 47 hotels&lt;/a&gt; · &lt;a href="https://dev.to/ishemah/i-priced-150-flights-across-november-tuesday-was-the-cheapest-day-to-fly-friday-cost-20-more-3i7i"&gt;the cheapest day to fly&lt;/a&gt;&lt;/p&gt;

</description>
      <category>marketing</category>
      <category>webscraping</category>
      <category>datascience</category>
      <category>seo</category>
    </item>
    <item>
      <title>I priced 150 flights across November. Tuesday was the cheapest day to fly, Friday cost 20% more.</title>
      <dc:creator>Hugues Ishema</dc:creator>
      <pubDate>Fri, 02 Oct 2026 11:00:48 +0000</pubDate>
      <link>https://dev.to/ishemah/i-priced-150-flights-across-november-tuesday-was-the-cheapest-day-to-fly-friday-cost-20-more-3i7i</link>
      <guid>https://dev.to/ishemah/i-priced-150-flights-across-november-tuesday-was-the-cheapest-day-to-fly-friday-cost-20-more-3i7i</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; 5 routes × every departure day in November 2026, cheapest one-way economy fare from Google Flights. Prices were seen on 2 Oct 2026.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tuesday was the cheapest day&lt;/strong&gt; to depart, &lt;strong&gt;−5%&lt;/strong&gt; vs the route's typical price. Monday and Wednesday were close behind (−3%, −2%).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Friday was the most expensive, +20%.&lt;/strong&gt; Saturday and Sunday were both about +13%.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Picking the wrong day cost up to 2.7×:&lt;/strong&gt; San Francisco → Honolulu was &lt;strong&gt;$163&lt;/strong&gt; on the cheapest day and &lt;strong&gt;$444&lt;/strong&gt; on the priciest.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Sunday after Thanksgiving (29 Nov)&lt;/strong&gt; was the most expensive day of the month on New York → LA ($489 vs $184 at best) and on Chicago → Miami ($195 vs $113).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F17ulb9tstbhp5tw6rha7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F17ulb9tstbhp5tw6rha7.png" alt="Tuesday was the cheapest day to fly, Friday cost 20% more than the route's typical price" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The routes
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Route&lt;/th&gt;
&lt;th&gt;Cheapest day&lt;/th&gt;
&lt;th&gt;Priciest day&lt;/th&gt;
&lt;th&gt;Spread&lt;/th&gt;
&lt;th&gt;Google's "price level" on most days&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;New York JFK → Los Angeles&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;$184&lt;/strong&gt; (Fri 6, Mon 16, Thu 19)&lt;/td&gt;
&lt;td&gt;$489 (Sun 29)&lt;/td&gt;
&lt;td&gt;+166%&lt;/td&gt;
&lt;td&gt;typical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;London LHR → New York JFK&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;$399&lt;/strong&gt; (14 different days from 11 Nov)&lt;/td&gt;
&lt;td&gt;$641 (Sun 1)&lt;/td&gt;
&lt;td&gt;+61%&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;low&lt;/strong&gt; on 21 of 30 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Chicago ORD → Miami&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;$113&lt;/strong&gt; (Sat 14)&lt;/td&gt;
&lt;td&gt;$195 (Sun 29)&lt;/td&gt;
&lt;td&gt;+73%&lt;/td&gt;
&lt;td&gt;typical / high&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;San Francisco → Honolulu&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;$163&lt;/strong&gt; (12 different days, every one a Sun–Wed)&lt;/td&gt;
&lt;td&gt;$444 (Fri 20)&lt;/td&gt;
&lt;td&gt;+172%&lt;/td&gt;
&lt;td&gt;low / typical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Los Angeles → Tokyo NRT&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;$329&lt;/strong&gt; (Wed 25)&lt;/td&gt;
&lt;td&gt;$823 (Fri 20)&lt;/td&gt;
&lt;td&gt;+150%&lt;/td&gt;
&lt;td&gt;typical&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbyc9by6ja0r5702eymwd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbyc9by6ja0r5702eymwd.png" alt="Cheapest vs priciest day in November on each route" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How I did it
&lt;/h2&gt;

&lt;p&gt;For each route I searched every departure date from 1 to 30 November: &lt;strong&gt;150 searches&lt;/strong&gt; in total, one-way, economy, 1 adult, USD, US point of sale. I took the cheapest itinerary per search.&lt;/p&gt;

&lt;p&gt;The weekday numbers compare each day's cheapest fare with &lt;strong&gt;that route's median&lt;/strong&gt; over the month, then average across the 5 routes. A $300 route and a $100 route count equally.&lt;/p&gt;

&lt;p&gt;Google also labels prices as &lt;em&gt;low&lt;/em&gt;, &lt;em&gt;typical&lt;/em&gt; or &lt;em&gt;high&lt;/em&gt; against its own history. I recorded that label too: London → New York was "low" on 21 of 30 days.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;All the data and the analysis script are open:&lt;/strong&gt; &lt;a href="https://github.com/ISHEMAH/travel-price-studies" rel="noopener noreferrer"&gt;github.com/ISHEMAH/travel-price-studies&lt;/a&gt; (CSV, CC BY 4.0). &lt;code&gt;python3 analysis.py&lt;/code&gt; reproduces every number in this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caveats
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Five routes and one month&lt;/strong&gt;, and November includes US Thanksgiving. Read it as a strong hint, not a law.&lt;/li&gt;
&lt;li&gt;Prices were seen on &lt;strong&gt;one day&lt;/strong&gt; (2 Oct). Fares change as departure gets closer.&lt;/li&gt;
&lt;li&gt;Cheapest fares are often basic economy, so check bags and seat rules.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Practical takeaway
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Be flexible by a day or two.&lt;/strong&gt; Use a date grid, because the difference can be bigger than any coupon.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoid Friday and Sunday departures&lt;/strong&gt; when you can, especially around holidays.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch Google's price level.&lt;/strong&gt; When it says &lt;em&gt;low&lt;/em&gt;, that's usually your moment.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Reproduce it (or scan your own route)
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I built the scraper I used.&lt;/em&gt; It's the &lt;a href="https://apify.com/kuezi/google-flights-scraper" rel="noopener noreferrer"&gt;Google Flights Scraper on Apify&lt;/a&gt;. Set &lt;code&gt;scanDepartureUntil&lt;/code&gt; and it searches every day in the range, then reports the &lt;strong&gt;cheapest day per route&lt;/strong&gt; in &lt;code&gt;SUMMARY&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"routes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"JFK-LAX"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"LHR-JFK"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ORD-MIA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SFO-HNL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"LAX-NRT"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"departureDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-11-01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scanDepartureUntil"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-11-30"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxFlightsPerSearch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# pip install apify-client
&lt;/span&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="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;routes&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;JFK-LAX&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;departureDate&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-01&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;scanDepartureUntil&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-30&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;maxFlightsPerSearch&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;}&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;YOUR_APIFY_TOKEN&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&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;kuezi/google-flights-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;summary&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;key_value_store&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;defaultKeyValueStoreId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;get_record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SUMMARY&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;value&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;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cheapestByRoute&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;route&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cheapestPrice&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;on&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;departureDate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Schedule it weekly and you have a fare-drop alert for your own trips.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Same method, hotels:&lt;/em&gt; &lt;a href="https://dev.to/ishemah/i-compared-24-booking-sites-on-47-hotels-bookingcom-expedia-and-hotelscom-were-26-above-the-4egk"&gt;I compared 24 booking sites on 47 hotels. Booking.com, Expedia and Hotels.com were ~26% above the cheapest.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Update: robustness check (thanks to a reader)
&lt;/h2&gt;

&lt;p&gt;A reader pointed out that November has only four Fridays, and two of them sit in the Thanksgiving window. Rerunning the same method on &lt;strong&gt;1–19 Nov only&lt;/strong&gt;: Mon −5.2%, Tue −2.8%, Wed +2.1%, Thu +10.2%, &lt;strong&gt;Fri +13.9%&lt;/strong&gt;, Sat +7.6%, Sun +5.2%.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The holiday inflated the headline: Friday falls from +19.7% to +13.9%, and Sunday from +12.7% to +5.2%.&lt;/li&gt;
&lt;li&gt;Monday edges out Tuesday as the cheapest day.&lt;/li&gt;
&lt;li&gt;Friday is still the priciest, but that rests on just 2 Fridays × 5 routes. Treat it as a hint, not a rule. A non-holiday month is the next run.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>travel</category>
      <category>webscraping</category>
      <category>datascience</category>
      <category>python</category>
    </item>
    <item>
      <title>I compared 24 booking sites on 47 hotels. Booking.com, Expedia and Hotels.com were ~26% above the cheapest.</title>
      <dc:creator>Hugues Ishema</dc:creator>
      <pubDate>Fri, 02 Oct 2026 09:37:38 +0000</pubDate>
      <link>https://dev.to/ishemah/i-compared-24-booking-sites-on-47-hotels-bookingcom-expedia-and-hotelscom-were-26-above-the-4egk</link>
      <guid>https://dev.to/ishemah/i-compared-24-booking-sites-on-47-hotels-bookingcom-expedia-and-hotelscom-were-26-above-the-4egk</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; 47 hotels in 5 cities, 24 booking sites per hotel on average, same dates for all (12–15 Nov 2026, 3 nights, 2 adults, USD).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;big names were a median 26–27% more expensive&lt;/strong&gt; than the cheapest site for the &lt;em&gt;same&lt;/em&gt; hotel: Booking.com +27%, Priceline +27%, Expedia +26%, Hotels.com +26%.&lt;/li&gt;
&lt;li&gt;The cheapest offer usually came from &lt;strong&gt;smaller sites&lt;/strong&gt;: Super.com, Vio.com and Traveluro were cheapest on 9 hotels each.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Checking Expedia, Hotels.com, Orbitz, Travelocity and CheapTickets is one check, not five.&lt;/strong&gt; They showed the exact same price on 37 of 45 hotels (all Expedia Group).&lt;/li&gt;
&lt;li&gt;The hotel's &lt;strong&gt;own website&lt;/strong&gt; was the cheapest on only &lt;strong&gt;4 of 34&lt;/strong&gt; hotels where I could identify it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google's headline price matched the cheapest site 42 times out of 47.&lt;/strong&gt; It's a good reference if you only look at one number.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbo27shwd77ee2m8k531h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbo27shwd77ee2m8k531h.png" alt="Same room, same dates: the big booking sites cost about 26% more than the cheapest one" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How I did it
&lt;/h2&gt;

&lt;p&gt;Google Hotels shows a "Prices" list for each hotel: every booking site it has a rate from. I pulled that list for the top 10 hotels Google returned in &lt;strong&gt;Paris, London, New York, Barcelona and Bangkok&lt;/strong&gt;, all for the same stay. Then for each hotel I compared every site's &lt;strong&gt;total price for the stay&lt;/strong&gt; with the cheapest one.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Point of sale: US (&lt;code&gt;gl=us&lt;/code&gt;), currency USD, collected on &lt;strong&gt;2 Oct 2026&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;50 hotels requested. 47 had at least two sites listed, which gives 24.4 sites per hotel on average.&lt;/li&gt;
&lt;li&gt;"Premium" = (site's total − cheapest total) / cheapest total, for the same hotel. The median is taken across hotels.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;All the data and the analysis script are open:&lt;/strong&gt; &lt;a href="https://github.com/ISHEMAH/travel-price-studies" rel="noopener noreferrer"&gt;github.com/ISHEMAH/travel-price-studies&lt;/a&gt; (CSV, CC BY 4.0). &lt;code&gt;python3 analysis.py&lt;/code&gt; reproduces every number in this post.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I found
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Site&lt;/th&gt;
&lt;th&gt;Hotels it was listed on&lt;/th&gt;
&lt;th&gt;Median premium vs cheapest&lt;/th&gt;
&lt;th&gt;Times it &lt;em&gt;was&lt;/em&gt; the cheapest&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Super.com&lt;/td&gt;
&lt;td&gt;36&lt;/td&gt;
&lt;td&gt;+8.5%&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kiwi.com&lt;/td&gt;
&lt;td&gt;33&lt;/td&gt;
&lt;td&gt;+12.7%&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trip.com&lt;/td&gt;
&lt;td&gt;36&lt;/td&gt;
&lt;td&gt;+21.9%&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hotels.com&lt;/td&gt;
&lt;td&gt;45&lt;/td&gt;
&lt;td&gt;+25.8%&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Expedia&lt;/td&gt;
&lt;td&gt;45&lt;/td&gt;
&lt;td&gt;+26.4%&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Priceline&lt;/td&gt;
&lt;td&gt;43&lt;/td&gt;
&lt;td&gt;+26.8%&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Booking.com&lt;/td&gt;
&lt;td&gt;43&lt;/td&gt;
&lt;td&gt;+27.2%&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;eDreams&lt;/td&gt;
&lt;td&gt;33&lt;/td&gt;
&lt;td&gt;+27.7%&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;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fun5ja3yer8rec1ryacxu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fun5ja3yer8rec1ryacxu.png" alt="Three things worth knowing before you book a hotel" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The gap between the cheapest and the priciest site for the same room was big:&lt;/strong&gt; median &lt;strong&gt;67%&lt;/strong&gt;, ranging from New York (41%) to London (98%) and Bangkok (116%).&lt;/p&gt;

&lt;h2&gt;
  
  
  Caveats (read these before you book the cheapest one)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cheapest isn't always best.&lt;/strong&gt; Smaller sites can mean stricter cancellation rules, member-only rates, or fees added at checkout. Check the refund policy and the final price before paying.&lt;/li&gt;
&lt;li&gt;This is &lt;strong&gt;one stay window, five cities, one day of prices&lt;/strong&gt;. Rates move hourly, and other dates or countries can look different.&lt;/li&gt;
&lt;li&gt;I compared the prices exactly as Google listed them. I didn't book anything.&lt;/li&gt;
&lt;li&gt;"The hotel's own site" was matched by name, so a few may be missed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Practical takeaway
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open the hotel on Google Hotels and look at the &lt;strong&gt;whole&lt;/strong&gt; price list, not the first logo.&lt;/li&gt;
&lt;li&gt;Skip comparing Expedia vs Hotels.com vs Orbitz vs Travelocity: they're almost always the same price.&lt;/li&gt;
&lt;li&gt;If a smaller site is much cheaper, check its reviews and refund policy, then decide whether the saving is worth it.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Reproduce it (or track your own hotels)
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I built the scraper I used.&lt;/em&gt; It's the &lt;a href="https://apify.com/kuezi/google-hotels-scraper" rel="noopener noreferrer"&gt;Google Hotels Scraper on Apify&lt;/a&gt;. With &lt;code&gt;includeVendorPrices&lt;/code&gt; turned on, it returns every booking site's price for your dates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"queries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Paris"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"London"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"New York"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Barcelona"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bangkok"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"checkInDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-11-12"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"checkOutDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-11-15"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"adults"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxResultsPerQuery"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"includeVendorPrices"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# pip install apify-client
&lt;/span&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="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;queries&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;Lisbon&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;checkInDate&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;checkOutDate&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-15&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;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;maxResultsPerQuery&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;includeVendorPrices&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="p"&gt;}&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;YOUR_APIFY_TOKEN&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&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;kuezi/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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;hotel&lt;/span&gt; &lt;span class="ow"&gt;in&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;defaultDatasetId&lt;/span&gt;&lt;span class="sh"&gt;"&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;span class="n"&gt;prices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vendor&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;totalPrice&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;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;hotel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vendorPrices&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="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;low&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hotel&lt;/span&gt;&lt;span class="p"&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="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;+&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;low&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;low&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Schedule it daily and you have a rate-shopping tracker.&lt;/p&gt;

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