<?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: CleanScrape</title>
    <description>The latest articles on DEV Community by CleanScrape (@cleanscrape).</description>
    <link>https://dev.to/cleanscrape</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%2F4126565%2F7f3a2bef-43ea-47db-a8a6-f8923b4ae916.png</url>
      <title>DEV Community: CleanScrape</title>
      <link>https://dev.to/cleanscrape</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cleanscrape"/>
    <language>en</language>
    <item>
      <title>Every cut in a 15-minute film: extracting 166 scene frames from a video link</title>
      <dc:creator>CleanScrape</dc:creator>
      <pubDate>Sun, 25 Oct 2026 14:21:19 +0000</pubDate>
      <link>https://dev.to/cleanscrape/every-cut-in-a-15-minute-film-extracting-166-scene-frames-from-a-video-link-4o66</link>
      <guid>https://dev.to/cleanscrape/every-cut-in-a-15-minute-film-extracting-166-scene-frames-from-a-video-link-4o66</guid>
      <description>&lt;p&gt;If you want to send a video to an AI vision model, build a thumbnail picker, or index a lecture by its slides, you rarely want every frame. You want one frame per shot. So I built a small tool on Apify that takes a video link and returns those frames as images, with their exact times.&lt;/p&gt;

&lt;p&gt;Here is what it does on Sintel, the 14:48 open movie from the Blender Foundation.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  The input
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"videos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"https://archive.org/download/Sintel/sintel-2048-stereo.mp4"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"scenes"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"contactSheet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It found &lt;strong&gt;166 shots&lt;/strong&gt; and saved one frame for each. The scan took 3 minutes 22 seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it finds the cuts
&lt;/h2&gt;

&lt;p&gt;In this precise mode it compares every frame with the one before. When the picture changes completely, that is a cut, and a frame is saved there. When the camera only pans or zooms, the picture changes a little at a time; that is not counted as a cut. (An earlier version did count fast camera moves, which is how I learned to require a sharp peak rather than a large change.)&lt;/p&gt;

&lt;h2&gt;
  
  
  When you don't need every cut
&lt;/h2&gt;

&lt;p&gt;Overview mode reads only the keyframes, the full pictures a video file stores every few seconds. On the same film it returned 24 frames in &lt;strong&gt;21 seconds&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Slides and screen recordings
&lt;/h2&gt;

&lt;p&gt;On a 60-second lecture recording with a moving mouse pointer, precise mode with high sensitivity found all &lt;strong&gt;6 slides&lt;/strong&gt; (at 0:00, 0:10, 0:20, 0:30, 0:40 and 0:50) and ignored the pointer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you get
&lt;/h2&gt;

&lt;p&gt;Every frame comes with its time, timecode, size and an image link (JPG, PNG or WebP), and every video gets a contact sheet: all its frames on one page. Other modes: a frame every N seconds, a set number of evenly spaced frames, or exact timestamps.&lt;/p&gt;

&lt;p&gt;It reads MP4, MOV, WebM, MKV, AVI, MPEG-TS, OGV and animated GIF from direct links, S3 and other storage links, Dropbox and Google Drive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://apify.com/cleanscrape/video-frame-extractor" rel="noopener noreferrer"&gt;https://apify.com/cleanscrape/video-frame-extractor&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;$2 per 1,000 frames, $0.005 per video, and in precise mode $0.01 per minute of 1080p video at 30 fps (smaller videos count less): the 166-frame Sintel run costs about $0.45, the overview run about $0.05. Use it on videos you own or may use.&lt;/p&gt;

&lt;p&gt;Sintel © Blender Foundation, durian.blender.org, CC BY 3.0.&lt;/p&gt;

&lt;p&gt;Niko, CleanScrape developer&lt;/p&gt;

</description>
      <category>video</category>
      <category>ai</category>
      <category>automation</category>
      <category>ffmpeg</category>
    </item>
    <item>
      <title>Which AI companies are hiring engineers, and what they pay: 691 jobs from career pages in 9 seconds</title>
      <dc:creator>CleanScrape</dc:creator>
      <pubDate>Sun, 25 Oct 2026 14:20:08 +0000</pubDate>
      <link>https://dev.to/cleanscrape/which-ai-companies-are-hiring-engineers-and-what-they-pay-691-jobs-from-career-pages-in-9-seconds-34e4</link>
      <guid>https://dev.to/cleanscrape/which-ai-companies-are-hiring-engineers-and-what-they-pay-691-jobs-from-career-pages-in-9-seconds-34e4</guid>
      <description>&lt;p&gt;Job boards repost, duplicate and keep expired listings. The cleanest source for who is hiring is the company's own careers page, and most companies run it on one of a handful of job board systems: Greenhouse, Lever, Ashby, Workable, Recruitee, Personio or Teamtailor. So I built a small tool on Apify that reads those boards directly.&lt;/p&gt;

&lt;p&gt;Here is one real run: engineering jobs at seven AI companies.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  The input
&lt;/h2&gt;

&lt;p&gt;You can paste a careers link, the company's website, or just its name. The tool finds the right board and says how it found it, so nothing is guessed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"companies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"https://jobs.ashbyhq.com/openai"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"https://job-boards.greenhouse.io/anthropic"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"perplexity.ai"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"ElevenLabs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"https://jobs.ashbyhq.com/cohere"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"https://jobs.lever.co/mistral"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"huggingface.co"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"titleKeywords"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"engineer"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The run took 9 seconds and saved 691 open jobs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who is hiring
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI&lt;/strong&gt;: 356 engineering jobs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anthropic&lt;/strong&gt;: 209&lt;/li&gt;
&lt;li&gt;Perplexity 46, ElevenLabs 41, Cohere 34, Hugging Face 5&lt;/li&gt;
&lt;li&gt;Mistral's board had no open jobs that day&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What they pay
&lt;/h2&gt;

&lt;p&gt;497 of the 691 jobs publish a yearly salary range in US dollars. Take the middle of each range, and half of them are above &lt;strong&gt;$355,500 a year&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where
&lt;/h2&gt;

&lt;p&gt;483 of the jobs (about 7 in 10) are in the United States. The rest are spread across 20 other countries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Following hiring over time
&lt;/h2&gt;

&lt;p&gt;Give the run a watch name and schedule it. The first run saves every job as a starting point; after that, each run saves only the jobs that are new, and lists the ones that closed in a separate table.&lt;/p&gt;

&lt;p&gt;I tried it on 25 tech companies with 7,492 open jobs between them. Checked again five hours later (on a Saturday), the next run found 1 new job (a senior engineer at Cloudflare) and 1 that closed (a compliance role at Stripe). Small, but that is the point: a daily check returns only what changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://apify.com/cleanscrape/career-site-jobs-scraper" rel="noopener noreferrer"&gt;https://apify.com/cleanscrape/career-site-jobs-scraper&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;$1 per 1,000 jobs plus $2 per 1,000 companies, less on paid Apify plans: the run above costs about $0.70. Export to Excel, CSV or Google Sheets, or call it from your own code or an AI agent through Apify's MCP server.&lt;/p&gt;

&lt;p&gt;Niko, CleanScrape developer&lt;/p&gt;

</description>
      <category>datascience</category>
      <category>webscraping</category>
      <category>career</category>
      <category>ai</category>
    </item>
    <item>
      <title>Checking casino affiliate pages for 18+ notices and terms, page by page</title>
      <dc:creator>CleanScrape</dc:creator>
      <pubDate>Mon, 19 Oct 2026 10:23:50 +0000</pubDate>
      <link>https://dev.to/cleanscrape/checking-casino-affiliate-pages-for-18-notices-and-terms-page-by-page-4hjk</link>
      <guid>https://dev.to/cleanscrape/checking-casino-affiliate-pages-for-18-notices-and-terms-page-by-page-4hjk</guid>
      <description>&lt;p&gt;Casino brands work with hundreds of affiliate and review sites, and each of those pages tells players something about the brand's bonus. Whether a page shows an age notice, links to safer-gambling help and puts the terms next to the offer is something compliance teams check by hand, page by page. I built a small tool on Apify that does the reading: it searches Google from the country you choose, reads every page through a connection in that country, and returns one row per page.&lt;/p&gt;

&lt;p&gt;No casino is named or shown in this video: brands, sites, offers, promo codes and links are blurred. It is about checking pages, not about any offer.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  What one run found
&lt;/h2&gt;

&lt;p&gt;The numbers are from one real run on Oct 18 2026 (United Kingdom, one brand): 10 pages on 8 sites, checked in under a minute and a half. Across those pages the brand's offer appeared in 9 different versions. All 5 affiliate pages showed an age notice and linked to safer-gambling help; 4 pages showed the offer with no terms next to it. Pages built with JavaScript are marked, so a notice they show later is not counted as missing. The rows report what each page shows and what is missing from it; they are not a legal verdict, since the rules differ by country and by who a page targets.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it reads a page
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The offer:&lt;/strong&gt; from the title, the main heading, offer cards and comparison tables. In a table that lists several casinos, an offer counts only when it sits in your brand's row.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notices:&lt;/strong&gt; age notices (18+, 19+, 21+), safer-gambling links and helplines (BeGambleAware, GamCare, GAMSTOP, 1-800-GAMBLER, ConnexOntario and others), an ad or affiliate disclosure, and wording such as "risk-free".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Terms next to the offer:&lt;/strong&gt; T&amp;amp;Cs, wagering, expiry or minimum deposit in the offer's box, or within about 500 characters of the offer's numbers in the page text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Country:&lt;/strong&gt; each page is read from the country being checked; in our tests one page in eight showed a different offer to visitors from another country.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pages it cannot read&lt;/strong&gt; (bot checks, files, JavaScript-only pages) are listed in the run report with the reason, and never charged.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The price is $8 per 1,000 saved pages; pages without an offer and pages that could not be read are free.&lt;/p&gt;

&lt;p&gt;Try it: &lt;a href="https://apify.com/cleanscrape/casino-bonus-checker" rel="noopener noreferrer"&gt;https://apify.com/cleanscrape/casino-bonus-checker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Maintained by CleanScrape. Questions or a reproducible issue: &lt;a href="mailto:contact.cleanscrape@gmail.com"&gt;contact.cleanscrape@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;CleanScrape is independent of Apify and of every casino, affiliate site and network.&lt;/p&gt;

</description>
      <category>datascience</category>
      <category>webscraping</category>
      <category>marketing</category>
      <category>analytics</category>
    </item>
    <item>
      <title>Which Kick streamers your competitors sponsor: 26 energy-drink sponsorships from 10,000 live streams</title>
      <dc:creator>CleanScrape</dc:creator>
      <pubDate>Mon, 12 Oct 2026 17:15:31 +0000</pubDate>
      <link>https://dev.to/cleanscrape/which-kick-streamers-your-competitors-sponsor-26-energy-drink-sponsorships-from-10000-live-streams-3388</link>
      <guid>https://dev.to/cleanscrape/which-kick-streamers-your-competitors-sponsor-26-energy-drink-sponsorships-from-10000-live-streams-3388</guid>
      <description>&lt;p&gt;Kick streamers advertise their sponsors in plain sight: a chat command in the stream title, a brand link in the channel's link panel, sometimes a promo code. Nobody collects that across channels, so I built a small tool on Apify that does: it scans the live streams on Kick, reads each channel's titles, links and the last month of broadcasts, and returns one row per streamer and brand.&lt;/p&gt;

&lt;p&gt;Here is one real use: an energy-drink brand for gamers checking which streamers its competitors sponsor.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  The input
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"brands"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"HOLY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"G FUEL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Red Bull"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DZIK"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxLiveStreams"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"minViewers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The run looked through 10,000 live streams, picked the 26 streamers whose live title named one of the brands, and checked each channel in depth. It took about four minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  One row per streamer and brand
&lt;/h2&gt;

&lt;p&gt;Each sponsorship row says where the brand shows up (live title, past broadcast titles, channel links, bio), how many of the streamer's last 30 broadcasts named it, how many hours those were, and any promo or affiliate codes. One example: &lt;strong&gt;rybsonlol&lt;/strong&gt;, live with 20,518 viewers at the time, named HOLY in all 30 recent broadcasts, 276.6 hours.&lt;/p&gt;

&lt;h2&gt;
  
  
  The brand summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HOLY&lt;/strong&gt;: 16 streamers, 26,211 live viewers at the time, 357 broadcasts and 2,507 hours in the past month.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DZIK&lt;/strong&gt; and &lt;strong&gt;G FUEL&lt;/strong&gt;: 5 streamers each.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Red Bull&lt;/strong&gt;: none in this scan.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A sponsorship here means the channel points viewers to the brand. It is what the channel shows publicly, not a confirmed contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running it every day
&lt;/h2&gt;

&lt;p&gt;Give the run a watch name and schedule it. Each row then carries &lt;code&gt;isNew&lt;/code&gt;, so a new sponsorship (a streamer starting with a brand) stands out. Export any table to Excel or CSV.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://apify.com/cleanscrape/kick-sponsor-tracker" rel="noopener noreferrer"&gt;https://apify.com/cleanscrape/kick-sponsor-tracker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;About 110 brands are recognised out of the box (drinks, gear, game stores, VPNs, skin sites, sportsbooks and more), and any brand you type is tracked the same way. $3 per 1,000 sponsorships, no start fee: this run cost about $0.18. No login, public data only.&lt;/p&gt;

&lt;p&gt;Niko, CleanScrape developer&lt;/p&gt;

</description>
      <category>datascience</category>
      <category>webscraping</category>
      <category>marketing</category>
      <category>analytics</category>
    </item>
    <item>
      <title>Who sold the most Pokémon cards on Whatnot in a day: two checks of the top 50 sellers</title>
      <dc:creator>CleanScrape</dc:creator>
      <pubDate>Mon, 12 Oct 2026 16:00:06 +0000</pubDate>
      <link>https://dev.to/cleanscrape/who-sold-the-most-pokemon-cards-on-whatnot-in-a-day-two-checks-of-the-top-50-sellers-2dh6</link>
      <guid>https://dev.to/cleanscrape/who-sold-the-most-pokemon-cards-on-whatnot-in-a-day-two-checks-of-the-top-50-sellers-2dh6</guid>
      <description>&lt;p&gt;Whatnot ranks its top sellers per category every week, but the leaderboard does not say how much each seller sold or who is growing. I built a small tool on Apify that saves the top sellers with their lifetime items sold, followers, rating and rank, and compares every run with the one before.&lt;/p&gt;

&lt;p&gt;Here is one real use: the top 50 Pokémon card sellers, checked twice, a day apart.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  The input
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"categories"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Pokémon Cards"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"topSellers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"historyName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Daily check"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The history name ties runs together: each run is compared with the last run under the same name. The first run, on Oct 11 at 14:51 UTC, saved the 50 sellers as a starting point. The second, 24.5 hours later, saved them again in 15 seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed in a day
&lt;/h2&gt;

&lt;p&gt;Each row of the second run has the change since the first: items sold since the last check, sales per day, new followers and the rank change.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The 48 sellers in the top 50 on both days sold &lt;strong&gt;41,380 items&lt;/strong&gt; between the checks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;outsidehits&lt;/strong&gt; sold 2,633 items, gained 1,447 followers and moved from #13 to #10.&lt;/li&gt;
&lt;li&gt;The biggest climber, &lt;strong&gt;pokeynpulls&lt;/strong&gt;, went from #23 to #16.&lt;/li&gt;
&lt;li&gt;Two sellers are new in the top 50.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Items sold come from Whatnot's own lifetime count on each profile, so "sold since the last check" is simply the difference between two checks. Whatnot can show the count a little late for sellers who are live, which is why a daily schedule works better than an hourly one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running it every day
&lt;/h2&gt;

&lt;p&gt;Save the input as a task and schedule it daily. Every run adds a day of sales, followers and rank for each seller, and the "Changes since last check" view shows only the columns that moved. Export any view to Excel or CSV.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://apify.com/cleanscrape/whatnot-seller-tracker" rel="noopener noreferrer"&gt;https://apify.com/cleanscrape/whatnot-seller-tracker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;$3 per 1,000 sellers, no start fee: a daily check of 50 sellers costs about $0.15. No login, public data only.&lt;/p&gt;

&lt;p&gt;Niko, CleanScrape developer&lt;/p&gt;

</description>
      <category>datascience</category>
      <category>webscraping</category>
      <category>python</category>
      <category>pokemon</category>
    </item>
    <item>
      <title>What a PSA 10 Charizard costs on Whatnot, from 73 live listings</title>
      <dc:creator>CleanScrape</dc:creator>
      <pubDate>Sun, 11 Oct 2026 15:43:20 +0000</pubDate>
      <link>https://dev.to/cleanscrape/what-a-psa-10-charizard-costs-on-whatnot-from-73-live-listings-3dl2</link>
      <guid>https://dev.to/cleanscrape/what-a-psa-10-charizard-costs-on-whatnot-from-73-live-listings-3dl2</guid>
      <description>&lt;p&gt;Whatnot is the live shopping marketplace where a lot of trading cards, sneakers and collectibles change hands, often during live streams. It has no public API for listings, so I built a small tool on Apify that turns a Whatnot search into a table, with the seller's track record on every row.&lt;/p&gt;

&lt;p&gt;Here is one real use: what does a PSA 10 Charizard cost on Whatnot right now, and who is selling them?&lt;/p&gt;

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

&lt;h2&gt;
  
  
  The search
&lt;/h2&gt;

&lt;p&gt;The input works like the filters on the website: a keyword, a category, and Whatnot's own card filters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"searchQueries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"charizard"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"categories"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Pokémon Cards"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"gradedOnly"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"gradingServices"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"PSA"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"grades"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"10"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"buyFormat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"buy_it_now"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"price_asc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxResultsPerSearch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The run returned 73 listings in 16 seconds. Each row has the price, currency, quantity, category, the date it was listed and a link, plus the seller's items sold on Whatnot, followers, rating and number of reviews.&lt;/p&gt;

&lt;h2&gt;
  
  
  The prices
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;Listings&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Under $100&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$100 to $499&lt;/td&gt;
&lt;td&gt;36&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$500 to $1,999&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$2,000 and up&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The cheapest was $15 and the most expensive $490,000, a 1999 first edition. One more listing asked $999,999, a placeholder price rather than a real offer, so I left it out of the table. The middle listing of all 73 was $300 ($292.50 without the placeholder).&lt;/p&gt;

&lt;p&gt;Two things to keep in mind. These are asking prices: Whatnot shows sold prices only to logged-in users, and the tool never logs in. And "PSA 10" is a filter on how sellers tag their listings, so a few titles mention other grades. Read the titles before you compare.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who is selling
&lt;/h2&gt;

&lt;p&gt;The seller columns are what make this more than a price list. The cheapest PSA 10 Charizard from a seller rated 5.0 with over a thousand sales was $100, from a seller with 11,846 items sold. In Python, with the Apify client:&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;statistics&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;median&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;apify_client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ApifyClient&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ApifyClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cleanscrape/whatnot-scraper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;searchQueries&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;charizard&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;categories&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Pokémon Cards&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;gradedOnly&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gradingServices&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PSA&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;grades&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;10&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;buyFormat&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;buy_it_now&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;sort&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_asc&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;maxResultsPerSearch&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&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="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;defaultDatasetId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;iterate_items&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;real&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;999999&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="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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;listings, median&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;median&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;real&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;trusted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;real&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sellerRating&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sellerSoldCount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;trusted&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sellerUsername&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sellerSoldCount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Live shows
&lt;/h2&gt;

&lt;p&gt;Switch "What to find" to live and upcoming shows and the same category gives you the streams. The top 100 live Pokémon card shows had 6,041 viewers between them when I ran it, the biggest over a thousand. Each show row has the title, viewers, start time, format (52 Singles, 29 Surprise Sets and 19 Breaks in this run), tags and seller, and you can ask for the items for sale in each show too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Only new listings
&lt;/h2&gt;

&lt;p&gt;For deal alerts, sort by "Newly listed", turn on "Only listings or shows not saved before" and schedule the task. Each run looks at the newest listings and returns the ones earlier runs did not save, plus price drops on ones they did. The skipped ones are not charged.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://apify.com/cleanscrape/whatnot-scraper" rel="noopener noreferrer"&gt;Whatnot Scraper on Apify&lt;/a&gt;. You pay per listing saved, and the search above cost about $0.15. It works on all eight Whatnot marketplaces: the US, Canada, the UK, Germany, France, Belgium, the Netherlands and Australia.&lt;/p&gt;

</description>
      <category>datascience</category>
      <category>webscraping</category>
      <category>python</category>
      <category>pokemon</category>
    </item>
    <item>
      <title>What a data analyst earns in New York, Chicago and Austin, from 150 Google Jobs listings</title>
      <dc:creator>CleanScrape</dc:creator>
      <pubDate>Wed, 07 Oct 2026 18:31:59 +0000</pubDate>
      <link>https://dev.to/cleanscrape/what-a-data-analyst-earns-in-new-york-chicago-and-austin-from-150-google-jobs-listings-48ke</link>
      <guid>https://dev.to/cleanscrape/what-a-data-analyst-earns-in-new-york-chicago-and-austin-from-150-google-jobs-listings-48ke</guid>
      <description>&lt;p&gt;Google Jobs is the job search built into Google. It pulls listings from LinkedIn, Indeed, Glassdoor, company career sites and local job boards into one place, which makes it a good single source when you want to compare jobs across cities. It has no public API, so I built a small tool on Apify that turns a Google Jobs search into a table.&lt;/p&gt;

&lt;p&gt;Here is one real use: I wanted to see what data analyst jobs pay in New York, Chicago and Austin.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  The search
&lt;/h2&gt;

&lt;p&gt;The input is a job title and a list of locations. Every title is searched in every location:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"queries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"data analyst"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"locations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"New York, NY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Chicago, IL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Austin, TX"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxJobsPerSearch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The run returned 150 jobs in 43 seconds. Most came via LinkedIn (34), Indeed (16), Dice (8) and Monster (8); the rest from company career sites and smaller boards.&lt;/p&gt;

&lt;h2&gt;
  
  
  Salaries as numbers
&lt;/h2&gt;

&lt;p&gt;Google shows pay as text, such as "$124K–$177K a year" or "$57.70–$62.50 an hour". The tool splits that into &lt;code&gt;salaryMin&lt;/code&gt;, &lt;code&gt;salaryMax&lt;/code&gt;, &lt;code&gt;salaryCurrency&lt;/code&gt; and &lt;code&gt;salaryPeriod&lt;/code&gt;, so you can sort and filter without parsing anything yourself.&lt;/p&gt;

&lt;p&gt;64 of the 150 jobs listed a salary. Taking the midpoint of each yearly range and the median per city:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;City&lt;/th&gt;
&lt;th&gt;Jobs with a yearly salary&lt;/th&gt;
&lt;th&gt;Median of range midpoints&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;New York&lt;/td&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;td&gt;$106,734&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Chicago&lt;/td&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;td&gt;$97,500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Austin&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;$110,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These are small samples from one search on October 6, 2026, not a salary survey. Austin coming out on top surprised me; with 13 jobs it can easily move by the next run.&lt;/p&gt;

&lt;p&gt;In Python, with the Apify client:&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;statistics&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;median&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;apify_client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ApifyClient&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ApifyClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cleanscrape/google-jobs-scraper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;queries&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data analyst&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;locations&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;New York, NY&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;Chicago, IL&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;Austin, TX&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;maxJobsPerSearch&lt;/span&gt;&lt;span class="sh"&gt;"&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="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;jobs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;defaultDatasetId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;iterate_items&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;New York, NY&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;Chicago, IL&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;Austin, TX&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;mids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;salaryMin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;salaryMax&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;jobs&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;searchLocation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;salaryPeriod&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;year&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;city&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;mids&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;median&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mids&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;mids&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  More than 10 jobs per search
&lt;/h2&gt;

&lt;p&gt;Google Jobs shows 10 jobs per search. To get more, the tool runs close variations of the same search (posted today, this week, full time, remote, senior and so on) and keeps each job once. A search stops when the variations stop finding new jobs, so a narrow search ends early instead of paying for repeats.&lt;/p&gt;

&lt;h2&gt;
  
  
  Only new jobs
&lt;/h2&gt;

&lt;p&gt;For job alerts, turn on "Only jobs not saved before" and schedule the task. Each run returns only jobs earlier runs did not save, and the skipped ones are not charged.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://apify.com/cleanscrape/google-jobs-scraper" rel="noopener noreferrer"&gt;Google Jobs Scraper on Apify&lt;/a&gt;. You pay per job saved: $2.95 per 1,000 jobs since October 21, 2026, less on paid Apify plans. At that price the 150-job run above costs about $0.44. It works in 36 countries; outside English-speaking ones, type the job title in the local language.&lt;/p&gt;

</description>
      <category>datascience</category>
      <category>jobs</category>
      <category>webscraping</category>
      <category>python</category>
    </item>
    <item>
      <title>What Chinese viewers say about coffee, second by second</title>
      <dc:creator>CleanScrape</dc:creator>
      <pubDate>Tue, 06 Oct 2026 05:50:02 +0000</pubDate>
      <link>https://dev.to/cleanscrape/what-chinese-viewers-say-about-coffee-second-by-second-1gb8</link>
      <guid>https://dev.to/cleanscrape/what-chinese-viewers-say-about-coffee-second-by-second-1gb8</guid>
      <description>&lt;p&gt;If you want to know what Chinese viewers watch and say about a topic, Bilibili is one of the best places to look. It is one of China's biggest video sites, and its viewers comment in two ways: ordinary comments under the video, and danmaku, the comments that fly across the video at the moment they were written.&lt;/p&gt;

&lt;p&gt;I built &lt;a href="https://apify.com/cleanscrape/bilibili-scraper" rel="noopener noreferrer"&gt;CleanScrape's Bilibili Scraper&lt;/a&gt; to get both into a spreadsheet without a Bilibili account. I'm the developer, so this is a walkthrough of my own tool, not an independent review. Every number in it was checked against my runs.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  One search term, 100 videos
&lt;/h2&gt;

&lt;p&gt;For the example I searched for 咖啡 (coffee) and turned on top comments and danmaku. You need an Apify account to run the Actor, but no Bilibili login or cookies. The same input as JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"searchQueries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"咖啡"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxVideosPerQuery"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"includeComments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"includeDanmaku"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxDanmakuPerVideo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The run took 81 seconds and saved 100 videos with views, likes, coins, favorites, shares and tags, plus 1,357 top comments and replies and 12,055 danmaku. Videos, comments, danmaku and creators each land in their own table, so an export holds one kind of row.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it doesn't get blocked
&lt;/h2&gt;

&lt;p&gt;Bilibili limits how fast one visitor can read each kind of data, and it blocks an IP for minutes to an hour when that limit is crossed. I measured those limits field by field before building the Actor. It spreads the work over several proxy connections at once (nine in this run), keeps each one under the measured pace, and moves work elsewhere when Bilibili refuses a request. In this run, 5 of 604 requests were refused, all for danmaku, and every one was retried on another connection. No video is missing its danmaku.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the danmaku show
&lt;/h2&gt;

&lt;p&gt;The most-watched video in the results, about drinking six cups of coffee a day, has 5,108,457 views and 63,604 coins. A second run collected the 1,800 danmaku Bilibili's player loads for it (10,343 were sent in total), each with its time in the video.&lt;/p&gt;

&lt;p&gt;Count them in 20-second steps and the busiest stretch after the opening is 0:40 to 1:00, with 136 danmaku. 21 of those are about bitterness, and the running joke is that life is more bitter than coffee:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;再苦能有生活苦: "Can it be more bitter than life?"&lt;/li&gt;
&lt;li&gt;咖啡没有我的命苦: "Coffee isn't as bitter as my life"&lt;/li&gt;
&lt;li&gt;因为生活比咖啡还苦: "Because life is even more bitter than coffee"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That kind of moment-by-moment reaction is hard to get any other way. Comments tell you what people thought after watching; danmaku tell you what they felt at a given second.&lt;/p&gt;

&lt;h2&gt;
  
  
  Top comments
&lt;/h2&gt;

&lt;p&gt;Without login Bilibili shows the top comments of a video (usually 3) and the first 20 replies under each, so this is a sample, not every comment. On the coffee video, the pinned top comment asks whether anyone has managed to quit coffee. It has 5,941 likes and 714 replies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Export and cost
&lt;/h2&gt;

&lt;p&gt;Open &lt;strong&gt;Storage &amp;gt; Dataset&lt;/strong&gt;, choose Default (videos), Comments, Danmaku or Creators, and download CSV, Excel or JSON. From the API, the run object lists the four datasets under &lt;code&gt;storageIds.datasets&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;At base prices a video costs $1.49 per 1,000, a comment $0.49 per 1,000 and a danmaku $0.10 per 1,000, with no start fee and platform usage included. 100 videos with tags cost about $0.15. There are also ready-made examples for &lt;a href="https://apify.com/cleanscrape/bilibili-scraper/examples/bilibili-videos-for-a-keyword" rel="noopener noreferrer"&gt;a keyword&lt;/a&gt;, &lt;a href="https://apify.com/cleanscrape/bilibili-scraper/examples/bilibili-video-danmaku-export" rel="noopener noreferrer"&gt;one video's danmaku&lt;/a&gt; and &lt;a href="https://apify.com/cleanscrape/bilibili-scraper/examples/bilibili-creator-profile-and-videos" rel="noopener noreferrer"&gt;a creator's profile and videos&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Besides search terms, you can paste video links, BV ids, creator links or UIDs, or the whole text the Bilibili app copies with Share &amp;gt; Copy link.&lt;/p&gt;

&lt;p&gt;What it can't do without login: every comment of a video, a creator's full upload history (it uses their public collections and series), subtitles, and bilibili.tv, the international site.&lt;/p&gt;

&lt;p&gt;Questions or a reproducible problem: use the Actor's Issues tab or email &lt;a href="mailto:contact.cleanscrape@gmail.com"&gt;contact.cleanscrape@gmail.com&lt;/a&gt;. CleanScrape is independent of Bilibili and Apify.&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>api</category>
      <category>datascience</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>A week of Nvidia news, past the 100-article limit</title>
      <dc:creator>CleanScrape</dc:creator>
      <pubDate>Mon, 05 Oct 2026 16:05:12 +0000</pubDate>
      <link>https://dev.to/cleanscrape/a-week-of-nvidia-news-past-the-100-article-limit-jch</link>
      <guid>https://dev.to/cleanscrape/a-week-of-nvidia-news-past-the-100-article-limit-jch</guid>
      <description>&lt;p&gt;A Google News search stops at about 100 articles. That's fine for a quick look, but not if you want everything the press wrote about a company in one week. A big name like Nvidia gets more than 100 articles in a single day, so a week-long search quietly leaves most of them out.&lt;/p&gt;

&lt;p&gt;I built &lt;a href="https://apify.com/cleanscrape/google-news-scraper" rel="noopener noreferrer"&gt;CleanScrape's Google News Scraper and RSS Feed Reader&lt;/a&gt; partly for this. I'm the developer, so this is a walkthrough of my own tool, not an independent review. Every number in it was checked against my run.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  One search per day
&lt;/h2&gt;

&lt;p&gt;The fix is simple: instead of one search for the whole week, run one search for each day and combine the results. The Actor does that when you turn on &lt;strong&gt;Search each day separately&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For the example I typed &lt;code&gt;Nvidia&lt;/code&gt;, picked September 21 to 27, 2026, and set &lt;strong&gt;Maximum articles&lt;/strong&gt; to 300. You don't need a Google account or an API key. You do need an Apify account to run the Actor. The same input as JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"queries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Nvidia"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"edition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"US:en"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"startDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-09-21"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"endDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-09-27"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"splitByDay"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxArticles"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That run returned 276 articles instead of about 100, each with the headline, the publisher, the publish time and a link.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the week looked like
&lt;/h2&gt;

&lt;p&gt;Counted by publish day (in UTC), Friday was the busiest, with 64 articles. By publisher, Yahoo Finance alone ran 73 of the 276.&lt;/p&gt;

&lt;p&gt;One honest caveat: each day's search also returned Google's maximum of 100 entries, so the run report marks those days as possibly incomplete. More articles may exist. Splitting by day gets you much closer to the full picture, but for a name this busy it isn't a guarantee of every article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Publisher links
&lt;/h2&gt;

&lt;p&gt;Google News links point back to Google, not to the article. Where it can, the Actor turns them into the publisher's own link, and a &lt;strong&gt;link status&lt;/strong&gt; column tells you which ones it found. In this run, 85 links were turned into the publisher's page and 191 kept the Google News link, because Google limits how many links can be looked up in a row. The Google link still opens the article; it just takes one extra hop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Follow the topic after the first run
&lt;/h2&gt;

&lt;p&gt;To keep up with a topic without getting the same headlines again, turn on &lt;strong&gt;Only articles not saved before&lt;/strong&gt; and give it a &lt;strong&gt;Watch name&lt;/strong&gt;. Later runs with the same watch name return only articles that weren't delivered before. Save the input as a task and schedule it daily or weekly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"queries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Nvidia"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timeRange"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"day"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"newOnly"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"watchName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Nvidia news"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I wrote more about that setup in &lt;a href="https://dev.to/cleanscrape/a-small-news-watchlist-that-doesnt-send-the-same-headlines-every-day-71"&gt;a small news watchlist that doesn't send the same headlines every day&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Export and cost
&lt;/h2&gt;

&lt;p&gt;Export the &lt;strong&gt;Articles&lt;/strong&gt; view as CSV or Excel. The run report shows what every search returned, including which days hit Google's limit.&lt;/p&gt;

&lt;p&gt;The price is $0.95 per 1,000 saved articles, with no start fee and platform usage included. The 276 articles above cost about $0.26 at base prices. Check the Pricing tab for your account's rate, and set a spending limit before larger runs.&lt;/p&gt;

&lt;p&gt;Questions or a reproducible problem: use the Actor's Issues tab or email &lt;a href="mailto:contact.cleanscrape@gmail.com"&gt;contact.cleanscrape@gmail.com&lt;/a&gt;. CleanScrape is independent of Google and Apify, and Nvidia is used here as a public-news example, not an endorsement.&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>api</category>
      <category>datascience</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>pytrends keeps failing with 429 errors? Here's a one-line fix</title>
      <dc:creator>CleanScrape</dc:creator>
      <pubDate>Sun, 04 Oct 2026 14:04:04 +0000</pubDate>
      <link>https://dev.to/cleanscrape/pytrends-keeps-failing-with-429-errors-heres-a-one-line-fix-4g00</link>
      <guid>https://dev.to/cleanscrape/pytrends-keeps-failing-with-429-errors-heres-a-one-line-fix-4g00</guid>
      <description>&lt;p&gt;If you have a Python script that pulls Google Trends data with pytrends, there's a good chance it stopped working. pytrends was archived in April 2025, and scripts using its unofficial endpoints can encounter &lt;code&gt;429 Too Many Requests&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I built &lt;a href="https://github.com/CleanScrape/trendreq" rel="noopener noreferrer"&gt;trendreq&lt;/a&gt; for scripts using the common &lt;code&gt;TrendReq&lt;/code&gt; methods. It returns pandas DataFrames, but the requests run on my &lt;a href="https://apify.com/cleanscrape/google-trends-scraper" rel="noopener noreferrer"&gt;Google Trends Actor&lt;/a&gt; on Apify, where the proxies and retries are handled for you. I'm the developer, so this is a walkthrough of my own tool, not an independent review. The output below is from a real run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why pytrends gets 429s
&lt;/h2&gt;

&lt;p&gt;Google offers an &lt;a href="https://developers.google.com/search/apis/trends" rel="noopener noreferrer"&gt;official Trends API alpha&lt;/a&gt;, with access by application. pytrends does not use that API. pytrends talks to the same internal endpoints the website uses: one request for a short-lived token, then one per chart. Every request comes from your IP address, and Google limits how often one address can do that. Limits vary by traffic and connection; neither this wrapper nor a proxy can guarantee that requests will never be rate-limited.&lt;/p&gt;

&lt;p&gt;The usual advice is sleeping between calls, rotating proxies yourself, or patching the library. That works for a bit, then it doesn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  The change
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# from pytrends.request import TrendReq
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;trendreq&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TrendReq&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install it and set your Apify token (a free Apify account includes $5 of usage a month):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;trendreq
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;APIFY_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The method calls stay the same. One optional line, &lt;code&gt;fetch&lt;/code&gt;, gets several data types in one run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;pytrends&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TrendReq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en-US&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tz&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;360&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;pytrends&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build_payload&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;iced coffee&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;cold brew&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;timeframe&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;today 12-m&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;geo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;US&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;pytrends&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;interest_over_time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;related_queries&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;interest_by_region&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;over_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pytrends&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;interest_over_time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;by_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pytrends&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;interest_by_region&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resolution&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REGION&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inc_geo_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;related&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pytrends&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;related_queries&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What came back
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;interest_over_time()&lt;/code&gt;, the last few weeks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;            iced coffee  cold brew  isPartial
date
2026-09-06           57         63      False
2026-09-13           59         68      False
2026-09-20           47         51      False
2026-09-27           42         49      False
2026-10-04           32         33       True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;interest_by_region()&lt;/code&gt;, sorted by cold brew. Oregon and Washington lean hardest toward cold brew:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;           geoCode  iced coffee  cold brew
geoName
Oregon       US-OR           31         69
Washington   US-WA           35         65
Kansas       US-KS           35         65
Montana      US-MT           36         64
California   US-CA           37         63
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the rising related queries for cold brew, which is where product ideas tend to show up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                                 query  value
0      toasted coconut cream cold brew  19700
1           smores cold brew starbucks  19700
4    how to make cold brew concentrate   2050
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The whole thing took one run of about 9 seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  One run instead of three
&lt;/h2&gt;

&lt;p&gt;Each method call starts one Apify run, and each run has a small start fee. If you want several data types for the same keywords, ask for them together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;pytrends&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;interest_over_time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;related_queries&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;interest_by_region&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, the three methods read from the same run. The example above did exactly that: 102 rows, about $0.36 at the base price.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's different from pytrends
&lt;/h2&gt;

&lt;p&gt;Most of it works the same, but not all of it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Related topics come back empty.&lt;/strong&gt; Google currently returns an empty list for automated requests (pytrends gets the same), so &lt;code&gt;related_topics()&lt;/code&gt; gives &lt;code&gt;None&lt;/code&gt; with a warning. Related queries work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;City results get coordinates.&lt;/strong&gt; &lt;code&gt;interest_by_region(resolution="CITY")&lt;/code&gt; adds latitude and longitude, because the US has several Springfields and they shouldn't merge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;US metro areas work&lt;/strong&gt; with &lt;code&gt;resolution="DMA"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;gprop&lt;/code&gt; isn't supported yet&lt;/strong&gt;, so YouTube, News and Shopping search raise a clear error instead of returning web data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;suggestions()&lt;/code&gt; and &lt;code&gt;categories()&lt;/code&gt; aren't there yet.&lt;/strong&gt; They raise &lt;code&gt;NotImplementedError&lt;/code&gt; with a short explanation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trending searches&lt;/strong&gt; (&lt;code&gt;trending_searches&lt;/code&gt;, &lt;code&gt;today_searches&lt;/code&gt;) work, and &lt;code&gt;trending_now("US")&lt;/code&gt; adds approximate traffic and related news headlines.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The exception names are the same, so &lt;code&gt;except ResponseError:&lt;/code&gt; blocks keep working.&lt;/p&gt;

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

&lt;p&gt;You pay Apify for the Actor's rows: $0.05 per run plus $0.003 per row at the base price, less on paid plans. Two keywords over 12 months is about $0.37. Today's trending searches for one country is about $0.08. The free monthly credit covers a few dozen typical calls.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Code, docs and offline tests: &lt;a href="https://github.com/CleanScrape/trendreq" rel="noopener noreferrer"&gt;github.com/CleanScrape/trendreq&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The Actor it runs on: &lt;a href="https://apify.com/cleanscrape/google-trends-scraper" rel="noopener noreferrer"&gt;apify.com/cleanscrape/google-trends-scraper&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If something you rely on in pytrends doesn't work, open an issue on GitHub. I'd rather hear about it and fix it.&lt;/p&gt;

</description>
      <category>python</category>
      <category>datascience</category>
      <category>seo</category>
      <category>webscraping</category>
    </item>
    <item>
      <title>How Sinner won Wimbledon 2025, in break points</title>
      <dc:creator>CleanScrape</dc:creator>
      <pubDate>Sat, 03 Oct 2026 20:01:09 +0000</pubDate>
      <link>https://dev.to/cleanscrape/how-sinner-won-wimbledon-2025-in-break-points-3jjc</link>
      <guid>https://dev.to/cleanscrape/how-sinner-won-wimbledon-2025-in-break-points-3jjc</guid>
      <description>&lt;p&gt;The scoreline of the 2025 Wimbledon men's final says Jannik Sinner beat Carlos Alcaraz 4-6 6-4 6-4 6-4. It doesn't say how. For that you need the match statistics, and for a whole tournament you need them in one table, with the counts behind every percentage.&lt;/p&gt;

&lt;p&gt;I built &lt;a href="https://apify.com/cleanscrape/tennis-match-data" rel="noopener noreferrer"&gt;CleanScrape's Tennis Scraper API&lt;/a&gt; to get that table from Flashscore. I'm the developer, so this is a walkthrough of my own tool, not an independent review. Every number in it was checked against my run.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  One line of input
&lt;/h2&gt;

&lt;p&gt;Open the Actor and type &lt;code&gt;Wimbledon 2025&lt;/code&gt; into &lt;strong&gt;Tournaments, players or matches&lt;/strong&gt;. Set &lt;strong&gt;Maximum matches&lt;/strong&gt; to 500 and start.&lt;/p&gt;

&lt;p&gt;You don't need a Flashscore account, cookies or an API key. You do need an Apify account to run the Actor. The same input as JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"targets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Wimbledon 2025"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxResults"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The list takes other things too: a player (&lt;code&gt;Sinner 2026&lt;/code&gt;), a draw (&lt;code&gt;US Open women 2024&lt;/code&gt;), a common name (&lt;code&gt;Roland Garros 2024&lt;/code&gt;) or any Flashscore link. The run report says how each line was read. Mine said: &lt;em&gt;"Wimbledon 2025" was read as ATP Wimbledon 2025, WTA Wimbledon 2025.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What came back
&lt;/h2&gt;

&lt;p&gt;478 singles matches, men's and women's, qualifying included. Each row has the round, the score with tiebreak points (&lt;code&gt;7-6(2) 6-4 6-4&lt;/code&gt;), the status (&lt;code&gt;finished&lt;/code&gt;, &lt;code&gt;retired&lt;/code&gt; and so on), the match time, the umpire and the match statistics. All 478 had full statistics. The run took about nine minutes.&lt;/p&gt;

&lt;p&gt;The statistics keep their counts. You don't just get "first serve points won: 75%", you get &lt;code&gt;firstServePointsWonHome&lt;/code&gt; = 54 and &lt;code&gt;firstServePointsPlayedHome&lt;/code&gt; = 72. That matters as soon as you add matches together, because you can't average percentages from matches of different lengths.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding it up
&lt;/h2&gt;

&lt;p&gt;I took the men's main draw and summed each finalist's serve numbers over their seven matches:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Service games held&lt;/th&gt;
&lt;th&gt;Break points faced&lt;/th&gt;
&lt;th&gt;Break points saved&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sinner&lt;/td&gt;
&lt;td&gt;93 of 99&lt;/td&gt;
&lt;td&gt;23&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alcaraz&lt;/td&gt;
&lt;td&gt;118 of 133&lt;/td&gt;
&lt;td&gt;57&lt;/td&gt;
&lt;td&gt;42&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Sinner faced fewer than half as many break points as Alcaraz over the fortnight. In the final itself he saved 4 of 6.&lt;/p&gt;

&lt;p&gt;Two caveats. Sinner's fourth-round match against Grigor Dimitrov ended in retirement with Dimitrov two sets up, so it counts with the statistics of the part that was played. And seven matches against different opponents isn't a controlled comparison. It's a description of how the two got through the draw, not a ranking of servers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Point-by-point, form and head-to-head
&lt;/h2&gt;

&lt;p&gt;Two switches add more. &lt;strong&gt;Point-by-point&lt;/strong&gt; gives every game: who served, who won, whether serve was broken, and every point score with break points, set points and match points marked. The last game of the final went 15-0, 30-0, 40-0, 40-15, with match point flagged on the last two.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Form and head-to-head&lt;/strong&gt; adds each player's latest matches, overall and on the surface, and their earlier meetings. It's meant for matches coming up. For a past match, the form lists are what Flashscore shows today, so they can include later matches. The row says so.&lt;/p&gt;

&lt;h2&gt;
  
  
  Export and check the report
&lt;/h2&gt;

&lt;p&gt;Click &lt;strong&gt;Export&lt;/strong&gt;, pick the &lt;strong&gt;Statistics&lt;/strong&gt; view and download CSV or Excel. Use JSON when you want the nested data: per-set statistics, point-by-point and the form lists. Keep ID columns as text.&lt;/p&gt;

&lt;p&gt;The run report shows how each line was read, how many matches it listed, matched and saved, how many had full, basic or no statistics, and why the run stopped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use it on what you actually care about
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One tournament, several years:&lt;/strong&gt; &lt;code&gt;Wimbledon&lt;/code&gt;, with &lt;strong&gt;Editions per tournament&lt;/strong&gt; at 5.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A player's season:&lt;/strong&gt; &lt;code&gt;Swiatek 2025&lt;/code&gt;, with point-by-point if you want it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Yesterday's results:&lt;/strong&gt; leave the list empty and pick &lt;strong&gt;Yesterday&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Upcoming matches:&lt;/strong&gt; leave the list empty, pick &lt;strong&gt;Next 3 days&lt;/strong&gt;, status &lt;strong&gt;Scheduled&lt;/strong&gt;, and turn on form and head-to-head.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are ready-made examples for &lt;a href="https://apify.com/cleanscrape/tennis-match-data/examples/tennis-wimbledon-2025-statistics" rel="noopener noreferrer"&gt;Wimbledon 2025 with statistics&lt;/a&gt;, &lt;a href="https://apify.com/cleanscrape/tennis-match-data/examples/tennis-yesterday-atp-wta-results" rel="noopener noreferrer"&gt;yesterday's results&lt;/a&gt;, &lt;a href="https://apify.com/cleanscrape/tennis-match-data/examples/tennis-upcoming-form-head-to-head" rel="noopener noreferrer"&gt;upcoming matches with form and head-to-head&lt;/a&gt; and &lt;a href="https://apify.com/cleanscrape/tennis-match-data/examples/tennis-player-season-point-by-point" rel="noopener noreferrer"&gt;a player's season with point-by-point&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost and limits
&lt;/h2&gt;

&lt;p&gt;The base price is $1.00 per 1,000 matches. Match details (statistics, set details or point-by-point) add $1.50 per 1,000, and form and head-to-head add $0.50 per 1,000, both only when Flashscore has them for that match. The Wimbledon run above, 478 matches with statistics, comes to about $1.20 before tier discounts. Check the Pricing tab for your account's rate and set a spending limit for big runs.&lt;/p&gt;

&lt;p&gt;Coverage follows Flashscore. ATP, WTA, Challenger and Grand Slam matches have full statistics. Most ITF matches have scores but few or no statistics. Bookmaker odds and rankings aren't included, and live matches are a snapshot at collection time.&lt;/p&gt;

&lt;p&gt;If you work with an AI assistant, there's also a free &lt;a href="https://github.com/CleanScrape/agent-skills/tree/main/skills/apify-cleanscrape-tennis-research" rel="noopener noreferrer"&gt;tennis research skill&lt;/a&gt; that explains the fields and how to add statistics up without mixing percentages.&lt;/p&gt;

&lt;p&gt;Questions or a reproducible problem: use the Actor's Issues tab or email &lt;a href="mailto:contact.cleanscrape@gmail.com"&gt;contact.cleanscrape@gmail.com&lt;/a&gt;. CleanScrape is independent of Flashscore, the ATP and the WTA.&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>api</category>
      <category>datascience</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Read the comments before you pay for Likee reach</title>
      <dc:creator>CleanScrape</dc:creator>
      <pubDate>Sat, 03 Oct 2026 10:00:12 +0000</pubDate>
      <link>https://dev.to/cleanscrape/read-the-comments-before-you-pay-for-likee-reach-14b2</link>
      <guid>https://dev.to/cleanscrape/read-the-comments-before-you-pay-for-likee-reach-14b2</guid>
      <description>&lt;p&gt;Say you're about to pay a Likee creator to reach people in the United States. Views and likes tell you that something was watched. They don't tell you who watched it. The comments are a better clue, because people write them in their own language and about their own concerns.&lt;/p&gt;

&lt;p&gt;I built &lt;a href="https://apify.com/cleanscrape/likee-scraper" rel="noopener noreferrer"&gt;CleanScrape's Likee Scraper API&lt;/a&gt; to get those comments into a spreadsheet. I'm the developer, so this is a walkthrough of my own tool, not an independent review. Every number in it was checked against my run.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Start with a creator's recent videos
&lt;/h2&gt;

&lt;p&gt;For the example I used Likee's official US account, &lt;code&gt;@likee_usa&lt;/code&gt;. Open the Actor, paste the handle into &lt;strong&gt;Creators or video links&lt;/strong&gt;, choose &lt;strong&gt;Videos&lt;/strong&gt; and set &lt;strong&gt;Maximum results&lt;/strong&gt; to &lt;code&gt;10&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You don't need a Likee account, cookies or a separate API key. You do need an Apify account to run the Actor. The same input as JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"targets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"@likee_usa"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"videos"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxResults"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;Videos&lt;/strong&gt; view puts each caption beside its publish date, views, likes, comment count and shares. In my run, the post with the most discussion was "Real or Mini?", with 114 comments. That's the one I wanted to read.&lt;/p&gt;

&lt;p&gt;The counts are what Likee showed at collection time. Some come from share pages, which round them (&lt;code&gt;5.90K&lt;/code&gt;). The &lt;code&gt;countPrecision&lt;/code&gt; column tells you which ones are exact.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then read the comments
&lt;/h2&gt;

&lt;p&gt;Copy the video's link (in the Likee app: &lt;strong&gt;Share &amp;gt; Copy link&lt;/strong&gt;), paste it into the same field, switch to &lt;strong&gt;Comments&lt;/strong&gt; and ask for &lt;code&gt;40&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"targets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"https://likee.video/@likee_usa/video/7629882278902002999"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"comments"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxResults"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what came back. 22 of the 40 comments were in Russian. One more was in Tajik. The most-liked comment, with 37 likes, was "В лайке есть сша?!", roughly "Is there a USA on Likee?!".&lt;/p&gt;

&lt;p&gt;That doesn't prove where the viewers live. Language is a clue, not a location, and 40 comments from one video is a small sample. But if you were budgeting for an American audience, it's the kind of thing you want to see before paying, not after.&lt;/p&gt;

&lt;p&gt;A note on counting: I first counted 24 comments in Cyrillic and nearly wrote "24 in Russian". Two of them weren't. If you do this check yourself, classify the language, not just the alphabet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Export and check the report
&lt;/h2&gt;

&lt;p&gt;Click &lt;strong&gt;Export&lt;/strong&gt;, pick the &lt;strong&gt;Comments&lt;/strong&gt; view and download CSV or Excel. The Comments view includes the text, public author name, date, likes and the video each comment belongs to. Keep the ID columns as text when you import, so spreadsheets don't round the long numbers.&lt;/p&gt;

&lt;p&gt;Then open the run report. It shows how many comments were read, which inputs were checked and why the run stopped. In this run it stopped because it reached the 40-comment limit, not because the video ran out of comments. A finished run is not a complete history of a video's comments, and hidden or removed comments can't be collected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use it on the creator you're actually considering
&lt;/h2&gt;

&lt;p&gt;Replace the official account with the creator you're thinking about paying. A few setups that work well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One creator's recent posts:&lt;/strong&gt; their handle, Videos, 10 results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comments on one post:&lt;/strong&gt; its Share link, Comments, 20 to 40 results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A sample across several posts:&lt;/strong&gt; their handle, Comments, &lt;strong&gt;Videos per creator&lt;/strong&gt; 3 and &lt;strong&gt;Comments per video&lt;/strong&gt; 15. &lt;strong&gt;Maximum results&lt;/strong&gt; is the total for the whole run, so set it to 45.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are two ready-made examples using Likee's own accounts: &lt;a href="https://apify.com/cleanscrape/likee-scraper/examples/likee-compare-two-creators" rel="noopener noreferrer"&gt;compare two official accounts&lt;/a&gt; and &lt;a href="https://apify.com/cleanscrape/likee-scraper/examples/likee-sample-creator-comments" rel="noopener noreferrer"&gt;read a comment sample&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost and limits
&lt;/h2&gt;

&lt;p&gt;The base price is $1.95 per 1,000 saved videos or comments, with no startup fee. The 40-comment run above costs $0.078 at that rate, before any tier discount. Check the Pricing tab for your account's rate, and set a spending limit before larger runs.&lt;/p&gt;

&lt;p&gt;It collects public videos and comments only. There's no keyword or hashtag search, no private content, and no guarantee of a complete history. The maximum you set is a ceiling, not a promise that the source has that many.&lt;/p&gt;

&lt;p&gt;If you work with an AI assistant, there's also a free &lt;a href="https://github.com/CleanScrape/agent-skills/tree/main/skills/apify-cleanscrape-likee-research" rel="noopener noreferrer"&gt;Likee research skill&lt;/a&gt; that explains the fields and how to do this kind of comment check without overclaiming.&lt;/p&gt;

&lt;p&gt;Questions or a reproducible problem: use the Actor's Issues tab or email &lt;a href="mailto:contact.cleanscrape@gmail.com"&gt;contact.cleanscrape@gmail.com&lt;/a&gt;. CleanScrape is independent of Likee.&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>api</category>
      <category>marketing</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
