<?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: Stella Lin</title>
    <description>The latest articles on DEV Community by Stella Lin (@stella_lin).</description>
    <link>https://dev.to/stella_lin</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%2F4140236%2F66d11055-b79e-48fe-82c3-c09868b4eac1.jpg</url>
      <title>DEV Community: Stella Lin</title>
      <link>https://dev.to/stella_lin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stella_lin"/>
    <language>en</language>
    <item>
      <title>How to Scrape Bing Search Results: 4 Practical Methods</title>
      <dc:creator>Stella Lin</dc:creator>
      <pubDate>Sun, 27 Sep 2026 13:47:03 +0000</pubDate>
      <link>https://dev.to/stella_lin/how-to-scrape-bing-search-results-4-practical-methods-4o8n</link>
      <guid>https://dev.to/stella_lin/how-to-scrape-bing-search-results-4-practical-methods-4o8n</guid>
      <description>&lt;p&gt;Bing results are easy to copy until you need the same query every week, several pages of results, or a dataset that another developer can reproduce.&lt;/p&gt;

&lt;p&gt;The practical choice depends on how much control you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use an &lt;strong&gt;Octoparse template&lt;/strong&gt; for a fast, standard keyword export.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Octoparse API or MCP&lt;/strong&gt; when a verified workflow must run repeatedly.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Octoparse Desktop&lt;/strong&gt; when you need custom fields, pagination, or filtering.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Python or a SERP service&lt;/strong&gt; when extraction is one component of a larger application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One important boundary: Microsoft retired the Bing Search APIs on August 11, 2025. Microsoft points customers toward Grounding with Bing Search for Azure AI agent grounding, which is a different product from collecting visible result rows. This guide focuses on browser-based extraction and code-first parsing, not on a hidden Bing API.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does it mean to scrape Bing search results?
&lt;/h2&gt;

&lt;p&gt;Scraping Bing search results means turning a visible result page into structured rows. A useful row normally includes the input keyword, result title, destination URL, description, and source name. A custom workflow can also record position, result type, sponsored status, related questions, or data from the destination page.&lt;/p&gt;

&lt;p&gt;That is different from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Crawling a website&lt;/strong&gt;, which discovers pages by following links across a domain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bingbot&lt;/strong&gt;, which is Microsoft's crawler for its search index.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grounding with Bing Search&lt;/strong&gt;, which supplies web context to an Azure AI agent rather than exporting a SERP table.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal here is a repeatable table that you can inspect, compare, and export.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four ways to scrape Bing, from easiest to most flexible
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;th&gt;Setup&lt;/th&gt;
&lt;th&gt;Main trade-off&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Octoparse template&lt;/td&gt;
&lt;td&gt;One-off or small batches of standard keyword results&lt;/td&gt;
&lt;td&gt;Lowest&lt;/td&gt;
&lt;td&gt;Inputs and fields follow the template schema&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Octoparse API or MCP&lt;/td&gt;
&lt;td&gt;Scheduled jobs, agents, and repeatable cloud runs&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;Automates supported Octoparse workflows; it is not a Bing API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Octoparse Desktop&lt;/td&gt;
&lt;td&gt;Custom fields, pagination, filters, and visual debugging&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;You own more setup and testing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python or a SERP service&lt;/td&gt;
&lt;td&gt;Code-first products and custom post-processing&lt;/td&gt;
&lt;td&gt;Highest&lt;/td&gt;
&lt;td&gt;Selectors, throttling, maintenance, and service cost remain your responsibility&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Start with the smallest method that can answer the question. Automate only after the output schema is useful. Move to Desktop or Python when the standard fields stop matching the dataset your application needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Method 1: use the Bing Search Results Scraper template
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.octoparse.com/template/bing-search-results-scraper" rel="noopener noreferrer"&gt;Bing Search Results Scraper template&lt;/a&gt; is the shortest path from a keyword to a spreadsheet. It accepts a language, country or area, one or more keywords, and a page count. You can run it from the browser or the Octoparse app without building selectors.&lt;/p&gt;

&lt;h3&gt;
  
  
  A repeatable template workflow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Select the language and market you want to observe.&lt;/li&gt;
&lt;li&gt;Enter one keyword per line.&lt;/li&gt;
&lt;li&gt;Set the number of result pages.&lt;/li&gt;
&lt;li&gt;Run one representative query.&lt;/li&gt;
&lt;li&gt;Inspect the rows before exporting.&lt;/li&gt;
&lt;li&gt;Export only after the fields and result types look correct.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do not treat a completed run as proof of a good dataset. Check row count, duplicates, empty cells, redirect URLs, and the difference between sponsored and organic results.&lt;/p&gt;

&lt;h3&gt;
  
  
  What one documented test returned
&lt;/h3&gt;

&lt;p&gt;The original Octoparse article reports a reproducible test run completed on August 21, 2026 with the keyword &lt;code&gt;web scraping&lt;/code&gt;, the United States market, and one page of results:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Observed value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Run time&lt;/td&gt;
&lt;td&gt;1 minute 10 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rows&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reported duplicates&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Export columns&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Keyword&lt;/code&gt;, &lt;code&gt;Title&lt;/code&gt;, &lt;code&gt;Link&lt;/code&gt;, &lt;code&gt;Description&lt;/code&gt;, &lt;code&gt;Source&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CSV size&lt;/td&gt;
&lt;td&gt;9,239 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is one test, not a guaranteed benchmark. The result included both sponsored and organic rows, and some sponsored rows had an empty &lt;code&gt;Link&lt;/code&gt; field. Query, market, page layout, and run conditions can change the result.&lt;/p&gt;

&lt;h3&gt;
  
  
  Validate the template output
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;What it represents&lt;/th&gt;
&lt;th&gt;What to check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Keyword&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The input query associated with the row&lt;/td&gt;
&lt;td&gt;Market and spelling match the request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Title&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The visible result headline&lt;/td&gt;
&lt;td&gt;Ads, truncation, and missing text&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Link&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Captured destination or tracking URL&lt;/td&gt;
&lt;td&gt;Empty values, redirects, and canonical URL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Description&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Visible result snippet&lt;/td&gt;
&lt;td&gt;Missing or changing snippets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Source&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Visible publisher or source name&lt;/td&gt;
&lt;td&gt;Empty or inconsistent values&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Try the standard path:&lt;/strong&gt; run one keyword through the &lt;a href="https://www.octoparse.com/template/bing-search-results-scraper" rel="noopener noreferrer"&gt;Bing Search Results Scraper template&lt;/a&gt;, inspect the first page, and export only the checked rows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Method 2: automate a verified workflow with API or MCP
&lt;/h2&gt;

&lt;p&gt;Once a template or cloud task returns the fields you need, the next step is usually automation, not a complete rebuild.&lt;/p&gt;

&lt;p&gt;Use the &lt;strong&gt;Octoparse API&lt;/strong&gt; when code, a scheduler, n8n, Make, or an internal application needs deterministic control. Use &lt;strong&gt;Octoparse MCP&lt;/strong&gt; when a compatible AI client should discover or run supported Octoparse workflows conversationally.&lt;/p&gt;

&lt;p&gt;Both are control layers for Octoparse. They do not expose a replacement Bing Search API. The extraction definition still comes from a supported template or cloud task.&lt;/p&gt;

&lt;p&gt;A safe automation boundary looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;searchTemplates -&amp;gt; executeTask -&amp;gt; exportData
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your application should verify all of the following before accepting the result:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The selected template or task matches the intended input schema.&lt;/li&gt;
&lt;li&gt;The run reaches a terminal success state.&lt;/li&gt;
&lt;li&gt;The export contains rows instead of an empty file.&lt;/li&gt;
&lt;li&gt;Required columns are present.&lt;/li&gt;
&lt;li&gt;The exported artifact is readable and stored with its query, market, and collection time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;An &lt;code&gt;accepted&lt;/code&gt; response means a task was created. It does not prove that a usable export is ready.&lt;/p&gt;

&lt;p&gt;Keep API keys out of prompts, screenshots, and source control. Store secrets in an environment variable or secret manager, and rotate a key if it is exposed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automate a verified run:&lt;/strong&gt; connect the &lt;a href="https://helpcenter.octoparse.com/en/articles/15855832-run-a-scraping-workflow-with-the-octoparse-agenttools-api" rel="noopener noreferrer"&gt;Octoparse API workflow&lt;/a&gt; only after a manual test has confirmed the schema and result quality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Method 3: build a custom workflow in Octoparse Desktop
&lt;/h2&gt;

&lt;p&gt;Use &lt;a href="https://www.octoparse.com/download" rel="noopener noreferrer"&gt;Octoparse Desktop&lt;/a&gt; when the prepared template returns almost what you need, but not quite.&lt;/p&gt;

&lt;p&gt;Desktop is useful when you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;separate sponsored blocks from organic results;&lt;/li&gt;
&lt;li&gt;keep an explicit result-position field;&lt;/li&gt;
&lt;li&gt;normalize tracking URLs;&lt;/li&gt;
&lt;li&gt;add pagination or waits;&lt;/li&gt;
&lt;li&gt;handle missing descriptions;&lt;/li&gt;
&lt;li&gt;rename or remove columns; or&lt;/li&gt;
&lt;li&gt;test the workflow against several localized result pages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A practical Desktop workflow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open a representative Bing result URL in the built-in browser.&lt;/li&gt;
&lt;li&gt;Let auto-detection create an initial field set.&lt;/li&gt;
&lt;li&gt;Review the preview table and rename fields to your own schema.&lt;/li&gt;
&lt;li&gt;Add pagination, waits, or filters where the page requires them.&lt;/li&gt;
&lt;li&gt;Test a second query and market before scaling.&lt;/li&gt;
&lt;li&gt;Run and export only after the preview contains usable rows.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The preview is a schema test, not a promise that every future Bing page will behave the same way. Search layouts, result types, and localized pages change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Method 4: scrape Bing with Python
&lt;/h2&gt;

&lt;p&gt;Python makes sense when search extraction is one step inside a maintained application. You can normalize the rows, store them in a database, compare snapshots, or feed them into a ranking-analysis pipeline.&lt;/p&gt;

&lt;p&gt;The following example is a minimal starting point for standard organic result cards. It is not a production scraper. Bing markup, localized layouts, throttling, and access rules can change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;__future__&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;annotations&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;bs4&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BeautifulSoup&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch_bing_results&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="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;dict&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;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://www.bing.com/search&lt;/span&gt;&lt;span class="sh"&gt;"&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;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;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;count&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User-Agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Mozilla/5.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;soup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BeautifulSoup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;html.parser&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;dict&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;card&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;li.b_algo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;heading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;h2 a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;snippet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.b_caption p&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;heading&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;rows&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="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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;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;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="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;strip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="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="n"&gt;heading&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;href&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;description&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;snippet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="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;strip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;snippet&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
                &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;rows&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="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="nf"&gt;fetch_bing_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;web scraping&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before using code at scale, add bounded retries, respectful delays, logging, schema checks, and a stop condition. If you buy a maintained SERP interface instead, compare supported markets, data provenance, freshness, rate limits, retention, and total scenario cost rather than only the advertised price per request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Store provenance with every result
&lt;/h2&gt;

&lt;p&gt;A SERP row without context becomes difficult to trust a week later. Store the input and collection conditions next to the result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timezone&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_provenance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&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;market&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&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="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;market&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;market&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;method&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;page&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;collected_at&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timezone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utc&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;isoformat&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;At minimum, keep:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the exact query;&lt;/li&gt;
&lt;li&gt;language and country or area;&lt;/li&gt;
&lt;li&gt;collection timestamp and timezone;&lt;/li&gt;
&lt;li&gt;page number and requested page count;&lt;/li&gt;
&lt;li&gt;extraction method and task version;&lt;/li&gt;
&lt;li&gt;sponsored versus organic classification; and&lt;/li&gt;
&lt;li&gt;the original link before redirect or URL cleanup.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes duplicate checks, ranking comparisons, and debugging much easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which method should you choose?
&lt;/h2&gt;

&lt;p&gt;Choose based on the next decision your team needs to make:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One-off keyword research:&lt;/strong&gt; use the template and export CSV or Excel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weekly monitoring:&lt;/strong&gt; validate the template first, then automate it with API or MCP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom SERP schema:&lt;/strong&gt; use Desktop for position, result type, pagination, or URL cleanup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Product engineering:&lt;/strong&gt; use Python or a maintained SERP service when rows must flow directly into application code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the research covers more than one search engine, compare the differences rather than forcing every result page into one schema. Market, layout, ranking rules, and result types are not interchangeable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quality and responsible-collection checklist
&lt;/h2&gt;

&lt;p&gt;Public visibility does not remove every obligation. Before scaling a workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;review current terms and applicable policies;&lt;/li&gt;
&lt;li&gt;avoid bypassing authentication or technical controls;&lt;/li&gt;
&lt;li&gt;use only the fields needed for the project;&lt;/li&gt;
&lt;li&gt;apply reasonable request rates and bounded retries;&lt;/li&gt;
&lt;li&gt;review personal or sensitive data before storage; and&lt;/li&gt;
&lt;li&gt;involve legal or security reviewers for regulated or commercial use.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For data quality, compare a sample with the live page, distinguish ads from organic listings, test destination links, record empty fields, and keep the exact input conditions. A dataset that cannot explain how it was produced is difficult to reproduce.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Does Bing still offer a Search API?
&lt;/h3&gt;

&lt;p&gt;No general Bing Search API is available. Microsoft announced that the Bing Search APIs would be retired on August 11, 2025 and directed customers toward Grounding with Bing Search for Azure AI agent scenarios. Grounding is not a drop-in endpoint for exporting visible SERP rows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I export Bing search results to Excel?
&lt;/h3&gt;

&lt;p&gt;Yes. The Octoparse template supports spreadsheet-oriented exports such as CSV and Excel for supported workflows. Inspect the result first because ads, localization, and page layout affect which fields are populated.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the difference between the template, API, and MCP?
&lt;/h3&gt;

&lt;p&gt;The template defines a ready-made extraction workflow. The API lets code control supported Octoparse tasks and retrieve their data. MCP lets compatible AI clients interact with supported Octoparse workflows. API and MCP automate Octoparse; they do not call a hidden Bing API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why did a test return fewer rows than expected?
&lt;/h3&gt;

&lt;p&gt;A search page is not a fixed database response. Market, query, ads, layout, deduplication, and extraction rules can change the row count. The documented test returned 9 rows for one page, but another query can return a different result.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which method is the most stable?
&lt;/h3&gt;

&lt;p&gt;For a defined custom dataset, Desktop usually provides the most control because you can inspect and adjust the workflow. For the fastest standard export, a template is simpler. Stability still depends on testing, target changes, and ongoing validation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is it legal to scrape Bing search results?
&lt;/h3&gt;

&lt;p&gt;That depends on the data, jurisdiction, access method, and intended use. Public visibility alone is not a complete legal analysis. Follow current terms, avoid circumvention, limit collection, and seek qualified advice for sensitive or commercial projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical starting point
&lt;/h2&gt;

&lt;p&gt;Start with one representative keyword and one page. Run the template, inspect the fields, and save the CSV only after the schema looks right. If the same question returns next week, automate the verified workflow with API or MCP. If the standard fields are not enough, move into Desktop and build the extraction your application actually needs.&lt;/p&gt;

&lt;p&gt;The original source is &lt;a href="https://www.octoparse.com/blog/scrape-bing-search-results" rel="noopener noreferrer"&gt;How to Scrape Bing Search Results (4 Methods, 2026)&lt;/a&gt;. This DEV.to version keeps the source's documented test boundaries while adding a developer-oriented decision table, Python example, provenance model, and validation checklist.&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>python</category>
      <category>tutorial</category>
      <category>api</category>
    </item>
    <item>
      <title>How to Scrape Zillow Data: A Practical Workflow for Property Listings</title>
      <dc:creator>Stella Lin</dc:creator>
      <pubDate>Sun, 27 Sep 2026 08:03:59 +0000</pubDate>
      <link>https://dev.to/stella_lin/how-to-scrape-zillow-data-a-practical-workflow-for-property-listings-45c2</link>
      <guid>https://dev.to/stella_lin/how-to-scrape-zillow-data-a-practical-workflow-for-property-listings-45c2</guid>
      <description>&lt;p&gt;If you need Zillow listing data, start with the smallest workflow that can reliably return the fields you need. Use a prepared template for a fast, repeatable export, move to a visual Desktop workflow when the template schema is too narrow, and use Python when your engineering team needs full control of parsing and downstream processing.&lt;/p&gt;

&lt;p&gt;One important distinction: an Octoparse scraper workflow is not Zillow's official API. It collects publicly displayed listing data through a supported workflow. Treat the source terms, access rules, field coverage, and your intended use as separate questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;th&gt;Setup&lt;/th&gt;
&lt;th&gt;Main trade-off&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Zillow template by URL&lt;/td&gt;
&lt;td&gt;Filtered listing-page URLs&lt;/td&gt;
&lt;td&gt;Lowest&lt;/td&gt;
&lt;td&gt;Fields depend on the template and source page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zillow template by keyword&lt;/td&gt;
&lt;td&gt;Locations plus buy-or-rent selection&lt;/td&gt;
&lt;td&gt;Lowest&lt;/td&gt;
&lt;td&gt;You still need to validate the returned schema&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Octoparse Desktop&lt;/td&gt;
&lt;td&gt;Dynamic pages, custom fields, pagination, and visual debugging&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;You build and maintain the workflow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;Custom processing and engineering-owned pipelines&lt;/td&gt;
&lt;td&gt;Highest&lt;/td&gt;
&lt;td&gt;Your team owns parsing, recovery, and access controls&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For most first projects, test one representative input before running a large list. A successful task request is not the same as a useful export.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Zillow data can you collect?
&lt;/h2&gt;

&lt;p&gt;The current Zillow listing templates describe a property-oriented schema. Depending on the page and what Zillow exposes, a returned row may include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Identity:&lt;/strong&gt; address, ZPID, and house URL&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pricing:&lt;/strong&gt; asking price&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Property details:&lt;/strong&gt; bedrooms, bathrooms, and square footage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Status and media:&lt;/strong&gt; listing status and image URL&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Listing context:&lt;/strong&gt; listing agent or other visible source context&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Field availability is conditional. A missing value does not mean zero, and a field documented by a template is not guaranteed to appear on every Zillow page. Define the fields your analysis actually needs before you choose a tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: choose the right Zillow input
&lt;/h2&gt;

&lt;p&gt;Octoparse has two useful starting points:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use the &lt;a href="https://www.octoparse.com/template/zillow-scraper" rel="noopener noreferrer"&gt;Zillow Listing Scraper by URL&lt;/a&gt; when you already have a filtered listing URL.&lt;/li&gt;
&lt;li&gt;Use the &lt;a href="https://www.octoparse.com/template/zillow-scraper-by-keywords" rel="noopener noreferrer"&gt;Zillow Listing Scraper by Keyword&lt;/a&gt; when your input is a location plus a buy-or-rent choice.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do not mix these two input models casually. If you begin with a search URL, preserve that URL in the exported data so you can reproduce or audit the run later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: run a small representative test
&lt;/h2&gt;

&lt;p&gt;Before scaling, test one URL or one location that looks like your real workload.&lt;/p&gt;

&lt;p&gt;Check four things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The template accepts the input.&lt;/li&gt;
&lt;li&gt;The result contains populated rows rather than an empty export.&lt;/li&gt;
&lt;li&gt;The fields match your analysis question.&lt;/li&gt;
&lt;li&gt;The values agree with several source pages.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This test is more valuable than a large run that quietly returns incomplete rows. It also tells you whether a prepared template is enough or whether you need a custom workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: validate the output before using it
&lt;/h2&gt;

&lt;p&gt;Use this checklist for every export:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep &lt;strong&gt;ZPID, address, and house URL&lt;/strong&gt; for deduplication.&lt;/li&gt;
&lt;li&gt;Record &lt;strong&gt;collection time&lt;/strong&gt; and listing status.&lt;/li&gt;
&lt;li&gt;Treat blank price or bedroom values as missing, not as zero.&lt;/li&gt;
&lt;li&gt;Compare several exported rows with their Zillow source pages.&lt;/li&gt;
&lt;li&gt;Check whether pagination, sponsored results, or location filters changed the sample.&lt;/li&gt;
&lt;li&gt;Record the exact input URL or keyword so another person can reproduce the run.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is a small Python normalization layer. It does not scrape Zillow. It makes a returned export safer to pass into the next step of your pipeline.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timezone&lt;/span&gt;

&lt;span class="n"&gt;REQUIRED&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;address&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;zpid&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;house_url&lt;/span&gt;&lt;span class="sh"&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;normalize_listing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;normalized&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;address&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;row&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;address&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;zpid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;row&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;zpid&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;house_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;row&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;house_url&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;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;row&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&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;bedrooms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;row&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;bedrooms&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;bathrooms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;row&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;bathrooms&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;square_feet&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;row&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;square_feet&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;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;row&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;status&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;collected_at&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timezone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utc&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;isoformat&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;normalized&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;has_identity&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;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;normalized&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&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="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="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;field&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;REQUIRED&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;normalized&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;has_identity&lt;/code&gt; flag is intentionally conservative. A row without a stable identity should not silently enter a price history or comparable-property dataset.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: move to Octoparse Desktop when the template is not enough
&lt;/h2&gt;

&lt;p&gt;Use &lt;a href="https://www.octoparse.com/download" rel="noopener noreferrer"&gt;Octoparse Desktop&lt;/a&gt; when you need fields, pagination, interactions, or troubleshooting that a prepared template does not expose.&lt;/p&gt;

&lt;p&gt;A practical Desktop workflow looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Paste a Zillow page URL into Octoparse.&lt;/li&gt;
&lt;li&gt;Let auto-detection create an initial field set.&lt;/li&gt;
&lt;li&gt;Review the preview table and rename fields to your own schema.&lt;/li&gt;
&lt;li&gt;Add the missing fields or pagination logic.&lt;/li&gt;
&lt;li&gt;Test the workflow on a representative page.&lt;/li&gt;
&lt;li&gt;Run and export only after the preview contains usable rows.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The important engineering habit is to treat the preview as a schema test, not as proof that every future page will behave the same way. Zillow layouts and listing states can change.&lt;/p&gt;

&lt;h2&gt;
  
  
  When should you use Python instead?
&lt;/h2&gt;

&lt;p&gt;Python is a better fit when scraping is one component of a maintained application. Choose it when your team needs custom parsing, a database model, retry logic, change detection, or integration with an existing data pipeline.&lt;/p&gt;

&lt;p&gt;The trade-off is maintenance. Your team owns request behavior, parsing logic, access controls, recovery, and tests. If you only need a repeatable export of a supported Zillow page type, a prepared template usually has less operational overhead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is a Zillow scraper API the same as the Zillow API?
&lt;/h2&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;p&gt;The Zillow API refers to Zillow's own data products and developer access under Zillow's terms. A scraper API generally describes an automated workflow that collects publicly displayed property information and returns structured output.&lt;/p&gt;

&lt;p&gt;Octoparse API and MCP can automate supported Octoparse templates or cloud tasks. They are not official Zillow endpoints. For a supported cloud workflow, the documented sequence is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;searchTemplates -&amp;gt; executeTask -&amp;gt; exportData
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The order matters. First confirm that the selected template is discoverable and that its current input schema matches your request. Then run a small task, monitor it, and verify that the export contains populated rows. An &lt;code&gt;accepted&lt;/code&gt; response means the task was created, not that a usable file is ready.&lt;/p&gt;

&lt;p&gt;See the &lt;a href="https://helpcenter.octoparse.com/en/articles/15855832-run-a-scraping-workflow-with-the-octoparse-agenttools-api" rel="noopener noreferrer"&gt;Octoparse AgentTools API workflow&lt;/a&gt; for the current execution boundaries.&lt;/p&gt;

&lt;h2&gt;
  
  
  How real estate teams use listing data
&lt;/h2&gt;

&lt;p&gt;Listing-level rows are useful when you connect them to a clear decision:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Inventory monitoring:&lt;/strong&gt; compare active listings by geography and status.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comparable-property research:&lt;/strong&gt; group properties by location, size, and features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Price analysis:&lt;/strong&gt; compare asking prices across a defined sample and collection date.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Market context:&lt;/strong&gt; combine listing observations with sources such as the &lt;a href="https://www.fhfa.gov/data/hpi" rel="noopener noreferrer"&gt;FHFA House Price Index&lt;/a&gt;, &lt;a href="https://www.census.gov/programs-surveys/acs" rel="noopener noreferrer"&gt;Census ACS housing profiles&lt;/a&gt;, or &lt;a href="https://www.zillow.com/research/data/" rel="noopener noreferrer"&gt;Zillow's public research datasets&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those market-level sources do not replace listing validation. They help answer a different question: whether a property-level change looks local or reflects a broader market movement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turning one export into a price tracker
&lt;/h2&gt;

&lt;p&gt;A scraper gives you a snapshot. A tracker needs repeated snapshots, a stable key, and comparison logic.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Preserve the source URL, house URL, address, price, market, and currency.&lt;/li&gt;
&lt;li&gt;Add a &lt;code&gt;collected_at&lt;/code&gt; timestamp to every export.&lt;/li&gt;
&lt;li&gt;Prefer ZPID or another stable identifier over title matching.&lt;/li&gt;
&lt;li&gt;Append each snapshot instead of overwriting the previous one.&lt;/li&gt;
&lt;li&gt;Calculate price changes against the previous observation.&lt;/li&gt;
&lt;li&gt;Treat a missing listing as unavailable, not as a zero-price event.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The collection schedule is only half the job. The other half is deciding what counts as the same property and how to handle relisted, removed, or changed records.&lt;/p&gt;

&lt;h2&gt;
  
  
  Responsible Zillow scraping
&lt;/h2&gt;

&lt;p&gt;Technical access does not automatically establish permission for a particular use. Review &lt;a href="https://www.zillowgroup.com/terms-of-use/" rel="noopener noreferrer"&gt;Zillow Group's current terms&lt;/a&gt; and any applicable data or API documentation before scaling a workflow.&lt;/p&gt;

&lt;p&gt;At minimum:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;collect only the fields necessary for the stated purpose;&lt;/li&gt;
&lt;li&gt;avoid personal or restricted information;&lt;/li&gt;
&lt;li&gt;respect access controls and reasonable request rates;&lt;/li&gt;
&lt;li&gt;keep a source URL and collection timestamp;&lt;/li&gt;
&lt;li&gt;test a small sample before a larger run; and&lt;/li&gt;
&lt;li&gt;get qualified legal advice when the project involves regulated, licensed, personal, or commercially sensitive data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQs about Zillow scraper workflows
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is the easiest way to scrape Zillow data?
&lt;/h3&gt;

&lt;p&gt;Start with the prepared template that matches your input. Use the URL version for filtered listing URLs and the keyword version for locations plus a buy-or-rent choice. Test one representative input and verify populated fields before scaling.&lt;/p&gt;

&lt;h3&gt;
  
  
  What fields can a Zillow scraper return?
&lt;/h3&gt;

&lt;p&gt;Depending on the page and workflow, a row may include address, ZPID, house URL, price, bedrooms, bathrooms, square footage, listing status, image URL, and visible listing context. Validate the current schema because some fields can be empty or absent.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use Zillow data for a price tracker?
&lt;/h3&gt;

&lt;p&gt;Yes, if you collect on a schedule, keep a stable property identifier, store each snapshot with a timestamp, and define how to handle removed or relisted properties. A one-time export is only a snapshot.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does Octoparse provide the official Zillow API?
&lt;/h3&gt;

&lt;p&gt;No. Octoparse automates supported web-data workflows. Zillow's own APIs and data products have separate access conditions and terms. Treat the two integration paths as different products.&lt;/p&gt;

&lt;h3&gt;
  
  
  When should I build a custom scraper?
&lt;/h3&gt;

&lt;p&gt;Build a custom Desktop or Python workflow when the prepared template cannot return the fields, pagination, or interactions your project needs. Keep the maintenance cost visible before you commit to custom parsing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final checklist
&lt;/h2&gt;

&lt;p&gt;Before using a Zillow export in a report or application, confirm:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the input type matches the workflow;&lt;/li&gt;
&lt;li&gt;the export contains populated rows;&lt;/li&gt;
&lt;li&gt;identity fields are present;&lt;/li&gt;
&lt;li&gt;blanks are not being interpreted as zeros;&lt;/li&gt;
&lt;li&gt;a sample matches the source pages;&lt;/li&gt;
&lt;li&gt;the collection date and source URL are stored; and&lt;/li&gt;
&lt;li&gt;your use complies with current terms and access requirements.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The original Octoparse article is &lt;a href="https://www.octoparse.com/blog/how-to-scrape-data-from-zillow" rel="noopener noreferrer"&gt;How to Create a Zillow Scraper for Property Data&lt;/a&gt;. This DEV.to version adds a developer-oriented decision table, a validation layer, an automation boundary, and a reproducible data model while preserving the original source attribution.&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>python</category>
      <category>tutorial</category>
      <category>api</category>
    </item>
    <item>
      <title>7 eBay Scraper Tools Tested in 2026: Results &amp; Trade-offs</title>
      <dc:creator>Stella Lin</dc:creator>
      <pubDate>Sat, 26 Sep 2026 11:23:06 +0000</pubDate>
      <link>https://dev.to/stella_lin/7-ebay-scraper-tools-tested-in-2026-results-trade-offs-2jj7</link>
      <guid>https://dev.to/stella_lin/7-ebay-scraper-tools-tested-in-2026-results-trade-offs-2jj7</guid>
      <description>&lt;p&gt;If you need eBay listing data, the best tool depends on your workflow. A ready-made template is usually the fastest route to structured rows. An official API is a better fit for an approved buying application. A managed scraper API makes more sense when your application needs recurring delivery.&lt;/p&gt;

&lt;p&gt;This is a tested comparison, not a universal ranking. The Octoparse workflow was run on August 31, 2026. Other options were checked against official documentation or maintained product pages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Best fit&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;th&gt;Trade-off&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Octoparse&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Repeatable eBay collection&lt;/td&gt;
&lt;td&gt;Structured rows and exports&lt;/td&gt;
&lt;td&gt;Account and cloud limits can apply&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;eBay Browse API&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Approved buying apps&lt;/td&gt;
&lt;td&gt;Official item resources&lt;/td&gt;
&lt;td&gt;Access requirements apply&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bright Data&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Managed collection at scale&lt;/td&gt;
&lt;td&gt;JSON, NDJSON, CSV&lt;/td&gt;
&lt;td&gt;More configuration and cost evaluation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Oxylabs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Managed fetching plus your parser&lt;/td&gt;
&lt;td&gt;eBay page HTML&lt;/td&gt;
&lt;td&gt;Your team owns the schema&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Crawlbase&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Parsed JSON for listings and stores&lt;/td&gt;
&lt;td&gt;Typed JSON&lt;/td&gt;
&lt;td&gt;Fields vary by target page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Apify&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Actor-based automation&lt;/td&gt;
&lt;td&gt;Dataset records&lt;/td&gt;
&lt;td&gt;Quality depends on the Actor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ParseHub&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Visual cross-site navigation&lt;/td&gt;
&lt;td&gt;Project exports&lt;/td&gt;
&lt;td&gt;More setup and maintenance&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;My default rule: choose &lt;strong&gt;Octoparse&lt;/strong&gt; for a maintained workflow and structured rows; the &lt;strong&gt;eBay Browse API&lt;/strong&gt; for an approved buying experience; a managed scraper API for recurring programmatic delivery; and &lt;strong&gt;ParseHub or custom code&lt;/strong&gt; when you need to own navigation and parsing.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the comparison was run
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The Octoparse team ran an eBay workflow with a public wireless-earbuds search URL.&lt;/li&gt;
&lt;li&gt;The test record captured the input screen, run state, populated rows, fields, and stop time.&lt;/li&gt;
&lt;li&gt;Other tools were checked against current official product pages, API references, or maintained marketplace listings.&lt;/li&gt;
&lt;li&gt;Every option was compared across coverage, input, output, operating model, and verification level.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A row marked &lt;strong&gt;tested&lt;/strong&gt; is not equivalent to a row marked &lt;strong&gt;documentation checked&lt;/strong&gt;. Prices, quotas, access rules, and marketplace layouts change.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Octoparse: from an eBay URL to structured rows
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.octoparse.com/template/ebay-scraper" rel="noopener noreferrer"&gt;Octoparse's eBay Scraper template&lt;/a&gt; accepts listing-page URLs and can return product names, prices, source pages, product URLs, seller ratings, subtitles, and image URLs when those values exist.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg8uzh6w6ioebi8ehm6qa.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg8uzh6w6ioebi8ehm6qa.webp" alt="Octoparse eBay scraper template gallery" width="600" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the dated August 31, 2026 test, the first evidence capture showed &lt;strong&gt;1,799 populated rows&lt;/strong&gt;. The run reached &lt;strong&gt;1,859 rows&lt;/strong&gt; when it was stopped after &lt;strong&gt;39 minutes and 10 seconds&lt;/strong&gt;. A separate AgentTools validation returned &lt;strong&gt;59 populated rows&lt;/strong&gt; before a controlled stop. These are dated observations, not guarantees for every future URL.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzuvqq3ggv9d48e40a7s3.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzuvqq3ggv9d48e40a7s3.webp" alt="Octoparse eBay template input" width="600" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Octoparse is a good fit when you want a visual workflow, a maintained template, repeatable collection, and a chance to inspect rows before export.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. eBay Browse API
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://developer.ebay.com/api-docs/buy/api-browse.html" rel="noopener noreferrer"&gt;eBay Browse API&lt;/a&gt; returns resources defined by eBay for supported Buy API use cases. It is not a general-purpose page scraper. Read the &lt;a href="https://developer.ebay.com/api-docs/buy/buy-requirements.html" rel="noopener noreferrer"&gt;Buy API requirements&lt;/a&gt; before designing your schema.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Bright Data
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://brightdata.com/products/web-scraper/ecommerce" rel="noopener noreferrer"&gt;Bright Data's eCommerce Scraper&lt;/a&gt; fits teams that need bulk jobs, delivery endpoints, and recurring infrastructure. Evaluate configuration effort and cost against expected volume.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Oxylabs
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://oxylabs.io/products/scraper-api/web/product-scraper" rel="noopener noreferrer"&gt;Oxylabs Web Scraper API&lt;/a&gt; returns eBay product-page HTML. Your engineering team owns the parser that turns HTML into JSON, which is useful when you need schema control.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Crawlbase
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://crawlbase.com/ebay-scraper" rel="noopener noreferrer"&gt;Crawlbase's eBay Scraper API&lt;/a&gt; separates product listings, search results, and seller shops as distinct targets. Check current fields for each target before writing downstream code.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Apify
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://apify.com/harvestlab/ebay-scraper/api/openapi" rel="noopener noreferrer"&gt;Apify's reviewed eBay Product Scraper Actor&lt;/a&gt; exposes UI, API, OpenAPI, and MCP surfaces. The maintainer, schema, usage model, and reliability belong to that specific Actor, so evaluate the listing you intend to run.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. ParseHub
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://help.parsehub.com/hc/en-us/articles/115004843408-Scrape-two-eCommerce-websites-in-one-project-Amazon-and-eBay-examples" rel="noopener noreferrer"&gt;ParseHub's Amazon-and-eBay example&lt;/a&gt; shows a cross-site pattern: collect product names from one site, use them as inputs on eBay, then extract matching names and prices. Expect more setup than a maintained eBay template.&lt;/p&gt;

&lt;h2&gt;
  
  
  Templates, APIs, or custom code?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Requirement&lt;/th&gt;
&lt;th&gt;Best route&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Export listing rows without coding&lt;/td&gt;
&lt;td&gt;Octoparse template&lt;/td&gt;
&lt;td&gt;Preconfigured input and visible results&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build an approved buying app&lt;/td&gt;
&lt;td&gt;eBay Browse API&lt;/td&gt;
&lt;td&gt;Official resources and requirements&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Feed data into a production pipeline&lt;/td&gt;
&lt;td&gt;Managed scraper API&lt;/td&gt;
&lt;td&gt;Programmatic execution and delivery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Own parsing and schema&lt;/td&gt;
&lt;td&gt;Oxylabs or custom code&lt;/td&gt;
&lt;td&gt;Developer-controlled parsing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Use hosted automation&lt;/td&gt;
&lt;td&gt;Apify Actor&lt;/td&gt;
&lt;td&gt;Existing API and dataset surfaces&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compare eBay with another marketplace&lt;/td&gt;
&lt;td&gt;ParseHub&lt;/td&gt;
&lt;td&gt;Visual multi-site navigation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Turning a one-time scrape into a price tracker
&lt;/h2&gt;

&lt;p&gt;A scraper gives you a snapshot. A tracker needs repeated snapshots, a stable product key, and comparison logic:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Preserve the source URL, product URL, name, price, marketplace, and currency.&lt;/li&gt;
&lt;li&gt;Add a collected_at timestamp to every export.&lt;/li&gt;
&lt;li&gt;Normalize the eBay item ID from ProductUrl when practical; do not match by title alone.&lt;/li&gt;
&lt;li&gt;Append each snapshot instead of overwriting the previous one.&lt;/li&gt;
&lt;li&gt;Calculate price_change and price_change_percent against the previous record.&lt;/li&gt;
&lt;li&gt;Treat missing listings as unavailable, never as a zero price.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;See &lt;a href="https://www.octoparse.com/blog/build-ebay-price-tracker-with-web-scraping" rel="noopener noreferrer"&gt;Octoparse's price-monitoring guide&lt;/a&gt; for implementation details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Responsible eBay scraping
&lt;/h2&gt;

&lt;p&gt;Tool availability does not decide whether a collection plan is permitted. Review eBay's &lt;a href="https://www.ebay.com/help/policies/member-behaviour-policies/user-agreement?id=4259" rel="noopener noreferrer"&gt;User Agreement&lt;/a&gt;, respect access controls and reasonable request rates, collect only the fields you need, avoid personal or restricted data, and test a small sample before scaling.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is the best eBay scraper for beginners?
&lt;/h3&gt;

&lt;p&gt;A ready-made Octoparse eBay template is the simplest starting point when the input and output schema match your use case. In the dated test above, one search URL produced 1,799 populated rows at the evidence capture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is eBay scraping the same as using the eBay API?
&lt;/h3&gt;

&lt;p&gt;No. A scraper reads selected web pages, while the Browse API returns resources defined by eBay for supported use cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use an eBay scraper as a price tracker?
&lt;/h3&gt;

&lt;p&gt;Yes, if the workflow runs on a schedule and each price is stored with a timestamp and stable product identifier. A one-time scrape is only a snapshot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final recommendation
&lt;/h2&gt;

&lt;p&gt;Start with the operating model: &lt;strong&gt;template first&lt;/strong&gt; for Octoparse; &lt;strong&gt;official integration&lt;/strong&gt; for the eBay Browse API; &lt;strong&gt;managed pipeline&lt;/strong&gt; for Bright Data or Crawlbase; &lt;strong&gt;parser ownership&lt;/strong&gt; for Oxylabs or custom code; &lt;strong&gt;hosted automation&lt;/strong&gt; for Apify; and &lt;strong&gt;visual multi-site work&lt;/strong&gt; for ParseHub.&lt;/p&gt;

&lt;p&gt;Reviewed August 31, 2026. Recheck unstable pricing, limits, and access requirements before production use.&lt;/p&gt;

&lt;p&gt;Original article: &lt;a href="https://www.octoparse.com/blog/best-ebay-scraper-tools" rel="noopener noreferrer"&gt;eBay Scraper API &amp;amp; Tools: 7 Tested, 1,799 Records&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/VQWkxUddis4" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>ebay</category>
      <category>api</category>
      <category>tooling</category>
    </item>
    <item>
      <title>YouTube Crawler: Data Extraction vs. Video Downloads</title>
      <dc:creator>Stella Lin</dc:creator>
      <pubDate>Thu, 24 Sep 2026 06:35:53 +0000</pubDate>
      <link>https://dev.to/stella_lin/what-is-a-youtube-crawler-data-extraction-vs-video-downloads-51fh</link>
      <guid>https://dev.to/stella_lin/what-is-a-youtube-crawler-data-extraction-vs-video-downloads-51fh</guid>
      <description>&lt;p&gt;When someone searches for a “YouTube crawler,” they may want three different outputs: a structured dataset, an application feed, or a downloadable media file. Those jobs should not be treated as interchangeable.&lt;/p&gt;

&lt;p&gt;This guide explains what a YouTube crawler can collect, how it differs from a downloader and the YouTube Data API, and how to choose a workflow that is repeatable, auditable, and appropriate for public data.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Crawler or scraper:&lt;/strong&gt; structured channel and video metadata for research, reporting, and monitoring.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;YouTube Data API:&lt;/strong&gt; documented JSON resources for applications you maintain in code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Downloader:&lt;/strong&gt; an authorized media file, only when you own the content or have permission to save it.&lt;/li&gt;
&lt;li&gt;Validate a sample, keep unavailable values blank, and record the collection date.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Disclosure:&lt;/strong&gt; I work at Octoparse, the no-code web data platform referenced in the workflow section.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What is a YouTube crawler?
&lt;/h2&gt;

&lt;p&gt;A YouTube crawler is a workflow that discovers or loads public channel and video pages and extracts selected fields into structured rows. A crawler may discover pages, while a scraper extracts fields; in practice, many products do both.&lt;/p&gt;

&lt;p&gt;The output is a dataset, not a folder of videos. A video-level row may include:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Channel&lt;/th&gt;
&lt;th&gt;Title&lt;/th&gt;
&lt;th&gt;URL&lt;/th&gt;
&lt;th&gt;Published date&lt;/th&gt;
&lt;th&gt;Duration&lt;/th&gt;
&lt;th&gt;Visible views&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Public channel&lt;/td&gt;
&lt;td&gt;Video title&lt;/td&gt;
&lt;td&gt;Watch URL&lt;/td&gt;
&lt;td&gt;Public date&lt;/td&gt;
&lt;td&gt;ISO 8601 duration&lt;/td&gt;
&lt;td&gt;Displayed count&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That dataset can support content research, publishing-cadence analysis, competitor monitoring, topic classification, or separate comment and transcript workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  YouTube crawler vs. downloader vs. Data API
&lt;/h2&gt;

&lt;p&gt;Choose the output before choosing the tool.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Primary output&lt;/th&gt;
&lt;th&gt;Best fit&lt;/th&gt;
&lt;th&gt;Main limitation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Crawler or scraper&lt;/td&gt;
&lt;td&gt;CSV, Excel, or JSON metadata&lt;/td&gt;
&lt;td&gt;Public-data research and recurring exports&lt;/td&gt;
&lt;td&gt;Limited to fields the page and workflow expose&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;YouTube Data API&lt;/td&gt;
&lt;td&gt;Documented JSON resources&lt;/td&gt;
&lt;td&gt;Maintained applications and data products&lt;/td&gt;
&lt;td&gt;Credentials, quota, pagination, and code maintenance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authorized downloader&lt;/td&gt;
&lt;td&gt;Video or audio file&lt;/td&gt;
&lt;td&gt;Content you own or are allowed to save&lt;/td&gt;
&lt;td&gt;Does not create a structured metadata dataset&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manual collection&lt;/td&gt;
&lt;td&gt;Small spreadsheet sample&lt;/td&gt;
&lt;td&gt;One-time validation&lt;/td&gt;
&lt;td&gt;Slow and difficult to repeat consistently&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A channel crawler returns titles, URLs, dates, and other fields. It does not become a video downloader just because both tools mention YouTube. If the deliverable is a media file, use an authorized workflow and follow the rights that apply to that content.&lt;/p&gt;

&lt;h2&gt;
  
  
  What public YouTube data can you collect?
&lt;/h2&gt;

&lt;p&gt;The answer depends on the page, region, collection date, and workflow. Common public fields include:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Channel-level fields&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Channel name, handle, URL, and description&lt;/li&gt;
&lt;li&gt;Displayed subscriber count&lt;/li&gt;
&lt;li&gt;Displayed public video count&lt;/li&gt;
&lt;li&gt;Uploads playlist reference when available through the API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Video-level fields&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Title, watch URL, and thumbnail URL&lt;/li&gt;
&lt;li&gt;Published date&lt;/li&gt;
&lt;li&gt;Duration&lt;/li&gt;
&lt;li&gt;Displayed view count and other exposed statistics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Comments, captions, and transcripts are usually separate jobs keyed by video URL. Keeping them in separate tables makes row counts easier to interpret.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three facts to verify before building
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. API quota is method-specific
&lt;/h3&gt;

&lt;p&gt;The YouTube Data API has a default daily allocation of 10,000 units for most methods, while some methods have separate limits. Every request costs quota, and paginated requests consume quota for each page. Check the current documentation and your Google Cloud project before scheduling a pipeline.&lt;/p&gt;

&lt;p&gt;Official source:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/youtube/v3/determine_quota_cost" rel="noopener noreferrer"&gt;https://developers.google.com/youtube/v3/determine_quota_cost&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Public counts are not private analytics
&lt;/h3&gt;

&lt;p&gt;The YouTube API documentation defines the semantics of public channel statistics. For example, subscriberCount is rounded down to three significant figures, and videoCount refers to public videos. Store the collection date and do not present public counts as private YouTube Analytics.&lt;/p&gt;

&lt;p&gt;Official source:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/youtube/v3/docs/channels#statistics" rel="noopener noreferrer"&gt;https://developers.google.com/youtube/v3/docs/channels#statistics&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. A test export is evidence for one run, not a guarantee
&lt;/h3&gt;

&lt;p&gt;A recorded Octoparse test on August 14, 2026 used one public channel and reached exported status with 50 rows. The sample showed five rows and ten channel or video fields. Treat this as dated, single-input evidence, not a universal speed, completeness, or row-limit guarantee.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a crawler cannot provide
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Private metrics:&lt;/strong&gt; watch time, retention, revenue, traffic sources, and detailed demographics require YouTube Studio or an owner-authorized workflow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every upload ever published:&lt;/strong&gt; private, unlisted, deleted, age-restricted, and region-restricted videos may be unavailable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A permanent snapshot:&lt;/strong&gt; channels change after collection, so every export should include a collection date.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep missing values missing. Replacing an unavailable view count with zero creates a false fact that can silently corrupt later analysis.&lt;/p&gt;

&lt;h2&gt;
  
  
  How a YouTube channel crawl works
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Define the input:&lt;/strong&gt; public channel URL, handle, video URL, keyword, or results page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load the relevant pages:&lt;/strong&gt; discover the channel or video records needed for the task.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Map fields:&lt;/strong&gt; assign page elements to columns such as title, URL, date, duration, and views.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate and export:&lt;/strong&gt; compare a few rows with the public page, inspect blanks, record the date, and export CSV, Excel, or JSON.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The fourth step is essential. A five-row spot check can catch a broken URL format, a shifted column, or a changed page layout before the data reaches a dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the right workflow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Option 1: Manual collection for a small validation sample
&lt;/h3&gt;

&lt;p&gt;Manual collection is useful when you need to verify a few rows or confirm the right channel. It becomes unreliable when repeated every week: scrolling is slow, fields can be misaligned, and the process is difficult to audit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 2: YouTube Data API for maintained applications
&lt;/h3&gt;

&lt;p&gt;The usual API chain is: resolve the channel, find its uploads playlist, page through playlist items, fetch video details in batches, then save a dated dataset. Your team owns the credentials, quota planning, retries, pagination, and policy maintenance.&lt;/p&gt;

&lt;p&gt;The example below checks for an empty channel response and keeps missing statistics as None.&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;datetime&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;dt&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;import&lt;/span&gt; &lt;span class="n"&gt;requests&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;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;YT_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;BASE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://www.googleapis.com/youtube/v3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;HANDLE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@YourChannelHandle&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;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;params&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;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="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;BASE&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;endpoint&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="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="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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;API_KEY&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&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="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;channel_page&lt;/span&gt; &lt;span class="o"&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;channels&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;contentDetails&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;forHandle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;HANDLE&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;channel_page&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;items&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;RuntimeError&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 public channel matched the supplied handle&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;uploads&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;channel_page&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;items&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;contentDetails&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;relatedPlaylists&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;uploads&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;video_ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="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;playlistItems&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;contentDetails&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;playlistId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;uploads&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxResults&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pageToken&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;video_ids&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extend&lt;/span&gt;&lt;span class="p"&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;contentDetails&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;videoId&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;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;page&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;items&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;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&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;nextPageToken&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;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;

&lt;span class="n"&gt;collected_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;today&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;isoformat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;rows&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;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="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;video_ids&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;batch&lt;/span&gt; &lt;span class="o"&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;videos&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;snippet,contentDetails,statistics&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;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;,&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;video_ids&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="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;video&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;batch&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;items&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;stats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;video&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;statistics&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;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;video_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;video&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;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;video&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;snippet&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;title&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;url&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;https://www.youtube.com/watch?v=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;video&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="si"&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;published_at&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;video&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;snippet&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;publishedAt&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;duration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;video&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;contentDetails&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;duration&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;view_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;stats&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;viewCount&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;collected_at&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;collected_at&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;rows&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;channel_videos.csv&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;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;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="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;utf-8&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;output&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="nc"&gt;DictWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fieldnames&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;rows&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="nf"&gt;keys&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;writeheader&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;writerows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rows&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Saved &lt;/span&gt;&lt;span class="si"&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;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; videos&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;h3&gt;
  
  
  Option 3: A no-code workflow for repeatable spreadsheet exports
&lt;/h3&gt;

&lt;p&gt;If the deliverable is a spreadsheet for an analyst, maintaining API code may be unnecessary. Octoparse’s YouTube Channel Scraper is designed for public channel inputs and structured channel or video fields without requiring you to build an API client.&lt;/p&gt;

&lt;p&gt;Template:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.octoparse.com/template/youtube-channel-scraper" rel="noopener noreferrer"&gt;https://www.octoparse.com/template/youtube-channel-scraper&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Start with one public channel, confirm the input points to the intended page, inspect several returned rows, and only then expand the input list or schedule recurring runs. The dated test above demonstrates one completed export under one set of conditions; it is not a performance or completeness promise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turning the dataset into decisions
&lt;/h2&gt;

&lt;p&gt;A table becomes useful when each field answers a question:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Publishing cadence:&lt;/strong&gt; group uploads by week or month and compare format, duration, and frequency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content themes:&lt;/strong&gt; label titles by topic and account for video age when comparing visible views.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Competitor gaps:&lt;/strong&gt; standardize columns across channels and identify topics one channel covers while another ignores.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Change over time:&lt;/strong&gt; save dated snapshots to monitor new uploads and visible metrics. This does not replace private YouTube Analytics.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Troubleshooting checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No videos appear:&lt;/strong&gt; verify that the channel and Videos tab are public and that the input format is supported.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Some fields are empty:&lt;/strong&gt; the page may not expose the value. Keep it blank.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subscriber counts look different:&lt;/strong&gt; public counts are rounded and time-sensitive; save the displayed value and date.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Export count differs from the channel page:&lt;/strong&gt; private, unlisted, deleted, restricted, or newly published videos may be missing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comments or transcripts are missing:&lt;/strong&gt; use a separate video-level workflow and verify public availability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A saved workflow breaks:&lt;/strong&gt; revalidate the page structure after YouTube changes its layout.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Is it permitted to crawl YouTube?
&lt;/h2&gt;

&lt;p&gt;Public visibility does not automatically make automated collection lawful or permitted. The answer depends on YouTube’s current terms, your collection method, applicable law, privacy and copyright obligations, and how the data will be used.&lt;/p&gt;

&lt;p&gt;Review the current YouTube Terms of Service and YouTube API Services policies before operating a production workflow. Do not bypass access controls, collect private information, harvest personal data for outreach, or automate engagement. Collect only what you need for an authorized use and obtain legal advice for high-risk projects.&lt;/p&gt;

&lt;p&gt;Sources:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/static?template=terms" rel="noopener noreferrer"&gt;https://www.youtube.com/static?template=terms&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/youtube/terms/api-services-terms-of-service" rel="noopener noreferrer"&gt;https://developers.google.com/youtube/terms/api-services-terms-of-service&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is a YouTube crawler the same as a YouTube scraper?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In practice, mostly. The crawler discovers or loads pages, while the scraper extracts fields; many tools do both.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I collect public channel data without an API key?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A no-code workflow may collect supported public fields without an API client. That does not unlock private analytics or remove platform-policy obligations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can a crawler export every video from a channel?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Only the public videos it can access. Compare the export with the channel page and record the collection date.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can one crawler collect channel data, comments, and transcripts?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Usually not in one pass. Comments and transcripts are separate video-level workflows keyed by video URL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How often should I crawl a channel?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Match the schedule to the decision. Monthly snapshots may be enough for benchmarking; active campaigns may need more frequent checks. Do not collect more often than necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final takeaway
&lt;/h2&gt;

&lt;p&gt;The best YouTube crawler is the workflow that matches your output:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Manual collection&lt;/strong&gt; for a few validation rows&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Data API&lt;/strong&gt; for a maintained application&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A no-code scraper&lt;/strong&gt; for repeatable CSV, Excel, or JSON exports&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start with one public channel, verify the returned fields against the page, and record the collection date. A small dataset that you can explain is more valuable than a large export with unknown gaps.&lt;/p&gt;

&lt;p&gt;Originally published on the Octoparse blog:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.octoparse.com/blog/youtube-channel-crawler" rel="noopener noreferrer"&gt;https://www.octoparse.com/blog/youtube-channel-crawler&lt;/a&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>webscraping</category>
      <category>youtube</category>
      <category>datascience</category>
    </item>
  </channel>
</rss>
