<?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: Sonika Arora</title>
    <description>The latest articles on DEV Community by Sonika Arora (@sonika_serpapi).</description>
    <link>https://dev.to/sonika_serpapi</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%2F3346383%2F8399a4f8-58d2-491f-88e9-8e28753d8a5a.jpg</url>
      <title>DEV Community: Sonika Arora</title>
      <link>https://dev.to/sonika_serpapi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sonika_serpapi"/>
    <language>en</language>
    <item>
      <title>Turn Bing News into an AI Briefing with Claude and SerpApi</title>
      <dc:creator>Sonika Arora</dc:creator>
      <pubDate>Tue, 30 Jun 2026 07:06:28 +0000</pubDate>
      <link>https://dev.to/serpapi/turn-bing-news-into-an-ai-briefing-with-claude-and-serpapi-3ma1</link>
      <guid>https://dev.to/serpapi/turn-bing-news-into-an-ai-briefing-with-claude-and-serpapi-3ma1</guid>
      <description>&lt;p&gt;Most news apps and search engines already present headlines well, so simply listing them is becoming less valuable. The real value has shifted to connecting the dots: grouping related news stories, identifying patterns across sources, and explaining what actually matters and why.&lt;/p&gt;

&lt;p&gt;In this post, we’ll build a simple pipeline that turns raw Bing News results into a structured daily briefing which does exactly that using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SerpApi's Bing News API for real-time news data&lt;/li&gt;
&lt;li&gt;Claude for summarization and insight generation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting Up
&lt;/h2&gt;

&lt;p&gt;LLMs work best when you give them clean, formatted context instead of raw scraped HTML, so we'll do exactly that.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Get results using SerpApi (Bing News API) → Normalize → Send to Claude with a relevant prompt → Get structured briefing&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For this tutorial, we're going to use SerpApi's&amp;nbsp;&lt;a href="https://github.com/serpapi/serpapi-python" rel="noopener noreferrer"&gt;new Python library&lt;/a&gt;&amp;nbsp;to get results from search.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install SerpApi's new Python&amp;nbsp;&lt;a href="https://serpapi.com/integrations/python" rel="noopener noreferrer"&gt;&lt;code&gt;serpapi&lt;/code&gt;&amp;nbsp;library&lt;/a&gt;, the&amp;nbsp;&lt;a href="https://pypi.org/project/python-dotenv/" rel="noopener noreferrer"&gt;python-dotenv&lt;/a&gt;&amp;nbsp;library (for using environment variables) and &lt;a href="https://github.com/anthropics/anthropic-sdk-python" rel="noopener noreferrer"&gt;&lt;code&gt;anthropic&lt;/code&gt; library&lt;/a&gt; (for Claude) in your environment:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;serpapi python-dotenv anthropic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;serpapi&lt;/code&gt;_&amp;nbsp;_is our new Python library. You can use this library to scrape search results from any of SerpApi's APIs.&lt;/p&gt;
&lt;h4&gt;
  
  
  More About Our Python Libraries
&lt;/h4&gt;

&lt;p&gt;We have two separate Python libraries &lt;a href="https://github.com/serpapi/serpapi-python" rel="noopener noreferrer"&gt;&lt;code&gt;serpapi&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/serpapi/google-search-results-python" rel="noopener noreferrer"&gt;&lt;code&gt;google-search-results&lt;/code&gt;&lt;/a&gt;, and both work perfectly fine. We are in the process of deprecating &lt;a href="https://github.com/serpapi/google-search-results-python" rel="noopener noreferrer"&gt;&lt;code&gt;google-search-results&lt;/code&gt;&lt;/a&gt;, so I recommend using &lt;code&gt;serpapi&lt;/code&gt; as that is our latest python library.&lt;/p&gt;

&lt;p&gt;You may encounter issues if you have both libraries installed at the same time. If you have the old library installed and want to proceed with using our new library, please follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Uninstall&amp;nbsp;&lt;code&gt;google-search-results&lt;/code&gt;&amp;nbsp;module from your environment.&lt;/li&gt;
&lt;li&gt;Make sure that neither&amp;nbsp;&lt;code&gt;serpapi&lt;/code&gt;&amp;nbsp;nor&amp;nbsp;&lt;code&gt;google-search-results&lt;/code&gt;&amp;nbsp;are installed at that stage.&lt;/li&gt;
&lt;li&gt;Install&amp;nbsp;&lt;code&gt;serpapi&lt;/code&gt;&amp;nbsp;module, for example with the following command if you're using&amp;nbsp;&lt;code&gt;pip&lt;/code&gt;: &lt;code&gt;pip install serpapi&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;To begin scraping data, create a&amp;nbsp;&lt;a href="https://serpapi.com/users/sign_up" rel="noopener noreferrer"&gt;free account on serpapi.com&lt;/a&gt;. You'll receive 250 free search credits each month to explore the API. Get your SerpApi API key from&amp;nbsp;&lt;a href="https://serpapi.com/manage-api-key" rel="noopener noreferrer"&gt;this page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[Optional but Recommended] Set your API keys in an environment variable, instead of directly pasting them in the code. Refer&amp;nbsp;&lt;a href="https://developer.vonage.com/en/blog/python-environment-variables-a-primer" rel="noopener noreferrer"&gt;here&lt;/a&gt;&amp;nbsp;to understand more about using environment variables.&lt;/p&gt;

&lt;p&gt;SERPAPI_API_KEY=&lt;br&gt;
CLAUDE_API_KEY=&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Get your SerpApi API key here: &lt;a href="https://serpapi.com/manage-api-key" rel="noopener noreferrer"&gt;https://serpapi.com/manage-api-key&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Get your Claude API key here: &lt;a href="https://platform.claude.com/settings/keys" rel="noopener noreferrer"&gt;https://platform.claude.com/settings/keys&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 You'll need to create an account with Claude in case you don't have one yet. You can do that here: &lt;a href="https://claude.ai/login" rel="noopener noreferrer"&gt;https://claude.ai/login&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Import classes needed for this project at the beginning of your code file and set up some constants we'll use later on:
&lt;/li&gt;
&lt;/ol&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;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;serpapi&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;anthropic&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;
&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;SERPAPI_API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SERPAPI_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;CLAUDE_API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CLAUDE_API_KEY&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;h2&gt;
  
  
  Fetch News with Bing News API
&lt;/h2&gt;

&lt;p&gt;We’ll write a function to use SerpApi’s Bing News API (&lt;code&gt;bing_news&lt;/code&gt; engine) and get all the news results.&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch_news&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&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="n"&gt;serpapi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;SERPAPI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;results&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;search&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;engine&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;bing_news&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;q&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;device&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;desktop&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;mkt&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;en-au&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;results&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;organic_results&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can call this function with any query such as "Self driving software" or "AI" and scrape results from Bing News.&lt;/p&gt;

&lt;p&gt;You can test the Bing News API out in our playground with parameters of your choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/playground?engine=bing_news&amp;amp;q=AI&amp;amp;mkt=en-us" rel="noopener noreferrer"&gt;SerpApi Playground - SerpApi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prompting Claude
&lt;/h2&gt;

&lt;p&gt;Good prompts can make all the difference when building a AI briefing based on the results.&lt;/p&gt;

&lt;p&gt;A bad prompt would look like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Summarize these articles”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Better prompts often define structure, force grouping, and require reasoning.&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;build_prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;articles&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&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;
You are a technical news analyst.

Task: Convert raw news articles into a structured daily briefing.

Requirements:
- Group related articles into 3-5 themes
- Each theme must have:
  - A short title
  - A 2-3 sentence summary
  - A &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Why it matters&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; explanation
- Be concise and non-generic
- Avoid repeating the same point across themes

Articles:
&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;articles&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Generate the Briefing (Claude API)
&lt;/h2&gt;

&lt;p&gt;Using Claude's API, we can turn the data we got from SerpApi into a briefing. Here is some simple code to use Anthropic API -&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_briefing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&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="n"&gt;anthropic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Anthropic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;CLAUDE_API_KEY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&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="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude-opus-4-7&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;messages&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;role&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;user&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;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&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;span class="n"&gt;text&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Putting It Together
&lt;/h2&gt;

&lt;p&gt;Now that we have all the pieces we'll use, let's write the code to call the different functions and get our news briefing:&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AI&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;articles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fetch_news&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;build_prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;articles&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;briefing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_briefing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&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;briefing&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;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; __main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we're ready to run this file. We can do so by typing &lt;code&gt;python &amp;lt;filename&amp;gt;&lt;/code&gt; in the terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automated Delivery
&lt;/h2&gt;

&lt;p&gt;A briefing is only useful if it reaches you regularly automatically. Add a delivery layer like automated daily email or a slack webhook.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automated Daily Email&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simple automation run daily via cron or other scheduling methods&lt;/li&gt;
&lt;li&gt;Email formatted briefing to yourself or a team&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Slack Webhook&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Post structured sections into a channel&lt;/li&gt;
&lt;li&gt;Good for teams or shared awareness feeds&lt;/li&gt;
&lt;li&gt;Enables discussion around themes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Read this blog post for more info on setting up a Slack webhook (The use case in the post is different, but the process remains the same). It also covers how to schedule a job every day using the Python&amp;nbsp;&lt;a href="https://schedule.readthedocs.io/en/stable/" rel="noopener noreferrer"&gt;schedule&lt;/a&gt;&amp;nbsp;library:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/blog/build-a-slack-bot-that-alerts-you-when-a-new-company-ranks-for-keywords/" rel="noopener noreferrer"&gt;Build a Slack Bot That Alerts You When a New Company Ranks for Keywords&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Generated AI Briefing Example Output
&lt;/h2&gt;

&lt;p&gt;Here's an example run. In my SerpApi call, I set the query to "AI" to keep things simple. I used these parameters for Anthropic API:&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;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude-opus-4-7&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="n"&gt;messages&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;role&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;user&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;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the Claude generated briefing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Daily AI Briefing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. AI Reshapes the Workforce: Layoffs, Skill Demands, and Survival Rules&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cloudflare announced a 20% workforce cut (1,100 employees) citing agentic AI as a fundamental disruptor of its operations, sending its stock down 18%. Meanwhile, Airbnb CEO Brian Chesky warned that "pure people managers" and change-resistant workers won't survive the AI era, and CBS reports employers are increasingly demanding AI fluency from new hires.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; &amp;nbsp;This is one of the first major tech layoffs explicitly attributed to agentic AI rather than macro conditions—signaling a shift from AI-as-productivity-tool to AI-as-headcount-replacement. Workers and managers face mounting pressure to reskill or face displacement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Conflicting Narratives on AI's Human Impact&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nvidia's Jensen Huang publicly framed AI as a net job creator, urging workers not to fear the technology. In contrast, a new study found that just 10 minutes of AI use measurably impaired cognitive performance on arithmetic and reasoning tasks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; &amp;nbsp;The optimistic vendor narrative (Huang) is increasingly at odds with both labor-market evidence (Cloudflare) and emerging cognitive research. Expect this tension to drive policy debates and shape enterprise adoption guardrails.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. AI Stocks Diverge as Earnings Season Tests the Hype&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;SoundHound AI beat Q1 expectations with 51.7% revenue growth but still dropped 12.4%, while Cloudflare cratered 18% post-earnings. Analysts are also reframing the Nvidia-vs-Palantir debate for 2026 as both stocks face renewed scrutiny.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; &amp;nbsp;Markets are no longer rewarding AI exposure alone—even strong top-line growth isn't enough. Investors are demanding margin discipline and clear AI monetization paths, marking a maturation point for the sector.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Military AI Moves From Theoretical to Operational&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The UK's Royal Air Force chief confirmed AI-powered uncrewed fighter aircraft are already being integrated into operations, far ahead of prior timelines. Simultaneously, CNN reports the Pentagon faces growing scrutiny over the legal limits of AI in warfare, including its use in Iran-related operations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; &amp;nbsp;Autonomous combat systems have crossed from R&amp;amp;D to deployment faster than legal and ethical frameworks can adapt. The gap between operational reality and governance is becoming a strategic vulnerability for Western militaries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. The Consumer AI Landscape Crystallizes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;TechRepublic published a side-by-side comparison of the major chatbots—ChatGPT, Gemini, Copilot, Claude, Perplexity, Grok, DeepSeek, and Meta AI—mapping each to specific use cases and integrations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; &amp;nbsp;With eight serious contenders now in the consumer/prosumer market, differentiation is shifting from raw model quality to ecosystem integration and vertical specialization. The "one assistant to rule them all" thesis is dead; multi-tool workflows are the new norm.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Building On Top Of This
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Changing The Model
&lt;/h3&gt;

&lt;p&gt;As of May 2026, here are the options Claude provides and what each is best for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Opus (Most Intelligent):&lt;/strong&gt; Best for complex tasks, deep reasoning, coding, and strategic analysis. It is the most powerful but slower and more expensive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sonnet (Balanced):&lt;/strong&gt; It provides the best balance of speed, intelligence, and cost, making it ideal for daily coding, data analysis, and content generation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Haiku (Fastest):&lt;/strong&gt; Optimized for speed and cost-efficiency. It is perfect for high-volume tasks, quick responses, and simple, repetitive jobs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can test the script with different models and figure out the best one for your use case. I used &lt;a href="https://www.anthropic.com/news/claude-opus-4-7" rel="noopener noreferrer"&gt;Claude Opus 4.7&lt;/a&gt; for this demo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Persisting History
&lt;/h3&gt;

&lt;p&gt;Instead of generating standalone briefings, store each run with a timestamp. This turns your system into a time-series of news summaries. Once you have history, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compare today vs yesterday (what’s new, what disappeared)&lt;/li&gt;
&lt;li&gt;Track theme momentum (what’s increasing or fading)&lt;/li&gt;
&lt;li&gt;Ask Claude for delta summaries instead of fresh-only summaries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example prompt changes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Compare today’s briefing with yesterday’s. Highlight new, removed, and shifting themes.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The key takeaway here is that LLMs work best when they’re grounded in high-quality external data. In this project, SerpApi provides structured, real-time Bing News data, while Claude turns that raw information into something readable and useful: a concise daily briefing with themes, summaries, and context.&lt;/p&gt;

&lt;p&gt;Instead of asking a model to know everything, we can give it fresh information and let it focus on synthesis and reasoning.&lt;/p&gt;

&lt;p&gt;I hope you found this useful. If you have any questions, feel free to reach out at&amp;nbsp;&lt;a href="mailto:contact@serpapi.com"&gt;contact@serpapi.com&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Relevant Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/bing-news-api" rel="noopener noreferrer"&gt;SerpApi Bing News API Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://platform.claude.com/docs/en/api/sdks/python" rel="noopener noreferrer"&gt;Claude Python SDK&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Related Blog Posts
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/connecting-claude-ai-to-the-internet-using-function-calling/" rel="noopener noreferrer"&gt;Connecting Claude AI to the Internet (using Function Calling)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/how-to-extract-bing-news-data-with-serpapi-and-python/" rel="noopener noreferrer"&gt;How to Extract Bing News Data with SerpApi and Python&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/the-web-search-api-for-ai-applications/" rel="noopener noreferrer"&gt;The Web Search API for AI Apps, Agents, and LLMs in 2026&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How To Scrape Home Depot Product Reviews</title>
      <dc:creator>Sonika Arora</dc:creator>
      <pubDate>Mon, 29 Jun 2026 07:05:48 +0000</pubDate>
      <link>https://dev.to/serpapi/how-to-scrape-home-depot-product-reviews-3jkg</link>
      <guid>https://dev.to/serpapi/how-to-scrape-home-depot-product-reviews-3jkg</guid>
      <description>&lt;p&gt;Customer reviews are one of the most valuable sources of product insight. They reveal real-world feedback, highlight product strengths and weaknesses, and help businesses understand customer sentiment.&lt;/p&gt;

&lt;p&gt;In this post, we'll explore how to collect product reviews from Home Depot using SerpApi's &lt;a href="https://serpapi.com/home-depot-product-reviews" rel="noopener noreferrer"&gt;Home Depot Product Reviews API&lt;/a&gt;. By the end, you'll be able to fetch product reviews data such as ratings, titles, and comments for analysis and monitoring.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Scrape Reviews?
&lt;/h2&gt;

&lt;p&gt;Home Depot is one of the largest home improvement retailers in the United States. Product reviews on its site provide valuable insights for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Competitive analysis — Understand how competing products are perceived.&lt;/li&gt;
&lt;li&gt;Sentiment analysis — Identify common praise or complaints.&lt;/li&gt;
&lt;li&gt;Market research — Learn what customers value most.&lt;/li&gt;
&lt;li&gt;Product development — Discover improvement opportunities.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Instead of manually collecting reviews, SerpApi lets you retrieve them programmatically and with many no code options.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Type of Data Can You Extract?
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://serpapi.com/home-depot-product-reviews" rel="noopener noreferrer"&gt;Home Depot Product Reviews API&lt;/a&gt; scrapes reviews for products from Home Depot and provides them in JSON format. Here are some prominent fields from the review object:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;id&lt;/code&gt;&lt;/strong&gt; — Unique identifier for the review.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;title&lt;/code&gt;&lt;/strong&gt; — Short headline summarizing the reviewer’s opinion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;text&lt;/code&gt;&lt;/strong&gt; — Full written content of the customer review.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;rating&lt;/code&gt;&lt;/strong&gt; — Numeric score given by the reviewer (typically on a 1–5 scale).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;badges&lt;/code&gt;&lt;/strong&gt; — Indicates badges on products like verifiedPurchaser.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;reviewer.name&lt;/code&gt;&lt;/strong&gt; — Display name of the person who wrote the review.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;time&lt;/code&gt;&lt;/strong&gt; — Timestamp showing when the review was published.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;original_source.name&lt;/code&gt;&lt;/strong&gt; — Website where the review originally appeared.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;images.link&lt;/code&gt;&lt;/strong&gt; — URLs of photos included in the review.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;total_positive_feedback&lt;/code&gt;&lt;/strong&gt; — Number of users who found the review helpful.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;total_negative_feedback&lt;/code&gt;&lt;/strong&gt; — Number of users who found the review unhelpful.&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%2F199ns8scxp1brojlrmp4.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%2F199ns8scxp1brojlrmp4.png" width="800" height="631"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Read the documentation page here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/home-depot-product-reviews" rel="noopener noreferrer"&gt;The Home Depot Product Reviews API - SerpApi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's an example in our playground:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/playground?engine=home_depot_product_reviews&amp;amp;product_id=302752040&amp;amp;sort_by=photoreview" rel="noopener noreferrer"&gt;SerpApi Playground - SerpApi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting up SerpApi
&lt;/h2&gt;

&lt;p&gt;Are you new to SerpApi? We'll walk you through the steps from sign up to integrating with SerpApi.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Started with SerpApi
&lt;/h3&gt;

&lt;p&gt;To get started with SerpApi, I recommend following the steps in this blog post:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/blog/getting-started-with-serpapi-the-web-search-api/" rel="noopener noreferrer"&gt;Getting started with SerpApi: The Web Search API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Home Depot Product Reviews API Documentation
&lt;/h3&gt;

&lt;p&gt;We recommend familiarizing yourself with the available parameters and details in the documentation here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/home-depot-product-reviews" rel="noopener noreferrer"&gt;The Home Depot Product Reviews API - SerpApi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Integrations / Libraries
&lt;/h3&gt;

&lt;p&gt;Some examples below will include our SerpApi libraries. If you would like to use one of our SerpApi libraries, we offer instructions for each language, such as Python, Node.js, Ruby, PHP, Java, Go, and more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/integrations" rel="noopener noreferrer"&gt;SerpApi: Integrations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Scraping Home Depot Product Reviews
&lt;/h2&gt;

&lt;p&gt;You can use any programming language in order to call our APIs. The parameters and results we reviewed above will not differ between the request methods, however the syntax used to call the APIs may differ.&lt;/p&gt;

&lt;p&gt;You will see across the examples the&amp;nbsp;&lt;code&gt;engine&lt;/code&gt;&amp;nbsp;is always set to &lt;code&gt;home_depot_product_reviews&lt;/code&gt;, the&amp;nbsp;&lt;code&gt;api_key&lt;/code&gt;&amp;nbsp;will be set to your API key, and we include the&amp;nbsp;&lt;code&gt;product_id&lt;/code&gt; in every query. In this example we are going to look for reviews for product with ID: 302752040&lt;/p&gt;

&lt;h3&gt;
  
  
  GET Request
&lt;/h3&gt;

&lt;p&gt;The syntax for the actual GET request between languages will vary between programming languages. However, the URL used each time is consistent. When you are sending a GET request in any language you will use this URL to make the request:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://serpapi.com/search.json?engine=home_depot_product_reviews&amp;amp;product_id=302752040
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Feel free to explore &lt;a href="https://serpapi.com/home-depot-product-reviews#api-parameters-advanced-filters" rel="noopener noreferrer"&gt;more parameters here&lt;/a&gt;, and add any that are relevant to your use case.&lt;/p&gt;

&lt;h3&gt;
  
  
  An Example With Our Python Library
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Install SerpApi's new Python&amp;nbsp;&lt;code&gt;serpapi&lt;/code&gt;&amp;nbsp;library in your environment:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;serpapi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;serpapi&lt;/code&gt;_&amp;nbsp;_is our new Python library. You can use this library to scrape search results from any of SerpApi's APIs.&lt;/p&gt;
&lt;h4&gt;
  
  
  More About Our Python Libraries
&lt;/h4&gt;

&lt;p&gt;We have two separate Python libraries &lt;a href="https://github.com/serpapi/serpapi-python" rel="noopener noreferrer"&gt;&lt;code&gt;serpapi&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/serpapi/google-search-results-python" rel="noopener noreferrer"&gt;&lt;code&gt;google-search-results&lt;/code&gt;&lt;/a&gt;, and both work perfectly fine. We are in the process of deprecating &lt;a href="https://github.com/serpapi/google-search-results-python" rel="noopener noreferrer"&gt;&lt;code&gt;google-search-results&lt;/code&gt;&lt;/a&gt;, so I recommend using &lt;code&gt;serpapi&lt;/code&gt; as that is our latest python library.&lt;/p&gt;

&lt;p&gt;You may encounter issues if you have both libraries installed at the same time. If you have the old library installed and want to proceed with using our new library, please follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Uninstall&amp;nbsp;&lt;code&gt;google-search-results&lt;/code&gt;&amp;nbsp;module from your environment.&lt;/li&gt;
&lt;li&gt;Make sure that neither&amp;nbsp;&lt;code&gt;serpapi&lt;/code&gt;&amp;nbsp;nor&amp;nbsp;&lt;code&gt;google-search-results&lt;/code&gt;&amp;nbsp;are installed at that stage.&lt;/li&gt;
&lt;li&gt;Install&amp;nbsp;&lt;code&gt;serpapi&lt;/code&gt;&amp;nbsp;module, for example with the following command if you're using&amp;nbsp;&lt;code&gt;pip&lt;/code&gt;: &lt;code&gt;pip install serpapi&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, let's take a look at the code:&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;import&lt;/span&gt; &lt;span class="n"&gt;serpapi&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serpapi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;YOUR_API_KEY&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;results&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;search&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;engine&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;home_depot_product_reviews&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;product_id&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;302752040&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;Replace the placeholder with your &lt;a href="https://serpapi.com/manage-api-key" rel="noopener noreferrer"&gt;API key&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  An Example With cURL
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl --get https://serpapi.com/search \
 -d api_key="YOUR_SECRET_API_KEY" \
 -d engine="home_depot_product_reviews" \
 -d product_id="302752040"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  No Code Options
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Google Sheets
&lt;/h3&gt;

&lt;p&gt;To connect your code with Google Sheets first follow this blog post:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://serpapi.com/blog/connect-serp-api-with-google-sheet-no-code/" rel="noopener noreferrer"&gt;Connect SERP API with Google Sheets (No Code)&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=SERPAPI_RESULT("engine=home_depot_product_reviews&amp;amp;product_id=302752040", "reviews.0.text")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Make.com
&lt;/h3&gt;

&lt;p&gt;While not every API we offer is on Make.com, there is a Universal Module where you can use any API.&lt;/p&gt;

&lt;p&gt;Review this blog post to get started:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/blog/announcing-serpapis-make-app/" rel="noopener noreferrer"&gt;Announcing SerpApi’s Make App&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  N8N
&lt;/h3&gt;

&lt;p&gt;Similar to Make.com, not every API is currently included in N8N. However, you can use the HTTP Request node to still call any of our APIs.&lt;/p&gt;

&lt;p&gt;To get started review this blog post:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/blog/boost-your-n8n-workflows-with-serpapis-verified-node/" rel="noopener noreferrer"&gt;Boost Your n8n Workflows with SerpApi’s Verified Node&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Scraping product reviews can unlock valuable insights about customer behavior and product performance. With the Home Depot Product Reviews API, you can retrieve structured review data in just a few lines of code.&lt;/p&gt;

&lt;p&gt;I hope you find this useful. If you have any questions, feel free to reach out at&amp;nbsp;&lt;a href="mailto:contact@serpapi.com"&gt;contact@serpapi.com&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Relevant Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/home-depot-product-reviews" rel="noopener noreferrer"&gt;API Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/status/home_depot_product_reviews" rel="noopener noreferrer"&gt;Status page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/pricing" rel="noopener noreferrer"&gt;Plans and Pricing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Related Blogs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/scraping-product-details-from-walmart-home-depot-and-google-shopping-with-serpapi/" rel="noopener noreferrer"&gt;Scraping Product Details from Walmart, Home Depot and Google Shopping with SerpApi&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/web-scraping-the-home-depot-search-with-nodejs/" rel="noopener noreferrer"&gt;Web scraping The Home Depot Search Pages with Nodejs and SerpApi&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/playground?engine=home_depot_product_reviews&amp;amp;product_id=302752040&amp;amp;sort_by=photoreview" rel="noopener noreferrer"&gt;SerpApi Playground - SerpApi&lt;/a&gt;0&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Build a Slack Bot That Alerts You When a New Company Ranks for Keywords</title>
      <dc:creator>Sonika Arora</dc:creator>
      <pubDate>Sun, 28 Jun 2026 07:05:02 +0000</pubDate>
      <link>https://dev.to/serpapi/build-a-slack-bot-that-alerts-you-when-a-new-company-ranks-for-keywords-1nl</link>
      <guid>https://dev.to/serpapi/build-a-slack-bot-that-alerts-you-when-a-new-company-ranks-for-keywords-1nl</guid>
      <description>&lt;p&gt;Monitoring when competitors begin ranking for new keywords can reveal product launches and marketing strategy changes. Instead of manually checking search results every day, you can automate the process with a Slack bot that sends alerts whenever a new company appears for keywords that matter for your brand.&lt;/p&gt;

&lt;p&gt;In this tutorial, we’ll build a simple system that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Checks search results using the &lt;a href="https://serpapi.com/search-api" rel="noopener noreferrer"&gt;SerpApi's Google Search API&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Detects when a competitor domain appears for a tracked keyword and sends an alert to a Slack channel.&lt;/li&gt;
&lt;li&gt;Run this process everyday using Python's schedule library.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Setting Up
&lt;/h2&gt;

&lt;p&gt;This system will work in four steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Send in requests to SerpApi's Google Search API for a list of relevant queries&lt;/li&gt;
&lt;li&gt;Extract all indexed pages&lt;/li&gt;
&lt;li&gt;Compare them with previously stored URLs&lt;/li&gt;
&lt;li&gt;Send alerts to Slack for new pages detected&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We'll run this job every day using the Python &lt;a href="https://schedule.readthedocs.io/en/stable/" rel="noopener noreferrer"&gt;schedule&lt;/a&gt; library. You can set the schedule as you like.&lt;/p&gt;

&lt;p&gt;To start, you’ll need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;a href="https://serpapi.com/" rel="noopener noreferrer"&gt;SerpApi&lt;/a&gt; account&lt;/li&gt;
&lt;li&gt;A Slack workspace (and a Slack Incoming Webhook URL)&lt;/li&gt;
&lt;li&gt;Python installed&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Create a Slack webhook
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to Slack → Apps&lt;/li&gt;
&lt;li&gt;Search for Incoming Webhooks&lt;/li&gt;
&lt;li&gt;Create a webhook for your channel&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You will get a Webhook URL like: &lt;code&gt;https://hooks.slack.com/services/XXXX/XXXX/XXXX&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Save this, as we'll need it later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code related setup steps
&lt;/h3&gt;

&lt;p&gt;For this tutorial, we're going to use SerpApi's &lt;a href="https://github.com/serpapi/serpapi-python" rel="noopener noreferrer"&gt;new Python library&lt;/a&gt; to get results from search.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install SerpApi's new Python&amp;nbsp;&lt;code&gt;serpapi&lt;/code&gt;&amp;nbsp;library, the &lt;a href="https://pypi.org/project/python-dotenv/" rel="noopener noreferrer"&gt;python-dotenv&lt;/a&gt; library, &lt;a href="https://pypi.org/project/tldextract/" rel="noopener noreferrer"&gt;tldextract&lt;/a&gt; library (for parsing the domains from URLs), and the &lt;a href="https://schedule.readthedocs.io/en/stable/" rel="noopener noreferrer"&gt;schedule&lt;/a&gt; library in your environment:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;serpapi python-dotenv schedule tldextract
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;serpapi&lt;/code&gt;_&amp;nbsp;_is our new Python library. You can use this library to scrape search results from any of SerpApi's APIs.&lt;/p&gt;
&lt;h4&gt;
  
  
  More About Our Python Libraries
&lt;/h4&gt;

&lt;p&gt;We have two separate Python libraries &lt;a href="https://github.com/serpapi/serpapi-python" rel="noopener noreferrer"&gt;&lt;code&gt;serpapi&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/serpapi/google-search-results-python" rel="noopener noreferrer"&gt;&lt;code&gt;google-search-results&lt;/code&gt;&lt;/a&gt;, and both work perfectly fine. We are in the process of deprecating &lt;a href="https://github.com/serpapi/google-search-results-python" rel="noopener noreferrer"&gt;&lt;code&gt;google-search-results&lt;/code&gt;&lt;/a&gt;, so I recommend using &lt;code&gt;serpapi&lt;/code&gt; as that is our latest python library.&lt;/p&gt;

&lt;p&gt;You may encounter issues if you have both libraries installed at the same time. If you have the old library installed and want to proceed with using our new library, please follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Uninstall&amp;nbsp;&lt;code&gt;google-search-results&lt;/code&gt;&amp;nbsp;module from your environment.&lt;/li&gt;
&lt;li&gt;Make sure that neither&amp;nbsp;&lt;code&gt;serpapi&lt;/code&gt;&amp;nbsp;nor&amp;nbsp;&lt;code&gt;google-search-results&lt;/code&gt;&amp;nbsp;are installed at that stage.&lt;/li&gt;
&lt;li&gt;Install&amp;nbsp;&lt;code&gt;serpapi&lt;/code&gt;&amp;nbsp;module, for example with the following command if you're using&amp;nbsp;&lt;code&gt;pip&lt;/code&gt;: &lt;code&gt;pip install serpapi&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;To begin scraping data, create a&amp;nbsp;&lt;a href="https://serpapi.com/users/sign_up" rel="noopener noreferrer"&gt;free account on serpapi.com&lt;/a&gt;. You'll receive 250 free search credits each month to explore the API. Get your SerpApi API Key from&amp;nbsp;&lt;a href="https://serpapi.com/manage-api-key" rel="noopener noreferrer"&gt;this page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;[Optional but Recommended] Set your API key in an environment variable, instead of directly pasting it in the code. Refer&amp;nbsp;&lt;a href="https://developer.vonage.com/en/blog/python-environment-variables-a-primer" rel="noopener noreferrer"&gt;here&lt;/a&gt;&amp;nbsp;to understand more about using environment variables. For this tutorial, I have saved the API key in an environment variable named "SERPAPI_API_KEY" in my .env file.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[Optional but Recommended] Set up your Slack Webhook URL as an an environment variable as well. In your &lt;code&gt;.env&lt;/code&gt; file, this will look like this:&lt;/p&gt;

&lt;p&gt;SERPAPI_API_KEY=&lt;br&gt;
SLACK_WEBHOOK_URL=&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Import classes needed for this project at the beginning of your code file and set up some constants we'll use later on:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&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;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;serpapi&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;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;schedule&lt;/span&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;tldextract&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;
&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;SERPAPI_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SERPAPI_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;queries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="c1"&gt;# List of queries for which you want to find the updated domains
&lt;/span&gt;&lt;span class="n"&gt;DB_FILE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;known_domains.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;SLACK_WEBHOOK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SLACK_WEBHOOK_URL&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;Provide the value of your slack webhook in the&amp;nbsp;&lt;code&gt;SLACK_WEBHOOK&lt;/code&gt;&amp;nbsp;variable. It looks something like this:&amp;nbsp;&lt;code&gt;https://hooks.slack.com/services/XXXX/XXXX/XXXX&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Provide a list of queries you're looking to track competitors with. Example: ["ai images tool", "ai image generators", "image creation ai tools"]&lt;/p&gt;

&lt;h2&gt;
  
  
  Get all indexed domains for a list of queries
&lt;/h2&gt;

&lt;p&gt;For the purpose of this post, we'll consider the first 30 organic results and use a simple list of 3 queries. You can increase or decrease this number as needed and change the queries as well depending on your use case.&lt;/p&gt;

&lt;p&gt;A simple function to get the root domain from the URL using the &lt;code&gt;tldextract&lt;/code&gt; library we installed earlier:&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_root_domain&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;extracted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tldextract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extract&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="c1"&gt;# Join the domain and suffix to get the root domain
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;extracted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;extracted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;suffix&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's create a script&amp;nbsp;com &lt;code&gt;get_domains.py&lt;/code&gt;&amp;nbsp;where we use SerpApi 's Google Search API to get the domains of the first 30 search results for a particular query.&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_all_domains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query_list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;domains_for_each_query&lt;/span&gt; &lt;span class="o"&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="n"&gt;serpapi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;SERPAPI_KEY&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;query&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;query_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;domains_for_each_query&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&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;start&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&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;span class="mi"&gt;30&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;results&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;search&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;engine&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;google&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;google_domain&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;google.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;q&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;start&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;organic_results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&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;result&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;organic_results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
                &lt;span class="n"&gt;link&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&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;link&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;link&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;continue&lt;/span&gt;

                &lt;span class="n"&gt;root_domain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_root_domain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;domains_for_each_query&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root_domain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&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="nf"&gt;list&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="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;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;domains_for_each_query&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;This function sends a request to SerpApi's Google Search API and collects the root domains from the organic result links, and stores them per query. It uses a set to keep only unique domains and fetches up to the first 30 results (pagination with start). It returns a dictionary mapping each query to a list of unique domains found in the search results.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 If you want to dive deeper into how to scrape Google search results with Python, read&amp;nbsp;&lt;a href="https://serpapi.com/blog/how-to-scrape-google-search-results-with-python/" rel="noopener noreferrer"&gt;this post&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Save known domains
&lt;/h2&gt;

&lt;p&gt;For the purpose of this example, let's assume the file&amp;nbsp;&lt;code&gt;known_domains.json&lt;/code&gt;&amp;nbsp;stores all previously stored pages in JSON format. So, we now need to compare with the domains in this file to find newly added ones.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 If you are starting from scratch, using the scripts here will pull all the domains because the&amp;nbsp;&lt;code&gt;known_domains.json&lt;/code&gt;&amp;nbsp;file will be empty. Next time, when you use the script, you'll only see the new ones added.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's write some code to load the URLs from the file and save the new URLs to the file which we can use later on:&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_domains&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DB_FILE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;save_domains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domains&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DB_FILE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domains&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Send slack alerts
&lt;/h2&gt;

&lt;p&gt;Let's write a simple function to send slack alerts for any new domains seen for each query. We'll use this later.&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_slack_alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domains&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="c1"&gt;# Filter out keys with no new values
&lt;/span&gt;    &lt;span class="n"&gt;domains&lt;/span&gt; &lt;span class="o"&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="n"&gt;v&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;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;domains&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;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;v&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;domains&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;message&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;text&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;✅ No new companies detected for any query.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&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;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SLACK_WEBHOOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;domains&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;domains&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;query&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;message&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;text&lt;/span&gt;&lt;span class="sh"&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;🚨 New company detected for &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&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="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domains&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&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;message&lt;/span&gt;&lt;span class="p"&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;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SLACK_WEBHOOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once everything is set up, your Slack channel will receive alerts like this once a day if new domains detected for any query:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;🚨 New company detected for 'image creation ai tools':&lt;br&gt;&lt;br&gt;
company1.com&lt;br&gt;&lt;br&gt;
company2.com&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Detect new pages
&lt;/h2&gt;

&lt;p&gt;Now let's work on code to specifically detect new pages by looking at already stored ones in &lt;code&gt;known_domains.json&lt;/code&gt;.&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check_for_new_domains&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Checking for new domains...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;known_domains&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load_domains&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;current_domains&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_all_domains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QUERY_LIST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;new_domains&lt;/span&gt; &lt;span class="o"&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;query&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;current_domains&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;new_domains&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_domains&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;known_domains&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;query&lt;/span&gt;&lt;span class="p"&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;known_domains&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;known_domains&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;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]))&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_domains&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;send_slack_alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_domains&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;save_domains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;known_domains&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function checks the search results for new domains appearing for each query compared to previously stored domains. It computes the difference between current domains and known domains, sends a Slack alert for any new ones, and then updates the stored list with the latest domains.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run the bot on a schedule
&lt;/h2&gt;

&lt;p&gt;Now the only thing left is to schedule this so it runs once everyday.&lt;/p&gt;

&lt;p&gt;To do this, we'll use&amp;nbsp;&lt;a href="https://schedule.readthedocs.io/en/stable/" rel="noopener noreferrer"&gt;Python's schedule library&lt;/a&gt;.&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="c1"&gt;# Schedule the bot to run every day at 9 AM
&lt;/span&gt;&lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;every&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;09:00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;check_for_new_domains&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Query domain monitoring bot running...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run_pending&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;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To keep the tasks running even after you close your terminal or IDE, you can choose to run the script as a persistent background process. For linux/macOS, use&amp;nbsp;&lt;code&gt;nohup&lt;/code&gt;&amp;nbsp;or&amp;nbsp;&lt;code&gt;disown&lt;/code&gt;&amp;nbsp;to detach the script from the terminal, e.g.,&amp;nbsp;&lt;code&gt;python3 script.py &amp;amp; disown&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the alert looks like
&lt;/h2&gt;

&lt;p&gt;I ran the code twice with &lt;code&gt;QUERY_LIST&lt;/code&gt; = ["ai images tool", "ai image generators", "image creation ai tools"]&lt;/p&gt;

&lt;p&gt;The first time, I got some new pages (because a few new companies started ranking for the queries since when I ran it last)&lt;br&gt;&lt;br&gt;
The next time, since all the webpages were already seen, I got a message letting me know that no new pages were detected.&lt;/p&gt;

&lt;p&gt;These were the alerts I received:&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%2Fdn3d5ve9fni4rm1t89mx.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%2Fdn3d5ve9fni4rm1t89mx.png" width="800" height="711"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now your team will instantly know when new companies start ranking for important keywords that matter for your brand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Possible Enhancements
&lt;/h2&gt;

&lt;p&gt;Once the basic setup works, you can extend it for a couple more use cases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Track ranking changes&lt;/strong&gt; : Alert when a domain jumps from page 2 -&amp;gt; page 1&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor multiple regions&lt;/strong&gt; : Use different location parameters&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Track different features&lt;/strong&gt; : Monitor if competitors appear in other parts of SERP like featured snippets, shopping results, and knowledge panels&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By combining SerpApi, Slack, and a Python script, you can build a lightweight monitoring system that continuously tracks competitor activity in search.&lt;/p&gt;

&lt;p&gt;With this, you’ll have a practical developer tool that saves hours of manual SERP monitoring and helps your team react faster to competitive changes. You can also use this tutorial to setup any other recurring tasks and send notifications to the slack channel.&lt;/p&gt;

&lt;p&gt;You can find the entire code here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/serpapi/slack-alerts-for-new-company-ranking" rel="noopener noreferrer"&gt;GitHub - serpapi/slack-alerts-for-new-company-ranking: In this tutorial, we’ll build a simple system that detects when a new brand ranks for a tracked keyword and send an alert to a Slack channel.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feel free to reach out to us at&amp;nbsp;&lt;a href="mailto:contact@serpapi.com"&gt;contact@serpapi.com&lt;/a&gt;&amp;nbsp;for any questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Relevant Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/search-engine-apis" rel="noopener noreferrer"&gt;API Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/status" rel="noopener noreferrer"&gt;Status page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/pricing" rel="noopener noreferrer"&gt;Plans and Pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.slack.dev/messaging/sending-messages-using-incoming-webhooks/" rel="noopener noreferrer"&gt;Slack Webhook Setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/blog/how-to-scrape-google-search-results-with-python/" rel="noopener noreferrer"&gt;Dive deeper into how to scrape search results with Python&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Build a Slack Bot That Alerts You When Your Competitor Launches a New Page</title>
      <dc:creator>Sonika Arora</dc:creator>
      <pubDate>Sat, 27 Jun 2026 07:04:07 +0000</pubDate>
      <link>https://dev.to/serpapi/build-a-slack-bot-that-alerts-you-when-your-competitor-launches-a-new-page-4khn</link>
      <guid>https://dev.to/serpapi/build-a-slack-bot-that-alerts-you-when-your-competitor-launches-a-new-page-4khn</guid>
      <description>&lt;p&gt;If you're tracking competitors, one of the most valuable signals is when they launch a new page and it shows up in search results. New pages that companies add often reveal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New product launches&lt;/li&gt;
&lt;li&gt;New feature pages&lt;/li&gt;
&lt;li&gt;New landing pages targeting keywords&lt;/li&gt;
&lt;li&gt;New content marketing strategies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Manually checking for changes can take quite some time, and repetitive work as pages are updated often. Instead of manually checking competitor sites, you can automate this process using:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;SerpApi (Google Search API)&lt;/li&gt;
&lt;li&gt;Slack Webhook&lt;/li&gt;
&lt;li&gt;Python's schedule library&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this tutorial, we’ll build a simple system that checks search results using the SerpApi's Google Search API to detect when a new competitor domain URL is noticed in search results and then sends an alert to a Slack channel.&lt;/p&gt;




&lt;h2&gt;
  
  
  Setting Up
&lt;/h2&gt;

&lt;p&gt;This system will work in four steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Send in a request to SerpApi's Google Search API with a relevant query&lt;/li&gt;
&lt;li&gt;Extract all indexed pages&lt;/li&gt;
&lt;li&gt;Compare them with previously stored URLs&lt;/li&gt;
&lt;li&gt;Send alerts to Slack for new pages detected&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We'll run this job every day using the Python schedule library. You can set the schedule as you like.&lt;/p&gt;

&lt;p&gt;To start, you’ll need a SerpApi account, a Slack workspace (and a Slack Incoming Webhook URL), and Python installed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a Slack Webhook
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to Slack → Apps&lt;/li&gt;
&lt;li&gt;Search for Incoming Webhooks&lt;/li&gt;
&lt;li&gt;Create a webhook for your channel&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You will get a Webhook URL like: &lt;code&gt;https://hooks.slack.com/services/XXXX/XXXX/XXXX&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Save this, as we'll need it later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Related Setup Steps
&lt;/h3&gt;

&lt;p&gt;For this tutorial, we're going to use SerpApi's &lt;a href="https://github.com/serpapi/serpapi-python" rel="noopener noreferrer"&gt;new Python library&lt;/a&gt; to get results from Google Search.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install SerpApi's new Python&amp;nbsp;&lt;code&gt;serpapi&lt;/code&gt;&amp;nbsp;library, the &lt;a href="https://pypi.org/project/python-dotenv/" rel="noopener noreferrer"&gt;python-dotenv&lt;/a&gt; library, and the &lt;a href="https://schedule.readthedocs.io/en/stable/" rel="noopener noreferrer"&gt;schedule&lt;/a&gt; library in your environment:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;serpapi python-dotenv schedule
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;serpapi&lt;/code&gt;_&amp;nbsp;_is our new Python library. You can use this library to scrape search results from any of SerpApi's APIs.&lt;/p&gt;
&lt;h4&gt;
  
  
  More About Our Python Libraries
&lt;/h4&gt;

&lt;p&gt;We have two separate Python libraries &lt;a href="https://github.com/serpapi/serpapi-python" rel="noopener noreferrer"&gt;&lt;code&gt;serpapi&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/serpapi/google-search-results-python" rel="noopener noreferrer"&gt;&lt;code&gt;google-search-results&lt;/code&gt;&lt;/a&gt;, and both work perfectly fine. We are in the process of deprecating &lt;a href="https://github.com/serpapi/google-search-results-python" rel="noopener noreferrer"&gt;&lt;code&gt;google-search-results&lt;/code&gt;&lt;/a&gt;, so I recommend using &lt;code&gt;serpapi&lt;/code&gt; as that is our latest python library.&lt;/p&gt;

&lt;p&gt;You may encounter issues if you have both libraries installed at the same time. If you have the old library installed and want to proceed with using our new library, please follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Uninstall&amp;nbsp;&lt;code&gt;google-search-results&lt;/code&gt;&amp;nbsp;module from your environment.&lt;/li&gt;
&lt;li&gt;Make sure that neither&amp;nbsp;&lt;code&gt;serpapi&lt;/code&gt;&amp;nbsp;nor&amp;nbsp;&lt;code&gt;google-search-results&lt;/code&gt;&amp;nbsp;are installed at that stage.&lt;/li&gt;
&lt;li&gt;Install&amp;nbsp;&lt;code&gt;serpapi&lt;/code&gt;&amp;nbsp;module, for example with the following command if you're using&amp;nbsp;&lt;code&gt;pip&lt;/code&gt;: &lt;code&gt;pip install serpapi&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;To begin scraping data, create a&amp;nbsp;&lt;a href="https://serpapi.com/users/sign_up" rel="noopener noreferrer"&gt;free account on serpapi.com&lt;/a&gt;. You'll receive 250 free search credits each month to explore the API. Get your SerpApi API Key from&amp;nbsp;&lt;a href="https://serpapi.com/manage-api-key" rel="noopener noreferrer"&gt;this page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;[Optional but Recommended] Set your API key in an environment variable, instead of directly pasting it in the code. Refer&amp;nbsp;&lt;a href="https://developer.vonage.com/en/blog/python-environment-variables-a-primer" rel="noopener noreferrer"&gt;here&lt;/a&gt;&amp;nbsp;to understand more about using environment variables. For this tutorial, I have saved the API key in an environment variable named "SERPAPI_API_KEY" in my .env file.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[Optional but Recommended] Set up your Slack Webhook URL as an an environment variable as well. In your &lt;code&gt;.env&lt;/code&gt; file, this will look like this:&lt;/p&gt;

&lt;p&gt;SERPAPI_API_KEY=&lt;br&gt;
SLACK_WEBHOOK_URL=&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Import classes needed for this project at the beginning of your code file and set up some constants we'll use later on:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&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;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;serpapi&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;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;schedule&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;
&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;SERPAPI_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SERPAPI_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;DOMAIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;company.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;DB_FILE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;known_urls.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;SLACK_WEBHOOK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SLACK_WEBHOOK_URL&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;h2&gt;
  
  
  Fetch All Indexed Pages For Competitor
&lt;/h2&gt;

&lt;p&gt;Let's create a script &lt;code&gt;competitor_page_monitor.py&lt;/code&gt; where we use SerpApi 's Google Search API to get all pages which show up in search results for a particular company.&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_all_pages&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
   &lt;span class="n"&gt;urls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&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="n"&gt;serpapi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;apikey&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;start&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&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;span class="mi"&gt;100&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;results&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;search&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
           &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;engine&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;google&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;q&lt;/span&gt;&lt;span class="sh"&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;site:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DOMAIN&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; -site:forum.&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DOMAIN&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; -site:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DOMAIN&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/blog -site:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DOMAIN&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/careers -site:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DOMAIN&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/release-notes&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;start&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;start&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;organic_results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&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;result&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;organic_results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
           &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;link&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 You may need to add more customized search operators to your query if you want to ignore specific types of pages. For this example, I'm using &lt;code&gt;site:company.com -site:forum.company.com -site:company.com/blog -site:company.com/careers -site:company.com/release-notes"&lt;/code&gt; to ignore the blog, forum and career pages.&lt;br&gt;&lt;br&gt;
Conversely, you can also choose to target specific areas such as blogs and get notified what exactly your competitors are writing about publicly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Feel free to change the maximum pagination as you'd like. I've set start to a max value of 100 which means we'll see data from up to 10 pages (since each page usually has 10 results).&lt;/p&gt;

&lt;p&gt;Now that we have all the pages for that domain, we need to find the newly added ones since our last check.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 If you want to dive deeper into how to scrape Google search results with Python, refer to &lt;a href="https://serpapi.com/blog/how-to-scrape-google-search-results-with-python/" rel="noopener noreferrer"&gt;this post&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Save Known URLs
&lt;/h2&gt;

&lt;p&gt;For the purpose of this example, let's assume the file &lt;code&gt;known_urls.json&lt;/code&gt; stores all previously stored pages in JSON format. So, we now need to compare with the URLs in this file to find newly added ones.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 If you are starting from scratch, using the scripts here will pull all the URLs for the competitor because the &lt;code&gt;known_urls.json&lt;/code&gt; file will be empty. Next time, when you use the script, you'll only see the new ones added.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's write some code to load the URLs from the file and save the new URLs to the file which we can use later on:&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_urls&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DB_FILE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;save_urls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
     &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DB_FILE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Send Slack Alerts
&lt;/h2&gt;

&lt;p&gt;Let's write a simple function to send slack alerts. We'll use this later.&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;SLACK_WEBHOOK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_SLACK_WEBHOOK&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_slack_alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urls&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;urls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
       &lt;span class="n"&gt;message&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;text&lt;/span&gt;&lt;span class="sh"&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;🚨 New competitor pages detected: &lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&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="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
       &lt;span class="n"&gt;message&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;text&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;✅ No new competitor pages detected.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
       &lt;span class="p"&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;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SLACK_WEBHOOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 Provide the value of your slack webhook in the &lt;code&gt;SLACK_WEBHOOK&lt;/code&gt; variable. It looks something like this: &lt;code&gt;https://hooks.slack.com/services/XXXX/XXXX/XXXX&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Detect New Pages
&lt;/h2&gt;

&lt;p&gt;Now let's work on code to specifically detect new pages by looking at already stored ones in known_urls.json.&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check_new_pages&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Checking for new pages...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;known_urls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load_urls&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;current_urls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_all_pages&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;new_pages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current_urls&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;known_urls&lt;/span&gt;

    &lt;span class="nf"&gt;send_slack_alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_pages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;new_seen_set&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;known_urls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;union&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_urls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;save_urls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_seen_set&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run the Bot on a Schedule
&lt;/h2&gt;

&lt;p&gt;Now the only thing left is to schedule this so it runs once everyday.&lt;/p&gt;

&lt;p&gt;To do this, we'll use &lt;a href="https://schedule.readthedocs.io/en/stable/" rel="noopener noreferrer"&gt;Python's schedule library&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 I'm using Python's schedule library instead of cron because it works reliably on macOS and local environments&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;every&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;09:00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;check_new_pages&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Competitor monitoring bot running...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run_pending&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;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To keep the tasks running even after you close your terminal or IDE, you can choose to run the script as a persistent background process. For linux/macOS, use&amp;nbsp;&lt;code&gt;nohup&lt;/code&gt;&amp;nbsp;or&amp;nbsp;&lt;code&gt;disown&lt;/code&gt;&amp;nbsp;to detach the script from the terminal, e.g.,&amp;nbsp;&lt;code&gt;python3 script.py &amp;amp; disown&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What The Alert Looks Like
&lt;/h2&gt;

&lt;p&gt;Once this is set up, your Slack channel will receive alerts like this once a day:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🚨 New competitor pages detected:&lt;br&gt;&lt;br&gt;
&lt;a href="https://competitor.com/products/ai-assistant" rel="noopener noreferrer"&gt;https://competitor.com/products/ai-assistant&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://competitor.com/features/fast-mode" rel="noopener noreferrer"&gt;https://competitor.com/features/fast-mode&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I ran the code twice for the domain &lt;code&gt;serpapi.com&lt;/code&gt;. The first time, I got some new pages and the next time, since all the webpages were already seen, I got a message letting me know that no new pages were detected. These were the alerts I received:&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%2Fy29dymg9848ni0s1bfkg.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%2Fy29dymg9848ni0s1bfkg.png" width="800" height="204"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This lets you instantly spot new product launches, new feature releases, and new landing pages which are showing up in search results for any company.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;With about 50 lines of Python, you now have a bot that monitors all indexed pages of a competitor, detects new launches, and sends instant Slack alerts.&lt;/p&gt;

&lt;p&gt;This is one of the simplest ways to build a competitive intelligence system using search data. You can also use this tutorial to setup any other recurring tasks and send notifications to the slack channel.&lt;/p&gt;

&lt;p&gt;You can find the entire code here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/serpapi/slack-alerts-for-new-competitor-pages" rel="noopener noreferrer"&gt;GitHub - serpapi/slack-alerts-for-new-competitor-pages: In this tutorial, we’ll build a simple system that uses SerpApi’s Google Search API to detect when a new competitor domain URL appears in search results and then sends an alert to a Slack channel.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feel free to reach out to us at&amp;nbsp;&lt;a href="mailto:contact@serpapi.com"&gt;contact@serpapi.com&lt;/a&gt;&amp;nbsp;for any questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Relevant Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/search-engine-apis" rel="noopener noreferrer"&gt;API Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/status" rel="noopener noreferrer"&gt;Status page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/pricing" rel="noopener noreferrer"&gt;Plans and Pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.slack.dev/messaging/sending-messages-using-incoming-webhooks/" rel="noopener noreferrer"&gt;Slack Webhook Setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/blog/how-to-scrape-google-search-results-with-python/" rel="noopener noreferrer"&gt;Dive deeper into how to scrape Google search results with Python&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Get AI Generated Responses From Search Engines In Structured JSON</title>
      <dc:creator>Sonika Arora</dc:creator>
      <pubDate>Fri, 26 Jun 2026 07:02:48 +0000</pubDate>
      <link>https://dev.to/serpapi/get-ai-generated-responses-from-search-engines-in-structured-json-2713</link>
      <guid>https://dev.to/serpapi/get-ai-generated-responses-from-search-engines-in-structured-json-2713</guid>
      <description>&lt;p&gt;Search engine results are no longer just a list of links. Many search engines like Google and Bing surface AI generated answers directly in the results page - in summaries, conversational responses, and synthesized insights that sit above or inside traditional SERP features. For developers and data teams, this raises an interesting question: How can you programmatically collect and analyze these AI answers the same way you do classic SERP data?&lt;/p&gt;

&lt;p&gt;With &lt;a href="https://serpapi.com/" rel="noopener noreferrer"&gt;SerpApi&lt;/a&gt; you can scrape these generated answers without needing to write brittle scraping logic.&lt;/p&gt;

&lt;p&gt;In this post we'll walk through how AI generated answers appear across major search engines and how SerpApi exposes them in structured JSON.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why scrape AI generated responses?
&lt;/h2&gt;

&lt;p&gt;AI generated answers have quickly become the first thing users often see. Scraping them enables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generative engine optimization (GEO) &amp;amp; content research - Understand what content AI models consider authoritative and trustworthy, and track how your pages appear in AI-generated answers.&lt;/li&gt;
&lt;li&gt;Search experience monitoring - Track how AI summaries describe your brand or product.&lt;/li&gt;
&lt;li&gt;Competitive analysis - See which competitors are mentioned or cited. &lt;/li&gt;
&lt;li&gt;LLM grounding - Compare AI answers across engines for factual drift.&lt;/li&gt;
&lt;li&gt;Product intelligence - Detect changes in how queries are answered over time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's dive into where we can find these AI responses.&lt;/p&gt;




&lt;h2&gt;
  
  
  Google: AI Mode, AI Overviews, and AI in People Also Ask
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Google AI Mode (Conversational Search)
&lt;/h3&gt;

&lt;p&gt;Google AI Mode introduces a chat‑like search experience, where the response is generated dynamically rather than assembled from classic SERP blocks.&lt;/p&gt;

&lt;p&gt;With SerpApi, you can capture these responses in structured form with our &lt;a href="https://serpapi.com/google-ai-mode-api" rel="noopener noreferrer"&gt;Google AI Mode API&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The full AI response text&lt;/li&gt;
&lt;li&gt;Follow up questions at the end of the answer&lt;/li&gt;
&lt;li&gt;All the references&lt;/li&gt;
&lt;li&gt;Shopping results&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Try out an example here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/playground?engine=google_ai_mode&amp;amp;q=Coffee&amp;amp;gl=us&amp;amp;hl=en" rel="noopener noreferrer"&gt;SerpApi Playground - SerpApi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is what the response looks like:&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%2F1evqmjnr1axffjv432j1.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%2F1evqmjnr1axffjv432j1.png" width="798" height="252"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Google AI Overviews
&lt;/h3&gt;

&lt;p&gt;Google AI Overviews appear at the top of the SERP results as a synthesized AI generated answer with citations.&lt;/p&gt;

&lt;p&gt;With SerpApi’s &lt;a href="https://serpapi.com/ai-overview" rel="noopener noreferrer"&gt;Google Search API&lt;/a&gt;, AI Overviews are returned as a dedicated JSON object, typically including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The generated summary text&lt;/li&gt;
&lt;li&gt;Referenced sources / citations&lt;/li&gt;
&lt;li&gt;Highlighted concepts&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Google may not always return the overview content, but instead return a &lt;code&gt;page_token&lt;/code&gt; in the &lt;code&gt;ai_overview&lt;/code&gt; object. When this happens, you can send an additional request to the &lt;a href="https://serpapi.com/google-ai-overview-api" rel="noopener noreferrer"&gt;AI Overview API&lt;/a&gt; to retrieve the full AI Overview.&lt;br&gt;&lt;br&gt;
﻿​﻿&lt;br&gt;&lt;br&gt;
﻿You can do this using the &lt;code&gt;page_token&lt;/code&gt; or by simply sending a GET request to the &lt;code&gt;serpapi_link&lt;/code&gt; in the &lt;code&gt;ai_overview&lt;/code&gt; object in the Google Search API response. The &lt;code&gt;page_token&lt;/code&gt; is only valid for one minute after the initial request, so we recommend querying for the AI overview immediately after your initial search.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This allows you to extract the AI generated answer without parsing HTML or executing JavaScript.&lt;/p&gt;

&lt;p&gt;Try out an example here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/playground?q=Dropshipping&amp;amp;location=Austin%2C+Texas%2C+United+States&amp;amp;gl=us&amp;amp;hl=en" rel="noopener noreferrer"&gt;SerpApi Playground - SerpApi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is what the response looks like when the &lt;code&gt;ai_overview&lt;/code&gt; content is included:&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%2Fktiux0m7sepmjsewgets.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%2Fktiux0m7sepmjsewgets.png" width="800" height="245"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is what the response looks like when the a &lt;code&gt;page_token&lt;/code&gt; is returned instead:&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%2F59t65ydtxxvpao5i9xzz.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%2F59t65ydtxxvpao5i9xzz.png" width="800" height="199"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After a request to the AI overview API with that &lt;code&gt;page_token&lt;/code&gt; we get:&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%2Fm8gtsrvcm2tit0h84yoc.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%2Fm8gtsrvcm2tit0h84yoc.png" width="799" height="205"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  AI Answers in “People Also Ask” (PAA)
&lt;/h3&gt;

&lt;p&gt;The People Also Ask section has evolved from expandable snippets with human written answers into AI‑style synthesized answers for many queries.&lt;/p&gt;

&lt;p&gt;Using SerpApi, you can get each PAA question and answer using our &lt;a href="https://serpapi.com/search-api" rel="noopener noreferrer"&gt;Google Search API&lt;/a&gt;, which includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The associated question&lt;/li&gt;
&lt;li&gt;The generated answer text&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  - Source references (when available)
&lt;/h2&gt;

&lt;p&gt;Try out an example here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/playground?q=is+coffee+healthy+for+you%3F&amp;amp;location=Austin%2C+Texas%2C+United+States&amp;amp;gl=us&amp;amp;hl=en" rel="noopener noreferrer"&gt;SerpApi Playground - SerpApi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is what the response looks like:&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%2F8umkrkit2uyo1ifi40dy.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%2F8umkrkit2uyo1ifi40dy.png" width="799" height="266"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Bing Copilot Answers
&lt;/h2&gt;

&lt;p&gt;Microsoft Bing has a Copilot page where you can get ask questions in a chat‑like search experience.&lt;/p&gt;

&lt;p&gt;With SerpApi’s &lt;a href="https://serpapi.com/bing-copilot-api" rel="noopener noreferrer"&gt;Bing Copilot API&lt;/a&gt;, Copilot responses are exposed as structured fields rather than embedded UI components.&lt;/p&gt;

&lt;p&gt;You can extract the following from the Copilot generated answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Text and lists &lt;/li&gt;
&lt;li&gt;Links wherever they appear in the answer&lt;/li&gt;
&lt;li&gt;Reference indexes&lt;/li&gt;
&lt;li&gt;Related follow‑up prompts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Try out an example here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/playground?engine=bing_copilot&amp;amp;q=new+shopping+things" rel="noopener noreferrer"&gt;SerpApi Playground - SerpApi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is what the response looks like:&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%2Fg341c30w3w1l2leuiw7p.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%2Fg341c30w3w1l2leuiw7p.png" width="800" height="521"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  DuckDuckGo Search Assist API
&lt;/h2&gt;

&lt;p&gt;DuckDuckGo exposes AI assisted summaries and responses through its Search Assist experience.&lt;/p&gt;

&lt;p&gt;With SerpApi’s &lt;a href="https://serpapi.com/duckduckgo-search-assist-api" rel="noopener noreferrer"&gt;DuckDuckGo Search Assist API&lt;/a&gt;, by setting the &lt;code&gt;search_assist&lt;/code&gt; parameter to &lt;code&gt;true&lt;/code&gt;, you can programmatically retrieve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI generated instant answers&lt;/li&gt;
&lt;li&gt;Referenced sources / citations&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Search assist results may contain &lt;code&gt;answer&lt;/code&gt;, &lt;code&gt;expanded_answer&lt;/code&gt;, &lt;code&gt;sources&lt;/code&gt;, &lt;code&gt;titles&lt;/code&gt;, &lt;code&gt;abstracts&lt;/code&gt;, &lt;code&gt;domains&lt;/code&gt;, &lt;code&gt;urls&lt;/code&gt;, &lt;code&gt;organic_word_ngrams&lt;/code&gt;, and&amp;nbsp;&lt;code&gt;organic_wiki_entities&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;DuckDuckGo is the only engine to include organic word n-grams (sequences of&amp;nbsp;&lt;em&gt;n&lt;/em&gt;&amp;nbsp;consecutive words) in their AI assisted summaries. These may be used to structure and optimize content based on actual search-driven data. They allow you to move beyond single-keyword targeting to understand user intent, phrase patterns, and topical depth.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Try out an example here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/playground?engine=duckduckgo&amp;amp;q=apple&amp;amp;kl=us-en&amp;amp;search_assist=true" rel="noopener noreferrer"&gt;SerpApi Playground - SerpApi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is what the response looks like:&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%2F1iyhqzif1vb9mknoyegk.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%2F1iyhqzif1vb9mknoyegk.png" width="800" height="261"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Naver AI Briefing
&lt;/h2&gt;

&lt;p&gt;Naver, the dominant search engine in South Korea, has rolled out its own AI Briefing feature, tailored to local content and language preferences.&lt;/p&gt;

&lt;p&gt;SerpApi supports Naver search results and surfaces the AI generated answer in structured JSON with the &lt;a href="https://serpapi.com/naver-ai-overview-api" rel="noopener noreferrer"&gt;Naver AI Overview API&lt;/a&gt;, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI generated answer (in markdown or broken down by paragraphs)&lt;/li&gt;
&lt;li&gt;Linked sources from Naver properties and external sites&lt;/li&gt;
&lt;li&gt;Reference indexes&lt;/li&gt;
&lt;li&gt;Any displayed media&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Try out an example here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/playground?engine=naver_ai_overview&amp;amp;query=Coffee&amp;amp;highlight=text_blocks" rel="noopener noreferrer"&gt;SerpApi Playground - SerpApi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is what the response looks like:&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%2Fsmbcifyxrmmf71gx51vn.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%2Fsmbcifyxrmmf71gx51vn.png" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Use SerpApi?
&lt;/h2&gt;

&lt;p&gt;SerpApi streamlines the process of web-scraping. SerpApi manages the intricacies of scraping and returns structured JSON results. This allows you to save time and effort by avoiding the need to build your own scrapers or rely on other web scraping tools.&lt;/p&gt;

&lt;p&gt;We do all the work to maintain all of our parsers and adapt them to respond to changes on search engines. This is important, as search engines are constantly experimenting with new layouts, new elements, and other changes. By taking care of this for you on our side, we eliminate a lot of time and complexity from your workflow.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As search continues to evolve from links to overviews and AI generated answers, having structured access to AI generated responses gives you a critical edge.&lt;/p&gt;

&lt;p&gt;I hope this post enabled you in understanding how AI generated answers appear across major search engines and how you can use SerpApi to get them in structured JSON. Feel free to reach out to us at &lt;a href="mailto:contact@serpapi.com"&gt;contact@serpapi.com&lt;/a&gt; for any questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Relevant Links
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Documentation
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/status" rel="noopener noreferrer"&gt;Status page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/pricing" rel="noopener noreferrer"&gt;Plans and Pricing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/use-cases/ai-seo-geo-api" rel="noopener noreferrer"&gt;AI SEO (GEO) API Use Case Page&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Related Posts
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/real-world-example-of-ai-powered-parsing/" rel="noopener noreferrer"&gt;Real World Example of AI Powered Parsing&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/web-scraping-with-ai-parsing-html-to-structured-data/" rel="noopener noreferrer"&gt;Web scraping with AI (Parsing HTML to structured data)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/ai-powered-seo-research-agent-with-openai-serpapi/" rel="noopener noreferrer"&gt;AI-Powered SEO Research Agent with OpenAI &amp;amp; SerpApi&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Get Hotel Details From Tripadvisor And Compare Hotels using Python</title>
      <dc:creator>Sonika Arora</dc:creator>
      <pubDate>Thu, 25 Jun 2026 07:00:36 +0000</pubDate>
      <link>https://dev.to/serpapi/get-hotel-details-from-tripadvisor-and-compare-hotels-using-python-5753</link>
      <guid>https://dev.to/serpapi/get-hotel-details-from-tripadvisor-and-compare-hotels-using-python-5753</guid>
      <description>&lt;p&gt;When people travel, one of the first things they do is compare hotels. Price alone isn’t enough - ratings, amenities, location, and recent reviews all factor into the decision. For developers building travel products, data analysts, or recommendation tools, this means turning rich but messy public data into structured, comparable insights.&lt;/p&gt;

&lt;p&gt;Tripadvisor is one of the most valuable public sources for this kind of hotel intelligence, but extracting structured, comparable data at scale is difficult. In this post, we’ll walk through how to scrape hotel details from Tripadvisor using SerpApi’s Tripadvisor Place Results API with Python, and then compare hotels programmatically using the returned data.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are Tripadvisor Place Results?
&lt;/h2&gt;

&lt;p&gt;The Tripadvisor Place Results page looks like this:&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%2Fqdv6y9lekeh4jz3u1hyb.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%2Fqdv6y9lekeh4jz3u1hyb.png" width="800" height="865"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's an example URL: &lt;a href="https://www.tripadvisor.com/1197076" rel="noopener noreferrer"&gt;https://www.tripadvisor.com/1197076&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A &lt;em&gt;place&lt;/em&gt; on Tripadvisor represents a specific entity such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A hotel&lt;/li&gt;
&lt;li&gt;A restaurant&lt;/li&gt;
&lt;li&gt;An attraction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For hotels, place results typically include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hotel name and Tripadvisor URL&lt;/li&gt;
&lt;li&gt;Rating and reviews&lt;/li&gt;
&lt;li&gt;Pricing&lt;/li&gt;
&lt;li&gt;Address and geographic location&lt;/li&gt;
&lt;li&gt;Pictures and descriptions&lt;/li&gt;
&lt;li&gt;Nearby destinations&lt;/li&gt;
&lt;li&gt;Amenities and categories&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes it a perfect input for hotel comparison workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Hotel Results from Tripadvisor
&lt;/h2&gt;

&lt;p&gt;Using SerpApi, you can request Tripadvisor place results by providing a hotel ID.&lt;/p&gt;

&lt;p&gt;To get the hotel ID (&lt;code&gt;place_id&lt;/code&gt;), you can make a request to our &lt;a href="https://serpapi.com/tripadvisor-search-api" rel="noopener noreferrer"&gt;Tripadvisor Search API&lt;/a&gt; like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set &lt;code&gt;engine&lt;/code&gt; parameter to &lt;code&gt;tripadvisor&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Provide a search query as the location (example: "Rome") and specify the &lt;code&gt;ssrc&lt;/code&gt;(Search Filter) parameter as &lt;code&gt;h&lt;/code&gt; (for Hotels)&lt;/li&gt;
&lt;li&gt;Specify your API key in the &lt;code&gt;api_key&lt;/code&gt; parameter&lt;/li&gt;
&lt;li&gt;Receive structured JSON with all hotels in that location&lt;/li&gt;
&lt;li&gt;Grab the &lt;code&gt;place_id&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's an example in our Playground:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/playground?engine=tripadvisor&amp;amp;q=Rome&amp;amp;ssrc=h" rel="noopener noreferrer"&gt;SerpApi Playground - SerpApi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, for each hotel, we can get the Place Results using the &lt;code&gt;place_id&lt;/code&gt; and sending the request to the &lt;a href="https://serpapi.com/tripadvisor-place-api" rel="noopener noreferrer"&gt;Tripadvisor Place API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The request for getting hotel details looks like:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set &lt;code&gt;engine&lt;/code&gt; parameter to &lt;code&gt;tripadvisor_place&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Provide a &lt;code&gt;place_id&lt;/code&gt; (example: &lt;code&gt;228406&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Specify your API key in the &lt;code&gt;api_key&lt;/code&gt; parameter&lt;/li&gt;
&lt;li&gt;Receive structured JSON with hotel details&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's an example in our Playground:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/playground?engine=tripadvisor_place&amp;amp;place_id=228406" rel="noopener noreferrer"&gt;SerpApi Playground - SerpApi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The response gets us Tripadvisor place data for each hotel that would otherwise require manual parsing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Some Basic Setup Steps
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Setup your environment&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ensure you have the &lt;code&gt;google-search-results&lt;/code&gt; library installed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;google-search-results
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;google-search-results&lt;/code&gt;_&amp;nbsp;_is our Python library. You can use this library to scrape search results from any of SerpApi's APIs.&lt;/p&gt;
&lt;h4&gt;
  
  
  More About Our Python Libraries
&lt;/h4&gt;

&lt;p&gt;We have two separate Python libraries &lt;a href="https://github.com/serpapi/serpapi-python" rel="noopener noreferrer"&gt;&lt;code&gt;serpapi&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/serpapi/google-search-results-python" rel="noopener noreferrer"&gt;&lt;code&gt;google-search-results&lt;/code&gt;&lt;/a&gt;, and both work perfectly fine. However,&amp;nbsp;&lt;code&gt;serpapi&lt;/code&gt;&amp;nbsp;is a new one, and all the examples you can find on our website are from the old one&amp;nbsp;&lt;code&gt;google-search-results&lt;/code&gt;. If you'd like to use our Python library with all the examples from our website, you should install&amp;nbsp;the &lt;code&gt;google-search-results&lt;/code&gt;&amp;nbsp;module instead of&amp;nbsp;&lt;code&gt;serpapi&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For this blog post, I am using &lt;code&gt;google-search-results&lt;/code&gt; because all of our documentation references this one.&lt;/p&gt;

&lt;p&gt;You may encounter issues if you have both libraries installed at the same time. If you have the old library installed and want to proceed with using our new library, please follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Uninstall&amp;nbsp;&lt;code&gt;google-search-results&lt;/code&gt;&amp;nbsp;module from your environment.&lt;/li&gt;
&lt;li&gt;Make sure that neither&amp;nbsp;&lt;code&gt;serpapi&lt;/code&gt;&amp;nbsp;nor&amp;nbsp;&lt;code&gt;google-search-results&lt;/code&gt;&amp;nbsp;are installed at that stage.&lt;/li&gt;
&lt;li&gt;Install&amp;nbsp;&lt;code&gt;serpapi&lt;/code&gt;&amp;nbsp;module, for example with the following command if you're using&amp;nbsp;&lt;code&gt;pip&lt;/code&gt;: &lt;code&gt;pip install serpapi&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;In addition to that, we'll need to install a few more libraries:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://pandas.pydata.org/" rel="noopener noreferrer"&gt;Pandas&lt;/a&gt;: Useful for organizing data. Install this with:&amp;nbsp;&lt;code&gt;pip install pandas&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://matplotlib.org/" rel="noopener noreferrer"&gt;Matplotlib&lt;/a&gt;: Useful for building static plots. Install this with&amp;nbsp;&lt;code&gt;pip install matplotlib&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Get your SerpApi API key&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To begin scraping data, first, create a&amp;nbsp;&lt;a href="https://serpapi.com/users/sign_up" rel="noopener noreferrer"&gt;free account on serpapi.com&lt;/a&gt;. You'll receive 250 free search credits each month to explore the API.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get your SerpApi API Key from&amp;nbsp;&lt;a href="https://serpapi.com/manage-api-key" rel="noopener noreferrer"&gt;this page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;[Optional but Recommended] Set your API key in an environment variable, instead of directly pasting it in the code. Refer&amp;nbsp;&lt;a href="https://developer.vonage.com/en/blog/python-environment-variables-a-primer" rel="noopener noreferrer"&gt;here&lt;/a&gt;&amp;nbsp;to understand more about using environment variables. For this tutorial, I have saved the API key in an environment variable named "SERPAPI_API_KEY" in my .env file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Import Libraries&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Import all the necessary libraries for this project:&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;import&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;serpapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;GoogleSearch&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;matplotlib.pyplot&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;

&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Get Hotel Details using Python
&lt;/h3&gt;

&lt;p&gt;For this tutorial, we'll look for 10 hotels in Rome. Once the setup is complete, here is a a simple Python script to get all hotels in Rome, and get hotels details for each one and add that to a list:&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;hotels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_hotel_results_from_tripadvisor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;params&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;engine&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;tripadvisor&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;q&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api_key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SERPAPI_API_KEY&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;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GoogleSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get_dict&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;results&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;places&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;def&lt;/span&gt; &lt;span class="nf"&gt;get_hotel_details_page_from_tripadvisor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;place_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;params&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;engine&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;tripadvisor_place&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;place_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;place_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api_key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SERPAPI_API_KEY&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;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GoogleSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get_dict&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;results&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;place_result&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="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; __main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Rome&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;place_results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;hotels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_hotel_results_from_tripadvisor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;first_10_hotels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hotels&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;first_10_hotels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;place_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&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;place_id&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;place_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;hotel_details&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_hotel_details_page_from_tripadvisor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;place_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;place_results&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="n"&gt;hotel_details&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Compare Hotels Programmatically
&lt;/h2&gt;

&lt;p&gt;Let's first start by identifying fields that will be of importance to us.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pick The Fields For Fair Comparison
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;To understand a place's identity:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;place_result.name&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;place_result.rating&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;place_result.reviews&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;place_result.hotel_stars&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;place_result.num_rooms&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Useful for competitive context:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;place_result.ranking&lt;/code&gt; → parse numeric rank&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;place_result.reviews&lt;/code&gt; → popularity signal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;For understanding pricing:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;price_range.low&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;price_range.high&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Lowest &lt;code&gt;offers[].extracted_price&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Sub rating across various dimensions:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;These are already numeric and normalized by Tripadvisor, making them perfect for comparison:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Location&lt;/li&gt;
&lt;li&gt;Rooms&lt;/li&gt;
&lt;li&gt;Value&lt;/li&gt;
&lt;li&gt;Cleanliness&lt;/li&gt;
&lt;li&gt;Service&lt;/li&gt;
&lt;li&gt;Sleep Quality&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Review highlights to extract insights from Reviews&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;reviews_highlights.category&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reviews_highlights.value&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 You can ignore summaries &amp;amp; quotes for scoring to keep things quantitative. For qualitative data, the review summaries are a good place to get it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Define a Scoring Strategy
&lt;/h3&gt;

&lt;p&gt;As a simple comparison strategy, we can compute three layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Base Quality Score → from &lt;code&gt;subratings&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Sentiments → from &lt;code&gt;reviews_highlights&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Value-for-Money Score → &lt;code&gt;rating ÷ price&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We can also weight the three differently when computing the final score for a hotel. For this tutorial, we'll use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;60%&lt;/strong&gt; quality score (most reliable)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;25%&lt;/strong&gt; sentiment score (guest opinions)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;15%&lt;/strong&gt; price efficiency score&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's define the plan for how we will use this scoring strategy on the list of place results we have already:&lt;/p&gt;

&lt;p&gt;Get &lt;code&gt;place_results&lt;/code&gt; for each hotel we want to compare&lt;br&gt;&lt;br&gt;
↓&lt;br&gt;&lt;br&gt;
Extract hotel features we want to compare for each hotel&lt;br&gt;&lt;br&gt;
↓&lt;br&gt;&lt;br&gt;
Compute scores for each hotel based on the scoring strategy above&lt;br&gt;&lt;br&gt;
↓&lt;br&gt;&lt;br&gt;
Store the hotel results in a table/dataframe&lt;br&gt;&lt;br&gt;
↓&lt;br&gt;&lt;br&gt;
Sort / filter / plot / export results&lt;/p&gt;
&lt;h3&gt;
  
  
  Code Solution
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;extract_hotel_features&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;place_result&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;HIGHLIGHT_SCORE_MAP&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;Immaculate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;5.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Abundant&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;4.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Convenient&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;4.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Good&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;4.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Inconsistent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;3.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Average&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;3.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Dated&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Outdated&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Pricey&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;hotel&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;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;place_result&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;name&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;rating&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;place_result&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;rating&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;review_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;place_result&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;reviews&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_stars&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;place_result&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;hotel_stars&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;num_rooms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;place_result&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;num_rooms&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="c1"&gt;# Ranking number
&lt;/span&gt;    &lt;span class="n"&gt;ranking&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;place_result&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;ranking&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="n"&gt;ranking&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;city_rank&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="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ranking&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="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;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="c1"&gt;# Price range
&lt;/span&gt;    &lt;span class="n"&gt;price_range&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;place_result&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;price_range&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;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;price_low&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;price_range&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;low&lt;/span&gt;&lt;span class="sh"&gt;"&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;price_high&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;price_range&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;high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Lowest observed price
&lt;/span&gt;    &lt;span class="n"&gt;offers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;place_result&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;prices&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="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;offers&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="n"&gt;offers&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;lowest_price&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="nf"&gt;min&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;extracted_price&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;offers&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;extracted_price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Subratings (primary scoring dimensions)
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;place_result&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;subratings&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;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;category&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;lower&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="s"&gt; &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;span class="n"&gt;hotel&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# Review highlights (sentiment signals)
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;place_result&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;reviews_highlights&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;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;category&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;h&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="n"&gt;hotel&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="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;_sentiment&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;HIGHLIGHT_SCORE_MAP&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;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;3.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;hotel&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compute_scores&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="c1"&gt;# 1. Base quality score (Tripadvisor subratings)
&lt;/span&gt;    &lt;span class="n"&gt;quality_fields&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;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;rooms&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cleanliness&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;service&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;sleep_quality&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;quality_scores&lt;/span&gt; &lt;span class="o"&gt;=&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="n"&gt;f&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;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;quality_fields&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;f&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="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;quality_score&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="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quality_scores&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&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;quality_scores&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="c1"&gt;# 2. Value-for-money score
&lt;/span&gt;    &lt;span class="k"&gt;if&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;lowest_price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&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;rating&lt;/span&gt;&lt;span class="sh"&gt;"&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;value_for_money&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="nf"&gt;round&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;rating&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;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;lowest_price&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;100&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="c1"&gt;# 3. Sentiment score
&lt;/span&gt;    &lt;span class="n"&gt;sentiment_keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;hotel&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;_sentiment&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="n"&gt;sentiment_keys&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;sentiment_score&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="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nf"&gt;sum&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="n"&gt;k&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;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sentiment_keys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&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;sentiment_keys&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="c1"&gt;# 4. Final composite score
&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;overall_score&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="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&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;quality_score&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="mf"&gt;0.6&lt;/span&gt; &lt;span class="o"&gt;+&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;sentiment_score&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="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.25&lt;/span&gt; &lt;span class="o"&gt;+&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;value_for_money&lt;/span&gt;&lt;span class="sh"&gt;"&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;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.15&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="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;hotel&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;With these basic functions in place, we can now compare hotels:&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compare_hotels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;place_results&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;hotels&lt;/span&gt; &lt;span class="o"&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;place_result&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;place_results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;hotel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extract_hotel_features&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;place_result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;hotel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;compute_scores&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="n"&gt;hotels&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="n"&gt;hotel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;hotels_sorted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;hotels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;h&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;overall_score&lt;/span&gt;&lt;span class="sh"&gt;"&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;span class="n"&gt;reverse&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="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;hotels_sorted&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Select only the most useful comparison columns
&lt;/span&gt;    &lt;span class="n"&gt;comparison_df&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;[&lt;br&gt;
                "name",&lt;br&gt;
                "overall_score",&lt;br&gt;
                "quality_score",&lt;br&gt;
                "sentiment_score",&lt;br&gt;
                "value_for_money",&lt;br&gt;
                "rating",&lt;br&gt;
                "review_count",&lt;br&gt;
                "city_rank",&lt;br&gt;
                "price_low",&lt;br&gt;
                "price_high",&lt;br&gt;
                "lowest_price",&lt;br&gt;
            ]&lt;br&gt;
        ]&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    return comparison_df
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Plotting The Results
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Best “at a glance” Ranking&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once we have the &lt;code&gt;comparison_df&lt;/code&gt;, we can now plot the overall scores we computed earlier:&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;plot_hotels_bar_chart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comparison_df&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;matplotlib.pyplot&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;plt&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;comparison_df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort_values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;overall_score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ascending&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;barh&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;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;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;overall_score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xlabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Overall Score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Overall Hotel Comparison&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gca&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;invert_yaxis&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tight_layout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What that looks like:&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%2F6ilf5pxqt7bud0hdc28q.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%2F6ilf5pxqt7bud0hdc28q.png" width="799" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Price comparison (range chart)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's understand the price spread per hotel.&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;plot_price_transparency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comparison_df&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;figure&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;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comparison_df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;itertuples&lt;/span&gt;&lt;span class="p"&gt;()):&lt;/span&gt;
        &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;[row.price_low, row.price_high],&lt;br&gt;
[i, i],&lt;br&gt;
                marker="o"&lt;br&gt;
            )&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    plt.yticks(range(len(comparison_df)), comparison_df["name"])
    plt.xlabel("Price (€)")
    plt.title("Hotel Price Ranges")
    plt.tight_layout()
    plt.show()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Calling this function plots a graph which makes pricing transparent:&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%2Ftz8p7sc1m9imzq5chfck.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%2Ftz8p7sc1m9imzq5chfck.png" width="800" height="599"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Use Cases
&lt;/h2&gt;

&lt;p&gt;This workflow is especially useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Travel startups&lt;/strong&gt; building hotel comparison products&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data teams&lt;/strong&gt; analyzing hotel trends&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SEO teams&lt;/strong&gt; creating location-based hotel content&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Investors and analysts&lt;/strong&gt; tracking hotel performance across regions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of manually browsing Tripadvisor for each hotel, you get structured, comparable insights at scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope that this tutorial helps you use SerpApi's Tripadvisor Place Results API and reliably extract hotel details and compare hotels in any destinations with minimal effort.&lt;/p&gt;

&lt;p&gt;You can find all the code used in this blog post here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/sonika-serpapi/get-hotel-details-from-trip-advisor-and-compare-hotels" rel="noopener noreferrer"&gt;https://github.com/sonika-serpapi/get-hotel-details-from-trip-advisor-and-compare-hotels&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feel free to reach out to us at &lt;a href="mailto:contact@serpapi.com"&gt;contact@serpapi.com&lt;/a&gt; for any questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Relevant Links
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Documentation
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/tripadvisor-search-api" rel="noopener noreferrer"&gt;Documentation for Tripadvisor Search API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/tripadvisor-place-api" rel="noopener noreferrer"&gt;Documentation for Tripadvisor Place API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/use-cases/travel-information" rel="noopener noreferrer"&gt;Use Case Page: Build a Travel App Using SERP data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/status/tripadvisor_place" rel="noopener noreferrer"&gt;Status page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/pricing" rel="noopener noreferrer"&gt;Plans and Pricing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Related Posts
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/how-to-scrape-tripadvisor-tutorial/" rel="noopener noreferrer"&gt;How to scrape Tripadvisor (2025 Tutorial)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/how-to-make-a-travel-guide-using-serp-data-and-python/" rel="noopener noreferrer"&gt;How To Make a Travel Guide Using SERP data and Python&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/scraping-google-hotels/" rel="noopener noreferrer"&gt;How to scrape Google Hotels Data (Tutorial 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/making-a-hotel-price-tracker-with-google-hotels-and-n8n/" rel="noopener noreferrer"&gt;Making a Hotel Price Tracker with Google Hotels and n8n&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Scrape News Results from Baidu to CSV with Python</title>
      <dc:creator>Sonika Arora</dc:creator>
      <pubDate>Wed, 24 Jun 2026 07:09:36 +0000</pubDate>
      <link>https://dev.to/serpapi/scrape-news-results-from-baidu-to-csv-with-python-jgc</link>
      <guid>https://dev.to/serpapi/scrape-news-results-from-baidu-to-csv-with-python-jgc</guid>
      <description>&lt;p&gt;Baidu is the dominant search engine in China, and Baidu News is a critical source for understanding media coverage, brand sentiment, and trending topics in the Chinese market. However, scraping Baidu directly is notoriously difficult due to aggressive bot detection, regional constraints, and frequent HTML changes.&lt;/p&gt;

&lt;p&gt;In this post, we’ll walk through how to scrape Baidu News using SerpApi.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use SerpApi To Scrape News From Baidu
&lt;/h2&gt;

&lt;p&gt;If you’ve tried scraping Baidu directly, you’ve likely run into issues such as a dynamic HTML, frequent layout changes, javaScript-rendered elements, Chinese - specific quirks (encodings, redirects, tracking parameters). For production use cases, brand monitoring, market research, competitive intelligence, DIY scraping quickly becomes impractical.&lt;/p&gt;

&lt;p&gt;That’s where SerpApi’s Baidu News API comes in. It's a structured API, which returns a clean JSON response. SerpApi manages the intricacies of scraping and returns structured JSON results. This allows you to save time and effort by avoiding the need to build your own Baidu scraper using generic web scraping frameworks like BeautifulSoup which require constant maintenance. We do all the work to maintain all of our parsers and adapt them to respond to changes on search engines. By taking care of this for you on our side, we eliminate a lot of time and complexity from your workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  About Baidu News API
&lt;/h2&gt;

&lt;p&gt;Baidu News API&amp;nbsp;returns structured news data from Baidu News pages. The API returns structured fields such as title, link, source, date, and snippet.&lt;/p&gt;

&lt;p&gt;At a minimum, you need the following parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;engine&lt;/code&gt; - set to &lt;code&gt;baidu_news&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;q&lt;/code&gt; (search query) - set to your query&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;api_key&lt;/code&gt; - set to your private API key&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is an example of the information the API scrapes:&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%2F8hyk7u5gaskbp5flsdhx.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%2F8hyk7u5gaskbp5flsdhx.png" width="800" height="964"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Get results using a simple GET request
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://serpapi.com/search.json?engine=baidu_news&amp;amp;q=Artificial+Intelligence&amp;amp;api_key=YOUR_API_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This request searches the Baidu News search engine for Artificial Intelligence and provides JSON results. Try it out on our playground:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/playground?engine=baidu_news&amp;amp;q=Artificial+Intelligence" rel="noopener noreferrer"&gt;SerpApi Playground - SerpApi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  An Example Use Case
&lt;/h2&gt;

&lt;p&gt;Let's write some code to extract Baidu News results for Phones and write them to a CSV.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup your environment
&lt;/h3&gt;

&lt;p&gt;Ensure you have the necessary libraries installed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;google-search-results
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;google-search-results&lt;/code&gt;_&amp;nbsp;_is our Python library. You can use this library to scrape search results from any of SerpApi's APIs.&lt;/p&gt;
&lt;h4&gt;
  
  
  More About Our Python Libraries
&lt;/h4&gt;

&lt;p&gt;We have two separate Python libraries &lt;a href="https://github.com/serpapi/serpapi-python" rel="noopener noreferrer"&gt;&lt;code&gt;serpapi&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/serpapi/google-search-results-python" rel="noopener noreferrer"&gt;&lt;code&gt;google-search-results&lt;/code&gt;&lt;/a&gt;, and both work perfectly fine. However,&amp;nbsp;&lt;code&gt;serpapi&lt;/code&gt;&amp;nbsp;is a new one, and all the examples you can find on our website are from the old one&amp;nbsp;&lt;code&gt;google-search-results&lt;/code&gt;. If you'd like to use our Python library with all the examples from our website, you should install&amp;nbsp;the &lt;code&gt;google-search-results&lt;/code&gt;&amp;nbsp;module instead of&amp;nbsp;&lt;code&gt;serpapi&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For this blog post, I am using &lt;code&gt;google-search-results&lt;/code&gt; because all of our documentation references this one.&lt;/p&gt;

&lt;p&gt;You may encounter issues if you have both libraries installed at the same time. If you have the old library installed and want to proceed with using our new library, please follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Uninstall&amp;nbsp;&lt;code&gt;google-search-results&lt;/code&gt;&amp;nbsp;module from your environment.&lt;/li&gt;
&lt;li&gt;Make sure that neither&amp;nbsp;&lt;code&gt;serpapi&lt;/code&gt;&amp;nbsp;nor&amp;nbsp;&lt;code&gt;google-search-results&lt;/code&gt;&amp;nbsp;are installed at that stage.&lt;/li&gt;
&lt;li&gt;Install&amp;nbsp;&lt;code&gt;serpapi&lt;/code&gt;&amp;nbsp;module, for example with the following command if you're using&amp;nbsp;&lt;code&gt;pip&lt;/code&gt;: &lt;code&gt;pip install serpapi&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Get your SerpApi API key
&lt;/h3&gt;

&lt;p&gt;To begin scraping data, first, create a&amp;nbsp;&lt;a href="https://serpapi.com/users/sign_up" rel="noopener noreferrer"&gt;free account on serpapi.com&lt;/a&gt;. You'll receive 250 free search credits each month to explore the API.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get your SerpApi API Key from&amp;nbsp;&lt;a href="https://serpapi.com/manage-api-key" rel="noopener noreferrer"&gt;this page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;[Optional but Recommended] Set your API key in an environment variable, instead of directly pasting it in the code. Refer&amp;nbsp;&lt;a href="https://developer.vonage.com/en/blog/python-environment-variables-a-primer" rel="noopener noreferrer"&gt;here&lt;/a&gt;&amp;nbsp;to understand more about using environment variables. For this tutorial, I have saved the API key in an environment variable named "SERPAPI_API_KEY" in my .env file.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Using Baidu News API
&lt;/h3&gt;

&lt;p&gt;First, we'll write a simple function to get news results from the Baidu News API:&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_baidu_news&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;params&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;engine&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;baidu_news&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;q&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api_key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SERPAPI_API_KEY&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;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GoogleSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get_dict&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;results&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;organic_results&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Writing Results To a CSV
&lt;/h3&gt;

&lt;p&gt;Then, we can write a simple script to call this function and write the news results to CSV:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if __name__ == " __main__":
    q = "Phones"
    output_file = "baidu_news_results.csv"

    header = ["position", "title", "link", "date", "snippet", "source", "thumbnail"]

    with open(output_file, "w", encoding="UTF8", newline="") as f:
        writer = csv.writer(f)
        writer.writerow(header)

        results = get_baidu_news(q)
        for r in results:
            writer.writerow([
                r.get("position", ""),
                r.get("title", ""),
                r.get("link", ""),
                r.get("date", ""),
                r.get("snippet", ""),
                r.get("source", ""),
                r.get("thumbnail", "")
            ])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can run this script to fetch Baidu News results for the query “Phones.” Then, this creates a CSV file called &lt;code&gt;baidu_news_results.csv&lt;/code&gt; and writes a header row that defines each column. You can then call &lt;code&gt;get_baidu_news&lt;/code&gt; to retrieve the results and loop through them. For each result, it safely extracts the fields and writes them as rows in the CSV file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Results
&lt;/h3&gt;

&lt;p&gt;Here's what the results look like:&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%2Fm3ff18t1paodi9b9yqo1.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%2Fm3ff18t1paodi9b9yqo1.png" width="798" height="207"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Localization
&lt;/h2&gt;

&lt;p&gt;Use the &lt;code&gt;ct&lt;/code&gt; parameter to control the language of the results returned. Set this when you want to restrict results to a specific Chinese language variant.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;1&lt;/code&gt; — All languages (default)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;2&lt;/code&gt; — Simplified Chinese&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;3&lt;/code&gt; — Traditional Chinese&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Adding Pagination
&lt;/h2&gt;

&lt;p&gt;Use the &lt;code&gt;pn&lt;/code&gt;, &lt;code&gt;rn&lt;/code&gt; parameters together to control paging and result count. Use &lt;code&gt;pn&lt;/code&gt; and &lt;code&gt;rn&lt;/code&gt; together to paginate through large result sets.&lt;/p&gt;

&lt;h3&gt;
  
  
  Result Offset
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;pn&lt;/code&gt;parameter defines how many results to skip, and is used to move through pages of results.&lt;/li&gt;
&lt;li&gt;Examples:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;pn=0&lt;/code&gt; → first page (default)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pn=10&lt;/code&gt; → second page&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pn=20&lt;/code&gt; → third page&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Results per Page
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use the &lt;code&gt;rn&lt;/code&gt; parameter defines the maximum number of results to return. (max: 50)&lt;/li&gt;
&lt;li&gt;Examples:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;rn=10&lt;/code&gt; → return 10 results (default)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rn=30&lt;/code&gt; → return 30 results&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rn=50&lt;/code&gt; → return 50 results&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Couple of Advanced Parameters
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Sorting the results
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;rtt&lt;/code&gt; parameter controls how results are ordered. Set this to a particular value when freshness matters more than relevance or vice versa.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;1&lt;/code&gt; — Sort by attraction/relevance (default)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;4&lt;/code&gt; — Sort by time (most recent first)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Medium Filter
&lt;/h3&gt;

&lt;p&gt;Filters results by content source using the &lt;code&gt;medium&lt;/code&gt; parameter. Use this to limit results to specific publisher types or platforms.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;0&lt;/code&gt; — No filtering (default)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;1&lt;/code&gt; — Only medium-authority sites&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;2&lt;/code&gt; — Only Baijiahao sources (&lt;code&gt;baijiahao.baidu.com&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these parameters are optional, but combining localization, pagination, and filters gives you precise control over the Baidu News results you receive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Scraping Baidu News directly is fragile and time-consuming. I hope this tutorial helped you understand how to use SerpApi’s Baidu News API to get clean, structured news data with production-ready reliability.&lt;/p&gt;

&lt;p&gt;If you’re building anything that depends on Chinese news visibility, this is the fastest and easiest way to get started.&lt;/p&gt;

&lt;p&gt;Feel free to reach out to us at &lt;a href="mailto:contact@serpapi.com"&gt;contact@serpapi.com&lt;/a&gt; for any questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Relevant Links
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Documentation
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/baidu-news-api" rel="noopener noreferrer"&gt;Documentation for Baidu News API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/status/baidu_news" rel="noopener noreferrer"&gt;Status page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/pricing" rel="noopener noreferrer"&gt;Plans and Pricing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Related Posts
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/serpapis-baidu-search-api/" rel="noopener noreferrer"&gt;SerpApi’s Baidu Search API&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/python-web-scraping-tutorial/" rel="noopener noreferrer"&gt;Web Scraping in Python (Complete Tutorial 2025)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Scrape Reviews From OpenTable to CSV with Python</title>
      <dc:creator>Sonika Arora</dc:creator>
      <pubDate>Tue, 23 Jun 2026 07:07:45 +0000</pubDate>
      <link>https://dev.to/serpapi/scrape-reviews-from-opentable-to-csv-with-python-5e4j</link>
      <guid>https://dev.to/serpapi/scrape-reviews-from-opentable-to-csv-with-python-5e4j</guid>
      <description>&lt;p&gt;OpenTable is one of the most influential platforms for restaurant reservations and diner feedback. Whether you're doing sentiment analysis, building a restaurant discovery app, or tracking customer satisfaction, accessing review data can be incredibly valuable.&lt;/p&gt;

&lt;p&gt;SerpApi’s OpenTable Reviews API allows you to scrape OpenTable reviews reliably and at scale.&lt;/p&gt;

&lt;p&gt;In this post, we’ll walk through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What the SerpApi OpenTable Reviews API is and what data you can extract&lt;/li&gt;
&lt;li&gt;How to integrate it using Python&lt;/li&gt;
&lt;li&gt;Pagination and Localization&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Use SerpApi?
&lt;/h2&gt;

&lt;p&gt;SerpApi streamlines the process of web-scraping. We take care of proxies and any CAPTCHAs that might be encountered, so that you don't have to worry about your searches being blocked. If you were to implement your own scraper using tools like BeautifulSoup and Requests, you'd need to determine your own solution for this. SerpApi manages the intricacies of scraping and returns structured JSON results. This allows you to save time and effort by avoiding the need to build your own OpenTable scraper or rely on other web scraping tools.&lt;/p&gt;

&lt;p&gt;We also do all the work to maintain all of our parsers and adapt them to respond to changes on search engines. This is important, as search engines like OpenTable are constantly experimenting with new layouts, new elements, and other changes. By taking care of this for you on our side, we eliminate a lot of time and complexity from your workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  About the OpenTable Reviews API
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://serpapi.com/open-table-reviews-api" rel="noopener noreferrer"&gt;OpenTable Reviews API&lt;/a&gt; returns structured review data from OpenTable restaurant pages.&lt;/p&gt;

&lt;p&gt;The API returns structured review fields such as Reviewer name, Review date, Attached Images, Rating, Text content, Rating and AI summary, and Pagination tokens.&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%2Fuaygwe6tok5blje1j6o9.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%2Fuaygwe6tok5blje1j6o9.png" width="602" height="1136"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can try it out in our playground, where you can visualize the response with various parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/playground?engine=open_table_reviews&amp;amp;place_id=central-park-boathouse-new-york-2" rel="noopener noreferrer"&gt;SerpApi Playground - SerpApi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  An Example Use Case
&lt;/h2&gt;

&lt;p&gt;Let's write some code to extract OpenTable reviews for Nobu Palo Alto and write them to a CSV.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup your environment
&lt;/h3&gt;

&lt;p&gt;Ensure you have the necessary libraries installed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;google-search-results
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;google-search-results&lt;/code&gt;_&amp;nbsp;_is our Python library. You can use this library to scrape search results from any of SerpApi's APIs.&lt;/p&gt;
&lt;h4&gt;
  
  
  More About Our Python Libraries
&lt;/h4&gt;

&lt;p&gt;We have two separate Python libraries &lt;a href="https://github.com/serpapi/serpapi-python" rel="noopener noreferrer"&gt;&lt;code&gt;serpapi&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/serpapi/google-search-results-python" rel="noopener noreferrer"&gt;&lt;code&gt;google-search-results&lt;/code&gt;&lt;/a&gt;, and both work perfectly fine. However,&amp;nbsp;&lt;code&gt;serpapi&lt;/code&gt;&amp;nbsp;is a new one, and all the examples you can find on our website are from the old one&amp;nbsp;&lt;code&gt;google-search-results&lt;/code&gt;. If you'd like to use our Python library with all the examples from our website, you should install&amp;nbsp;the &lt;code&gt;google-search-results&lt;/code&gt;&amp;nbsp;module instead of&amp;nbsp;&lt;code&gt;serpapi&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For this blog post, I am using &lt;code&gt;google-search-results&lt;/code&gt; because all of our documentation references this one.&lt;/p&gt;

&lt;p&gt;You may encounter issues if you have both libraries installed at the same time. If you have the old library installed and want to proceed with using our new library, please follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Uninstall&amp;nbsp;&lt;code&gt;google-search-results&lt;/code&gt;&amp;nbsp;module from your environment.&lt;/li&gt;
&lt;li&gt;Make sure that neither&amp;nbsp;&lt;code&gt;serpapi&lt;/code&gt;&amp;nbsp;nor&amp;nbsp;&lt;code&gt;google-search-results&lt;/code&gt;&amp;nbsp;are installed at that stage.&lt;/li&gt;
&lt;li&gt;Install&amp;nbsp;&lt;code&gt;serpapi&lt;/code&gt;&amp;nbsp;module, for example with the following command if you're using&amp;nbsp;&lt;code&gt;pip&lt;/code&gt;: &lt;code&gt;pip install serpapi&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Get your SerpApi API key
&lt;/h3&gt;

&lt;p&gt;To begin scraping data, first, create a&amp;nbsp;&lt;a href="https://serpapi.com/users/sign_up" rel="noopener noreferrer"&gt;free account on serpapi.com&lt;/a&gt;. You'll receive 250 free search credits each month to explore the API.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get your SerpApi API Key from&amp;nbsp;&lt;a href="https://serpapi.com/manage-api-key" rel="noopener noreferrer"&gt;this page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;[Optional but Recommended] Set your API key in an environment variable, instead of directly pasting it in the code. Refer&amp;nbsp;&lt;a href="https://developer.vonage.com/en/blog/python-environment-variables-a-primer" rel="noopener noreferrer"&gt;here&lt;/a&gt;&amp;nbsp;to understand more about using environment variables. For this tutorial, I have saved the API key in an environment variable named "SERPAPI_API_KEY" in my .env file.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Using OpenTable Reviews API
&lt;/h3&gt;

&lt;p&gt;First, we'll write a simple function to get reviews from the OpenTable Reviews API:&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_opentable_reviews&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;place_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;params&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;engine&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;open_table_reviews&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;place_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;place_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api_key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SERPAPI_API_KEY&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;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GoogleSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get_dict&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;results&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;reviews&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Writing Results To a CSV
&lt;/h3&gt;

&lt;p&gt;First, we need to get the &lt;code&gt;place_id&lt;/code&gt; for Nobu Palo Alto. This identifier can be found in the URL of the restaurant's page on OpenTable, immediately following&amp;nbsp;&lt;code&gt;/r/&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;For Nobu Palo Alto, the URL&amp;nbsp;is &lt;code&gt;https://www.opentable.com/r/nobu-palo-alto&lt;/code&gt; , and so the ID is&amp;nbsp;&lt;code&gt;nobu-palo-alto&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then, we can write a simple script to call this function and write the reviews to CSV:&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; __main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;place_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nobu-palo-alto&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;output_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;opentable_reviews.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="n"&gt;header&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;submitted_at&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;id&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;user_name&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;rating&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;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;UTF8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newline&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writerow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;reviews&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_opentable_reviews&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;place_id&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;reviews&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writerow&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="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;submitted_at&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="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="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;id&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="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="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;user&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="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;name&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="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="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;rating&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="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;overall&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="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="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;content&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="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This block runs only when the script is executed directly. We set the &lt;code&gt;place_id&lt;/code&gt; and create a new CSV file with the appropriate header. We then fetch the OpenTable reviews using &lt;code&gt;get_opentable_reviews()&lt;/code&gt;, and for each review, we write a row to the CSV. We safely extract fields like the submission date, review ID, username, rating, and content so the script won’t break if any data is missing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Results
&lt;/h3&gt;

&lt;p&gt;Here's what the results look like:&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%2Fxpp3csjtgot1h465w7dh.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%2Fxpp3csjtgot1h465w7dh.png" width="799" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Pagination with &lt;code&gt;page&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;OpenTable has more reviews than those served on the first page with our Reviews API. We can use the parameter &lt;code&gt;page&lt;/code&gt;&amp;nbsp;for further data retrieval and page navigation.&lt;/p&gt;

&lt;p&gt;This parameter defines the page number.&amp;nbsp;&lt;code&gt;1&lt;/code&gt;&amp;nbsp;(default) is the first page of 10 results,&amp;nbsp;&lt;code&gt;2&lt;/code&gt;&amp;nbsp;is the 2nd page, etc. To get more results beyond the ones we just got, you can make the same request with &lt;code&gt;page&lt;/code&gt; set to &lt;code&gt;2&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt; and so on depending on the number of reviews available and the number of reviews you want to retrieve.&lt;/p&gt;

&lt;h3&gt;
  
  
  Localization
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;open_table_domain&lt;/code&gt; parameter defines the OpenTable domain to use. You can localize the request if you are looking for results from another domain for Opentable besides &lt;a href="http://www.opentable.com" rel="noopener noreferrer"&gt;www.opentable.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can view the&amp;nbsp;&lt;a href="https://serpapi.com/open-table-domains" rel="noopener noreferrer"&gt;OpenTable domains page&lt;/a&gt;&amp;nbsp;for a full list of supported OpenTable domains.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Using the SerpApi OpenTable Reviews API simplifies the process of collecting high-quality, structured review data. Instead of spending time building and maintaining a fragile scraper, you get to focus on the valuable part: analyzing the customer sentiment and insights hidden within the reviews.&lt;/p&gt;

&lt;p&gt;I hope this blog post was helpful in understanding how to you can write a simple script to scrape reviews from OpenTable. If you have any questions, don't hesitate to reach out to me at &lt;a href="mailto:sonika@serpapi.com"&gt;sonika@serpapi.com&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Relevant Links
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Documentation
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/open-table-reviews-api" rel="noopener noreferrer"&gt;Documentation for OpenTable Reviews API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/status/open_table_reviews" rel="noopener noreferrer"&gt;Status page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/pricing" rel="noopener noreferrer"&gt;Plans and Pricing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Related Posts
&lt;/h4&gt;

&lt;p&gt;Scrape reviews from other search engines like Google Maps and Yelp:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/scrape-google-maps-data-and-reviews-using-python/" rel="noopener noreferrer"&gt;Scrape Google Maps data and reviews using Python&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/how-to-scrape-yelp-data-places-and-reviews/" rel="noopener noreferrer"&gt;How to scrape Yelp data using Python (Places and Reviews)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/how-to-scrape-google-maps-contributor-reviews/" rel="noopener noreferrer"&gt;How To Scrape Google Maps Contributor Reviews&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
  </channel>
</rss>
