<?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: ReventaData</title>
    <description>The latest articles on DEV Community by ReventaData (@reventadata).</description>
    <link>https://dev.to/reventadata</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%2F4177459%2Fcc5d8f1f-f95e-4529-b62d-0bd135d64ca6.png</url>
      <title>DEV Community: ReventaData</title>
      <link>https://dev.to/reventadata</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/reventadata"/>
    <language>en</language>
    <item>
      <title>How to Scrape eBay Spain Listings and Prices with Python</title>
      <dc:creator>ReventaData</dc:creator>
      <pubDate>Mon, 02 Nov 2026 10:06:15 +0000</pubDate>
      <link>https://dev.to/reventadata/how-to-scrape-ebay-spain-listings-and-prices-with-python-351j</link>
      <guid>https://dev.to/reventadata/how-to-scrape-ebay-spain-listings-and-prices-with-python-351j</guid>
      <description>&lt;p&gt;By the end of this tutorial, you will have a short Python script that turns an ebay.es search into structured rows: title, price in EUR, condition, auction state and bid count, shipping cost, ship-from country, and whether the seller is a private person or a business.&lt;/p&gt;

&lt;p&gt;eBay Spain puts a JavaScript browser challenge in front of its search pages. In testing on 2026-08-22, plain, datacenter and residential requests all got the same canned error page, while Apify Unblocker returned real result pages.&lt;/p&gt;

&lt;p&gt;In this guide, we use Python and the Apify Actor &lt;strong&gt;eBay Spain Scraper&lt;/strong&gt; (&lt;code&gt;reventadata/ebay-scraper&lt;/code&gt;). You will configure a search, run the Actor and read the rows. The rows shown below are a sample from a capture dated 2026-08-22, parsed with the Actor's own parser.&lt;/p&gt;

&lt;p&gt;⏱️ &lt;strong&gt;Time estimate:&lt;/strong&gt; one sitting: install one package, set one token, run three short Python blocks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To follow this tutorial, you will need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Python 3.11+&lt;/strong&gt; (&lt;code&gt;apify-client&lt;/code&gt; 3.3.0 requires it).&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Apify API client&lt;/strong&gt; for Python.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;Apify account&lt;/strong&gt; and its API token, which sits on the &lt;strong&gt;API &amp;amp; Integrations&lt;/strong&gt; page in Apify Console.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Install the client:&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; &lt;span class="s2"&gt;"apify-client~=3.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code reads the token from an environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;APIFY_API_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your_apify_token_here"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What you'll achieve
&lt;/h2&gt;

&lt;p&gt;You will turn an ebay.es search into one row per active listing. Each row carries the &lt;code&gt;listingId&lt;/code&gt; and a clean &lt;code&gt;url&lt;/code&gt;, the &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;price&lt;/code&gt; in &lt;code&gt;EUR&lt;/code&gt;, eBay's own &lt;code&gt;condition&lt;/code&gt; wording, &lt;code&gt;sellerType&lt;/code&gt; (&lt;code&gt;private&lt;/code&gt; or &lt;code&gt;business&lt;/code&gt;), the auction fields (&lt;code&gt;isAuction&lt;/code&gt;, &lt;code&gt;bidCount&lt;/code&gt;, &lt;code&gt;timeLeft&lt;/code&gt;, &lt;code&gt;endsAt&lt;/code&gt;), the shipping fields and &lt;code&gt;shipFrom&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Active listings only. Per the README, sold and completed listings are not available: eBay's sold filters send an anonymous visitor to a sign-in page. The README also states that eBay's robots.txt disallows the &lt;code&gt;/sch/&lt;/code&gt; search path this Actor reads, so you can weigh that yourself.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Example use case:&lt;/strong&gt; Suppose you want used iPhones from private sellers between 200 and 600 EUR. You would set &lt;code&gt;searchTerms: ["iphone 15 pro"]&lt;/code&gt;, &lt;code&gt;condition: "used"&lt;/code&gt;, &lt;code&gt;sellerType: "private"&lt;/code&gt;, &lt;code&gt;minPrice: 200&lt;/code&gt; and &lt;code&gt;maxPrice: 600&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Access eBay Spain Scraper
&lt;/h2&gt;

&lt;p&gt;Go to the &lt;a href="https://apify.com/reventadata/ebay-scraper" rel="noopener noreferrer"&gt;eBay Spain Scraper&lt;/a&gt; page on Apify Store. The README lists every input and output field. In this tutorial we drive the Actor from Python, so everything after this step happens in code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Configure the search
&lt;/h2&gt;

&lt;p&gt;The main input is &lt;code&gt;searchTerms&lt;/code&gt;, and it is required: one or more keywords, typed exactly as you would type them into eBay's own search box. Each term is searched in turn, and every row records the term it came from in &lt;code&gt;keyword&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Two inputs bound the run:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;maxItems&lt;/code&gt; (default 240) caps the rows saved across all terms.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;maxPages&lt;/code&gt; (1 to 500, default 500) caps the pages read per term. The Actor already stops at the real end of a query, worked out from eBay's own result count.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;itemsPerPage&lt;/code&gt; sets how many listings eBay puts on each page: &lt;code&gt;"60"&lt;/code&gt;, &lt;code&gt;"120"&lt;/code&gt; or &lt;code&gt;"240"&lt;/code&gt; (the default). Per the input description, 240 makes a quarter of the requests that 60 makes, for the same rows.&lt;/p&gt;

&lt;p&gt;Here is the setup. It searches &lt;code&gt;iphone&lt;/code&gt;, reads one page of 60 listings and saves at most 10 rows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&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="c1"&gt;# 1. Initialize ApifyClient with the token from the environment
&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="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;APIFY_API_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# 2. Define the search: one keyword, one page of 60, at most 10 rows
&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;searchTerms&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;iphone&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;itemsPerPage&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;60&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;maxPages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maxItems&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No proxy setting exists: the Actor always fetches through Apify Unblocker.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Add optional filters
&lt;/h2&gt;

&lt;p&gt;Three filters go to eBay itself and change the results it serves; one runs on the rows after fetching:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Values&lt;/th&gt;
&lt;th&gt;Where it runs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;condition&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;any&lt;/code&gt;, &lt;code&gt;new&lt;/code&gt;, &lt;code&gt;refurbished&lt;/code&gt;, &lt;code&gt;used&lt;/code&gt;, &lt;code&gt;forParts&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;eBay's own condition filter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;listingType&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;any&lt;/code&gt;, &lt;code&gt;auction&lt;/code&gt;, &lt;code&gt;buyItNow&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;eBay's own auction / Buy It Now filter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;minPrice&lt;/code&gt; / &lt;code&gt;maxPrice&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;whole euros&lt;/td&gt;
&lt;td&gt;eBay's own price filter; omitted when empty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sellerType&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;any&lt;/code&gt;, &lt;code&gt;private&lt;/code&gt;, &lt;code&gt;business&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;On the rows, from the seller line eBay prints on each card&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three example combinations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Private sellers only:&lt;/strong&gt; &lt;code&gt;sellerType: "private"&lt;/code&gt;, any term.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live auctions:&lt;/strong&gt; &lt;code&gt;listingType: "auction"&lt;/code&gt;; each row then carries &lt;code&gt;bidCount&lt;/code&gt;, and &lt;code&gt;timeLeft&lt;/code&gt; when eBay prints one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Refurbished in a price band:&lt;/strong&gt; &lt;code&gt;condition: "refurbished"&lt;/code&gt;, &lt;code&gt;minPrice: 300&lt;/code&gt;, &lt;code&gt;maxPrice: 500&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ A value outside the lists above is refused before the run starts. A &lt;code&gt;minPrice&lt;/code&gt; above &lt;code&gt;maxPrice&lt;/code&gt; stops the run with an error at its start.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 4: Run the Actor
&lt;/h2&gt;

&lt;p&gt;Now start the run with &lt;code&gt;client.actor("reventadata/ebay-scraper").call(run_input=run_input)&lt;/code&gt;. The call starts the Actor on Apify and waits for it to finish before returning the 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="c1"&gt;# 3. Start the Actor run and wait for it to finish
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Starting eBay Spain extraction...&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;reventadata/ebay-scraper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SUCCEEDED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Run did not succeed (status: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;).&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 4. Fetch the saved listings
&lt;/span&gt;&lt;span class="n"&gt;items&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;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;default_dataset_id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;list_items&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Retrieved &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; listings.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behind the scenes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Actor builds the ebay.es search URL from your term and filters and fetches each page through Apify Unblocker.&lt;/li&gt;
&lt;li&gt;It reads eBay's results heading first. When eBay found nothing, the page still shows unrelated listings; none of it is collected.&lt;/li&gt;
&lt;li&gt;It parses each listing card, skips eBay's own promo cards, applies &lt;code&gt;sellerType&lt;/code&gt;, and saves the rows.&lt;/li&gt;
&lt;li&gt;It stops at &lt;code&gt;maxItems&lt;/code&gt;, at &lt;code&gt;maxPages&lt;/code&gt;, at the last real page from eBay's count, or at a page that adds no new listing.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 5: View and download results
&lt;/h2&gt;

&lt;p&gt;Loop over the rows to print the parts you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;current bid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;isAuction&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="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="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;currency&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Condition: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;condition&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Seller type: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sellerType&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Shipping: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;shippingText&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;not shown&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Link: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here are two rows, a sample from a capture dated 2026-08-22 (an &lt;code&gt;iphone&lt;/code&gt; search) parsed with the Actor's own parser. &lt;code&gt;keyword&lt;/code&gt; and &lt;code&gt;page&lt;/code&gt; come from the search loop; here they are the values passed to the parser. First, a fixed-price listing from a business seller:&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;"listingId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"147520935178"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Apple Iphone 15 Black 128GB (ohne Simlock)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url"&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://www.ebay.es/itm/147520935178"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"keyword"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"iphone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"page"&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="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usado"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sellerType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"business"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;369.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"buyItNowPrice"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"isAuction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"bidCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"timeLeft"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"endsAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"isBuyItNow"&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;"acceptsBestOffer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"shippingCost"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"freeShipping"&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;"shippingText"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Envío gratis"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"shipFrom"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Austria"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"energyClass"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"B"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sellerUsername"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"marketxpres"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sellerFeedbackPercent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;100.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sellerFeedbackCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;169&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;Second, an auction from a private seller that also offers Buy It Now:&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;"listingId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"278302959365"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"iPhone 17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url"&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://www.ebay.es/itm/278302959365"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"keyword"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"iphone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"page"&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="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usado"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sellerType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"private"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;400.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"buyItNowPrice"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1000.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"isAuction"&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;"bidCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;39&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"timeLeft"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Quedan 2 d 3 h"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"endsAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"(Lunes, 23:25)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"isBuyItNow"&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;"acceptsBestOffer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"shippingCost"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;15.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"freeShipping"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"shippingText"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"+ 15,00 EUR de envío"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"shipFrom"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"energyClass"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&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;Apify datasets export as JSON, CSV, XML, Excel, HTML table, RSS or JSONL.&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding your results
&lt;/h2&gt;

&lt;p&gt;The fields that matter most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;price&lt;/code&gt;: means two things, and &lt;code&gt;isAuction&lt;/code&gt; tells you which. On a fixed-price listing it is the asking price; on an auction it is the current bid. In the sample, 400 EUR is the bid after 39 bids, and &lt;code&gt;buyItNowPrice&lt;/code&gt; holds the seller's fixed 1,000 EUR.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sellerType&lt;/code&gt;: &lt;code&gt;private&lt;/code&gt; or &lt;code&gt;business&lt;/code&gt;, from eBay's own card line (&lt;em&gt;Vendedor particular&lt;/em&gt; / &lt;em&gt;Vendedor profesional&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sellerUsername&lt;/code&gt;, &lt;code&gt;sellerFeedbackPercent&lt;/code&gt;, &lt;code&gt;sellerFeedbackCount&lt;/code&gt;: business sellers only. On a private seller's row the keys are absent, not null, as in the auction above.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;condition&lt;/code&gt;: eBay's Spanish wording, verbatim (&lt;code&gt;Usado&lt;/code&gt;, &lt;code&gt;Reacondicionado&lt;/code&gt;, &lt;code&gt;Solo piezas&lt;/code&gt;), not mapped to a grade.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;shippingCost&lt;/code&gt;, &lt;code&gt;freeShipping&lt;/code&gt;, &lt;code&gt;shippingText&lt;/code&gt;: a number, a flag and eBay's own phrase. &lt;code&gt;shipFrom&lt;/code&gt; is filled only when the card says &lt;code&gt;desde &amp;lt;country&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;timeLeft&lt;/code&gt; and &lt;code&gt;endsAt&lt;/code&gt;: eBay's phrases. &lt;code&gt;endsAt&lt;/code&gt; is a weekday and clock time, not a date.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;energyClass&lt;/code&gt;: the EU energy label, A to G, not a condition grade.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Pro tips
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Leave &lt;code&gt;itemsPerPage&lt;/code&gt; at 240 for real runs.&lt;/strong&gt; The same rows come back in a quarter of the requests 60 needs. The 60 above only keeps the first test small.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filter on eBay first.&lt;/strong&gt; &lt;code&gt;condition&lt;/code&gt;, &lt;code&gt;listingType&lt;/code&gt; and the price bounds change what eBay serves. &lt;code&gt;sellerType&lt;/code&gt; only drops rows after the fetch, so pair it with a narrow term.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch terms in one run.&lt;/strong&gt; Put several keywords in &lt;code&gt;searchTerms&lt;/code&gt;. A listing saved under one term is not saved again under a later one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treat &lt;code&gt;price&lt;/code&gt; with &lt;code&gt;isAuction&lt;/code&gt;.&lt;/strong&gt; Before averaging prices, split auctions from fixed-price rows, or use &lt;code&gt;buyItNowPrice&lt;/code&gt; where an auction has one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start small.&lt;/strong&gt; Keep &lt;code&gt;maxPages: 1&lt;/code&gt; and &lt;code&gt;maxItems: 10&lt;/code&gt; until your downstream code handles the fields, then raise them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read the log on a short run.&lt;/strong&gt; eBay sometimes answers a URL with a full-size page that carries no listing at all. The Actor retries it, and if a page is still skipped after every retry, the log says how many pages were skipped, so a short dataset is never silent. Re-running usually picks those listings up.&lt;/li&gt;
&lt;/ol&gt;




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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero rows:&lt;/strong&gt; a run that is blocked, skips a page after every retry, cannot parse a results page or runs out of time ends FAILED. If pages loaded normally but your filters dropped everything, or eBay's own heading says zero results for the term, the run ends SUCCEEDED with an empty dataset and a status message saying so.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run stops at once:&lt;/strong&gt; &lt;code&gt;searchTerms&lt;/code&gt; was empty, or &lt;code&gt;minPrice&lt;/code&gt; is above &lt;code&gt;maxPrice&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fewer rows than expected:&lt;/strong&gt; read the lines near the end of the log: &lt;code&gt;Rejected N: seller is not private&lt;/code&gt; counts rows &lt;code&gt;sellerType&lt;/code&gt; dropped, and a line reports pages skipped after every retry. From Python: &lt;code&gt;client.log(run.id).get()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No sold prices:&lt;/strong&gt; not a bug. The Actor covers active listings only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;shipFrom&lt;/code&gt; is often null:&lt;/strong&gt; normal. eBay prints &lt;code&gt;desde &amp;lt;country&amp;gt;&lt;/code&gt; only on some cards; a domestic listing usually has none.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For help, use the Actor's &lt;a href="https://apify.com/reventadata/ebay-scraper" rel="noopener noreferrer"&gt;Store page&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pricing and next steps
&lt;/h2&gt;

&lt;p&gt;For current pricing and details, see the &lt;a href="https://apify.com/reventadata/ebay-scraper" rel="noopener noreferrer"&gt;Store page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To repeat a search, save the input as a task and add an Apify schedule, which runs an Actor or task on a cron expression (&lt;code&gt;0 8 * * *&lt;/code&gt; is every day at 8 AM). To react when a run finishes, add a webhook on &lt;code&gt;ACTOR.RUN.SUCCEEDED&lt;/code&gt;; its payload carries the run object, including &lt;code&gt;defaultDatasetId&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://apify.com/reventadata/ebay-scraper" rel="noopener noreferrer"&gt;eBay Spain Scraper on Apify Store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.apify.com/api/client/python/docs" rel="noopener noreferrer"&gt;Apify Python client documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What are you planning to track on eBay Spain? Drop a comment! 💬&lt;/p&gt;

</description>
      <category>python</category>
      <category>webscraping</category>
      <category>apify</category>
      <category>automation</category>
    </item>
    <item>
      <title>How to Scrape Back Market Spain Refurbished Prices with Python</title>
      <dc:creator>ReventaData</dc:creator>
      <pubDate>Mon, 02 Nov 2026 10:05:26 +0000</pubDate>
      <link>https://dev.to/reventadata/how-to-scrape-back-market-spain-refurbished-prices-with-python-3nbk</link>
      <guid>https://dev.to/reventadata/how-to-scrape-back-market-spain-refurbished-prices-with-python-3nbk</guid>
      <description>&lt;p&gt;By the end of this tutorial, you will have a short Python script that turns a Back Market Spain category into structured rows: model name, starting price, the price the device cost new, star rating, review count and condition grade.&lt;/p&gt;

&lt;p&gt;Back Market sells refurbished electronics, and backmarket.es sits behind Cloudflare Bot Management. In recon on 2026-08-22, requests with no proxy, datacenter and residential proxies got an error body instead of a page; Apify Unblocker returned the page.&lt;/p&gt;

&lt;p&gt;In this guide, we use Python and the Apify Actor &lt;strong&gt;Back Market Spain Scraper&lt;/strong&gt; (&lt;code&gt;reventadata/backmarket-scraper&lt;/code&gt;). You will pick a category, run the Actor and narrow rows by price and brand. The sample row below is a sample from a capture dated 2026-09-18, parsed with the Actor's own parser.&lt;/p&gt;

&lt;p&gt;⏱️ &lt;strong&gt;Time estimate:&lt;/strong&gt; one sitting: install one package, set one token, run three short Python blocks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To follow this tutorial, you will need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Python 3.11+&lt;/strong&gt; (&lt;code&gt;apify-client&lt;/code&gt; 3.3.0 requires it).&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Apify API client&lt;/strong&gt; for Python.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;Apify account&lt;/strong&gt; and its API token, which sits on the &lt;strong&gt;API &amp;amp; Integrations&lt;/strong&gt; page in Apify Console.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Install the client:&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; &lt;span class="s2"&gt;"apify-client~=3.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code reads the token from an environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;APIFY_API_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your_apify_token_here"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What you'll achieve
&lt;/h2&gt;

&lt;p&gt;You will turn one Back Market category page into one row per product model. A card on that page is a model, "iPhone 16", not a merchant offer. Each row carries &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;brand&lt;/code&gt;, &lt;code&gt;model&lt;/code&gt;, &lt;code&gt;price&lt;/code&gt; (the cheapest variant, the site's &lt;em&gt;Desde&lt;/em&gt;), &lt;code&gt;priceWhenNew&lt;/code&gt;, &lt;code&gt;rating&lt;/code&gt;, &lt;code&gt;ratingCount&lt;/code&gt;, &lt;code&gt;availableColors&lt;/code&gt;, &lt;code&gt;grade&lt;/code&gt;, &lt;code&gt;availableStock&lt;/code&gt; and &lt;code&gt;warrantyMonths&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Back Market names no merchant on its category or product pages, so rows carry no seller data. The payload holds a &lt;code&gt;sellerId&lt;/code&gt;; the Actor never reads it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Example use case:&lt;/strong&gt; Suppose you want refurbished iPhones that start between 300 and 700 EUR. You would put the iPhone category URL in &lt;code&gt;categories&lt;/code&gt;, set &lt;code&gt;minPrice: 300&lt;/code&gt; and &lt;code&gt;maxPrice: 700&lt;/code&gt;, and every saved row would have a starting price inside that band, with its price new beside it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Access Back Market Spain Scraper
&lt;/h2&gt;

&lt;p&gt;Go to the &lt;a href="https://apify.com/reventadata/backmarket-scraper" rel="noopener noreferrer"&gt;Back Market Spain Scraper&lt;/a&gt; page on Apify Store. The README lists every input and output field. In this tutorial we drive the Actor from Python, so everything after this step happens in code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Configure the category
&lt;/h2&gt;

&lt;p&gt;The one required input is &lt;code&gt;categories&lt;/code&gt;: one or more Back Market Spain category URLs, copied from the address bar. A category is a slug &lt;strong&gt;and&lt;/strong&gt; the UUID after it, for example &lt;code&gt;iphone/aabc736a-cb66-4ac0-a3b7-0f449781ed39&lt;/code&gt;; a slug alone is an error. The Actor checks every category before its first request.&lt;/p&gt;

&lt;p&gt;There is no free-text search input: backmarket.es's robots.txt disallows &lt;code&gt;*/search&lt;/code&gt;, so the Actor browses categories only.&lt;/p&gt;

&lt;p&gt;Each category page holds 31 models. &lt;code&gt;maxPages&lt;/code&gt; (1 to 33, default 33) bounds pages per category, and &lt;code&gt;maxItems&lt;/code&gt; (default 300) caps rows across all categories.&lt;/p&gt;

&lt;p&gt;Here is the setup. It reads one page of the iPhone category and saves at most 10 rows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&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="c1"&gt;# 1. Initialize ApifyClient with the token from the environment
&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="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;APIFY_API_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# 2. Define the category: one page, at most 10 rows
&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;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;https://www.backmarket.es/es-es/l/iphone/aabc736a-cb66-4ac0-a3b7-0f449781ed39&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;maxPages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maxItems&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No proxy setting exists: the Actor always fetches through Apify Unblocker, the one transport that reached the site in recon.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Add optional filters
&lt;/h2&gt;

&lt;p&gt;Back Market's own price, storage, model and colour controls write a URL fragment (&lt;code&gt;#price=600&amp;amp;price=900&lt;/code&gt;). A fragment never leaves the browser, and the query-string spelling of the same filters is ignored by the server. So the Actor sends only &lt;code&gt;?p=&amp;lt;n&amp;gt;&lt;/code&gt; and applies its filters to the rows it read:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;What it keeps&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;minPrice&lt;/code&gt; / &lt;code&gt;maxPrice&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;integer&lt;/td&gt;
&lt;td&gt;Rows whose starting price, in whole euros, is inside the bound.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;brands&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;array&lt;/td&gt;
&lt;td&gt;Rows whose brand matches, using the site's lowercase value such as &lt;code&gt;apple&lt;/code&gt; or &lt;code&gt;samsung&lt;/code&gt;, case-insensitive.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fetchProductDetails&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;boolean&lt;/td&gt;
&lt;td&gt;Not a filter: opens each model's product page for its variant price matrix. Off by default.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;code&gt;minPrice&lt;/code&gt; greater than &lt;code&gt;maxPrice&lt;/code&gt; stops the run with an error at its start. A negative price is refused before the run starts.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 4: Run the Actor
&lt;/h2&gt;

&lt;p&gt;Start the run with &lt;code&gt;.call()&lt;/code&gt;. It starts the Actor on Apify and waits for it to finish before returning the 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="c1"&gt;# 3. Start the Actor run and wait for it to finish
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Starting Back Market extraction...&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;reventadata/backmarket-scraper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SUCCEEDED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Run did not succeed (status: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;).&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 4. Fetch the saved models
&lt;/span&gt;&lt;span class="n"&gt;items&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;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;default_dataset_id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;list_items&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Retrieved &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; models.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behind the scenes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Actor builds the category URL with &lt;code&gt;?p=N&lt;/code&gt; and fetches each page through Apify Unblocker.&lt;/li&gt;
&lt;li&gt;It reads the models from the page's embedded &lt;code&gt;__NUXT_DATA__&lt;/code&gt; payload, keeps the 31 grid records and skips the recommendation carousel, applies your filters and saves the rows.&lt;/li&gt;
&lt;li&gt;It stops at &lt;code&gt;maxItems&lt;/code&gt;, at &lt;code&gt;maxPages&lt;/code&gt;, or once it has every model the site reports for the category.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 5: View and download results
&lt;/h2&gt;

&lt;p&gt;Loop over the rows to print the parts you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;|&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;grade&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  From &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; EUR, new &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;priceWhenNew&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; EUR&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;priceWhenNew&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;priceWhenNew&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; below the price new&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Rating &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rating&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; from &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ratingCount&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; reviews&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is one row, a sample from a capture dated 2026-09-18 (page 1 of the iPhone category) parsed with the Actor's own parser:&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5119391"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"iPhone 16"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url"&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://www.backmarket.es/es-es/p/iphone-16"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"iphone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"brand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"apple"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"productType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Smartphone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"iphone 16"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"variationId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0e3441cf-37af-429e-973f-218cb3c1fd63"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;584.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"priceWhenNew"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1009.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"isStartingFromPrice"&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;"rating"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;4.59&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ratingCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;14802&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"availableColors"&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;"Azul ultramar"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"Blanco"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"Negro"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"Rosa"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"Teal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"Ultramarine"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"Verde azulado"&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;"imageUrl"&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://d2e6ccujb3mkqf.cloudfront.net/2d99b692-a008-4345-8196-fea4cf5e4096-1_44974392-bda8-41f2-835b-2410a15bd88a.jpg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"grade"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Excelente"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"availableStock"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"warrantyMonths"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;24&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;Apify datasets export as JSON, CSV, XML, Excel, HTML table, RSS or JSONL.&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding your results
&lt;/h2&gt;

&lt;p&gt;The fields that matter most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;price&lt;/code&gt; and &lt;code&gt;isStartingFromPrice&lt;/code&gt;: the cheapest variant of the model, in EUR, not the price of one device. The real price depends on grade, battery, storage, colour and SIM. All 31 captured rows had &lt;code&gt;isStartingFromPrice: true&lt;/code&gt;, and starting prices ran from 81.99 (iPhone 7) to 1,180 (iPhone 17 Pro Max).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;priceWhenNew&lt;/code&gt;: what the site says the device cost new, taken from the card. In the capture, the starting price sat between 20% (iPhone 17 Pro Max) and 78% (iPhone 12) below it; that percentage is our arithmetic, not a site field.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;grade&lt;/code&gt;, &lt;code&gt;availableStock&lt;/code&gt;, &lt;code&gt;warrantyMonths&lt;/code&gt;: they describe the listing behind the starting price. Grades are the site's Spanish words: of 31 rows, 17 &lt;code&gt;Correcto&lt;/code&gt;, 8 &lt;code&gt;Muy bueno&lt;/code&gt;, 5 &lt;code&gt;Excelente&lt;/code&gt;, 1 &lt;code&gt;Prémium&lt;/code&gt;. All 31 had 24 months.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rating&lt;/code&gt;, &lt;code&gt;ratingCount&lt;/code&gt;: two decimals out of 5. 30 of 31 were rated, 4.07 to 4.68; iPhone 15 Pro showed 0 with 0 reviews.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;variationId&lt;/code&gt;: the priced listing's public UUID; it changes when another offer becomes the cheapest.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Pro tips
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use leaf categories.&lt;/strong&gt; The site serves at most 1,000 models per category: 32 pages of 31 plus a page of 8. Past that it shows &lt;code&gt;0 productos&lt;/code&gt;, even on &lt;code&gt;electronica&lt;/code&gt;, which reported 6,588 on page 1 (2026-09-18). The Actor stops at page 33 and logs the site's count, so for a large category, run its sub-categories.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch categories in one run.&lt;/strong&gt; Put several URLs in &lt;code&gt;categories&lt;/code&gt;. A model saved under one is not saved again under the next.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Turn on details only when you need them.&lt;/strong&gt; &lt;code&gt;fetchProductDetails&lt;/code&gt; adds &lt;code&gt;currentPrice&lt;/code&gt;, &lt;code&gt;grades&lt;/code&gt;, &lt;code&gt;batteryOptions&lt;/code&gt;, &lt;code&gt;storageOptions&lt;/code&gt;, &lt;code&gt;colorOptions&lt;/code&gt; and &lt;code&gt;simOptions&lt;/code&gt;, each option with a label, the site's value and a price, at one extra page request per model. A product page that fails keeps its listing row.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filters narrow what you receive, not what is read.&lt;/strong&gt; A tight &lt;code&gt;maxPrice&lt;/code&gt; on a large category still walks its pages; set &lt;code&gt;maxPages&lt;/code&gt; to bound it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start small.&lt;/strong&gt; Keep &lt;code&gt;maxPages: 1&lt;/code&gt; and &lt;code&gt;maxItems: 10&lt;/code&gt; until your code handles the fields.&lt;/li&gt;
&lt;/ol&gt;




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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero rows:&lt;/strong&gt; the status message names the reason. A page that failed or a category that could not be resolved ends the run FAILED. Rows rejected by your filters, or a category the site itself reports as &lt;code&gt;0 productos&lt;/code&gt;, end it SUCCEEDED with an empty dataset.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run stops at once:&lt;/strong&gt; a category is a slug without its UUID, or &lt;code&gt;minPrice&lt;/code&gt; is above &lt;code&gt;maxPrice&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fewer rows than expected:&lt;/strong&gt; read the end of the log. &lt;code&gt;Rejected N: ...&lt;/code&gt; lines count each filter's drops, and &lt;code&gt;Pushed N row(s).&lt;/code&gt; the saved rows. From Python: &lt;code&gt;client.log(run.id).get()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A large category stops at 1,000:&lt;/strong&gt; the site's window, not a fault. Use sub-categories.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For help, use the Actor's &lt;a href="https://apify.com/reventadata/backmarket-scraper" rel="noopener noreferrer"&gt;Store page&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pricing and next steps
&lt;/h2&gt;

&lt;p&gt;For current pricing and details, see the &lt;a href="https://apify.com/reventadata/backmarket-scraper" rel="noopener noreferrer"&gt;Store page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To track prices, save the input as a task and add an Apify schedule, which runs an Actor or task on a cron expression (&lt;code&gt;0 8 * * *&lt;/code&gt; is every day at 8 AM). To react when a run finishes, add a webhook on &lt;code&gt;ACTOR.RUN.SUCCEEDED&lt;/code&gt;; its payload carries the run object, including &lt;code&gt;defaultDatasetId&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://apify.com/reventadata/backmarket-scraper" rel="noopener noreferrer"&gt;Back Market Spain Scraper on Apify Store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.apify.com/api/client/python/docs" rel="noopener noreferrer"&gt;Apify Python client documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which refurbished categories are you planning to track on Back Market? Drop a comment! 💬&lt;/p&gt;

</description>
      <category>python</category>
      <category>webscraping</category>
      <category>apify</category>
      <category>automation</category>
    </item>
    <item>
      <title>How to Scrape Amazon Search Results with Python and an Apify Actor</title>
      <dc:creator>ReventaData</dc:creator>
      <pubDate>Mon, 02 Nov 2026 10:05:00 +0000</pubDate>
      <link>https://dev.to/reventadata/how-to-scrape-amazon-search-results-with-python-and-an-apify-actor-fhf</link>
      <guid>https://dev.to/reventadata/how-to-scrape-amazon-search-results-with-python-and-an-apify-actor-fhf</guid>
      <description>&lt;p&gt;By the end of this tutorial, you will have a short Python script that turns an Amazon search into structured JSON: one row per product with its ASIN, title, current price, strikethrough list price, discount percentage, star rating, review count, a Prime flag, a sponsored flag and a clean &lt;code&gt;/dp/&lt;/code&gt; link.&lt;/p&gt;

&lt;p&gt;We use the Apify Actor &lt;strong&gt;Amazon Product &amp;amp; Price Scraper&lt;/strong&gt; (&lt;code&gt;reventadata/amazon-scraper&lt;/code&gt;). It is for developers who track prices, compare products by rating, or watch what Amazon shows for a keyword, and would rather read rows than result cards. It covers 9 Amazon marketplaces: the US, UK, Germany, Spain, France, Italy, Canada, Japan and India.&lt;/p&gt;

&lt;p&gt;You will learn how to configure a search, run it from Python, read every field, and filter the results before they reach your dataset.&lt;/p&gt;

&lt;p&gt;⏱️ &lt;strong&gt;Time:&lt;/strong&gt; about 10 minutes for the setup.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;You need three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;An Apify account.&lt;/strong&gt; You can &lt;a href="https://console.apify.com/sign-up" rel="noopener noreferrer"&gt;sign up for free&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python 3.11 or newer&lt;/strong&gt;, which &lt;code&gt;apify-client&lt;/code&gt; requires.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your API token&lt;/strong&gt;, from the &lt;a href="https://console.apify.com/settings/integrations" rel="noopener noreferrer"&gt;Integrations settings page&lt;/a&gt; in Apify Console.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Install the client:&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; &lt;span class="s2"&gt;"apify-client~=3.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then keep the token in an environment variable, never in the script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;APIFY_API_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;your token&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No scraping code is required: the Actor handles fetching and parsing.&lt;/p&gt;




&lt;h2&gt;
  
  
  What you'll achieve
&lt;/h2&gt;

&lt;p&gt;You will get a dataset with one row per search result, for the keywords and marketplace you choose. Each row holds the fields printed on Amazon's result card: price in the marketplace's currency, list price when Amazon shows one crossed out, the discount computed from those two, rating, review count, Prime and sponsored flags, and the product image.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example use case:&lt;/strong&gt; you follow business laptops on amazon.com. You search &lt;code&gt;thinkpad&lt;/code&gt;, keep rows rated 4 stars or more, drop sponsored placements, and compare prices against list prices. That is the configuration this tutorial builds up.&lt;/p&gt;

&lt;p&gt;The sample rows below come from a capture of amazon.com page 1 for "thinkpad", dated 2026-10-22, read with the Actor's own parser. They are not from a run started for this post.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Access Amazon Product &amp;amp; Price Scraper
&lt;/h2&gt;

&lt;p&gt;Go to the &lt;a href="https://apify.com/reventadata/amazon-scraper" rel="noopener noreferrer"&gt;Amazon Product &amp;amp; Price Scraper&lt;/a&gt; page on Apify Store. If you prefer clicking to coding, Apify Console has the same fields in the Actor's &lt;strong&gt;Input&lt;/strong&gt; tab, and you press &lt;strong&gt;Start&lt;/strong&gt; there.&lt;/p&gt;

&lt;p&gt;In this tutorial we drive it from Python, so the same search is easy to repeat.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Configure the search
&lt;/h2&gt;

&lt;p&gt;The main input is &lt;code&gt;searchQueries&lt;/code&gt;: a list of keywords, each searched on its own. Pick the marketplace with &lt;code&gt;country&lt;/code&gt;, one of &lt;code&gt;US&lt;/code&gt;, &lt;code&gt;UK&lt;/code&gt;, &lt;code&gt;DE&lt;/code&gt;, &lt;code&gt;ES&lt;/code&gt;, &lt;code&gt;FR&lt;/code&gt;, &lt;code&gt;IT&lt;/code&gt;, &lt;code&gt;CA&lt;/code&gt;, &lt;code&gt;JP&lt;/code&gt; or &lt;code&gt;IN&lt;/code&gt;. Prices come back in that marketplace's currency: USD, GBP, EUR, CAD, JPY or INR.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;maxItems&lt;/code&gt; caps the saved rows across all your queries (20 by default). The Actor reads at most 7 result pages per query and stops earlier when a page is empty or has no next-page link.&lt;/p&gt;

&lt;p&gt;Here is the script. Its input is the Actor's own starting example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&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="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;APIFY_API_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_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;thinkpad&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;country&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;US&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maxItems&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sortBy&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;relevance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;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;reventadata/amazon-scraper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SUCCEEDED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Run did not succeed (status: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;default_dataset_id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;iterate_items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;asin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;|&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;currency&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;|&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rating&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;|&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][:&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; keywords work like Amazon's search box, but the Actor adds one check of its own: every word of your query must appear in the product title (case and accents ignored). On the captured "thinkpad" page, 20 of the 22 results passed. The two that did not were a "Lenovo 15.6 FHD Essential Laptop" and a sponsored MacBook.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Add sort order and filters
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;sortBy&lt;/code&gt; goes to Amazon in the search URL: &lt;code&gt;relevance&lt;/code&gt;, &lt;code&gt;price_low_to_high&lt;/code&gt;, &lt;code&gt;price_high_to_low&lt;/code&gt;, &lt;code&gt;review_rank&lt;/code&gt; or &lt;code&gt;newest&lt;/code&gt;. Because &lt;code&gt;country&lt;/code&gt; and &lt;code&gt;sortBy&lt;/code&gt; are fixed lists in the input schema, a misspelled value is refused before the run starts.&lt;/p&gt;

&lt;p&gt;The other filters run inside the Actor, after each page is read:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;minPrice&lt;/code&gt; / &lt;code&gt;maxPrice&lt;/code&gt;&lt;/strong&gt;: a price band in the marketplace currency. When either is set, rows without a price are dropped.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;minRating&lt;/code&gt;&lt;/strong&gt;: a whole number from 1 to 5. Unrated products are dropped when it is set.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;primeOnly&lt;/code&gt;&lt;/strong&gt;: keeps rows where &lt;code&gt;isPrime&lt;/code&gt; is true (see the next section for what that flag means).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;excludeSponsored&lt;/code&gt;&lt;/strong&gt;: drops results Amazon labels as sponsored.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the captured page, the 20 rows that passed the keyword check included 5 sponsored ones and 2 without a rating. So &lt;code&gt;excludeSponsored: true&lt;/code&gt; would keep 15 of them, and &lt;code&gt;minRating: 4&lt;/code&gt; would keep 18.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; filtered rows are never saved, and &lt;code&gt;maxItems&lt;/code&gt; counts only saved rows.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 4: Run the Actor
&lt;/h2&gt;

&lt;p&gt;Save the script as amazon_search.py and run it with &lt;code&gt;python amazon_search.py&lt;/code&gt;. &lt;code&gt;.call()&lt;/code&gt; starts the run on Apify and waits for it to finish; the script then checks the status and prints each row.&lt;/p&gt;

&lt;p&gt;Behind the scenes, the Actor builds Amazon's search URL for your keyword, marketplace, page and sort order, reads the result cards, applies your filters, and saves the rows that pass. It pauses one second between pages. A product that shows up under two of your keywords is saved once, matched by ASIN.&lt;/p&gt;

&lt;p&gt;For marketplaces outside the US and Canada, the Actor fetches pages through a web-unlocking service first. In our recon on 2026-10-17, amazon.de and amazon.es answered requests from US datacenter IPs with a captcha page.&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Tip:&lt;/strong&gt; in Console, the run's tabs include its log, which is where to look first if something goes wrong.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5: View and download results
&lt;/h2&gt;

&lt;p&gt;Each row prints in your terminal. In Console, the rows sit in the run's &lt;strong&gt;Output&lt;/strong&gt; tab, and &lt;strong&gt;Export&lt;/strong&gt; downloads them. Apify datasets export as JSON, CSV, XML, Excel, HTML table, RSS or JSONL.&lt;/p&gt;

&lt;p&gt;Here is a real row from the 2026-10-22 amazon.com capture, the third result on the page. I left out &lt;code&gt;scrapedAt&lt;/code&gt;, the time the page was read:&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;"asin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"B0HB8D3NQ3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Lenovo ThinkPad E16 Gen 3, 16GB DDR5 RAM, 512GB SSD, 500GB External HDD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1139.98&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"listPrice"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1749.99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"discountPercentage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rating"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;4.6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reviewsCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;343&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&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://www.amazon.com/dp/B0HB8D3NQ3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"image"&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://m.media-amazon.com/images/I/71GqQ5PQ+hL._AC_UY218_.jpg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"isPrime"&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;"isSponsored"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"country"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"US"&lt;/span&gt;&lt;span class="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;And a trimmed row from an amazon.in capture of the same date (page 2 for "pressure cooker"):&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;"asin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"B0843YY4QP"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3292.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"INR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"listPrice"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;4140.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"discountPercentage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rating"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;4.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reviewsCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1687&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"isPrime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"country"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IN"&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;h2&gt;
  
  
  Understanding your results
&lt;/h2&gt;

&lt;p&gt;Every row has the same 14 fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;asin&lt;/code&gt;: Amazon's 10-character product id, used to save each product once.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;title&lt;/code&gt;: the product name, with the brand joined on when the card prints it separately ("Lenovo ThinkPad T16, ...", not "Lenovo").&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;price&lt;/code&gt;, &lt;code&gt;currency&lt;/code&gt;: the current price as a number, in the marketplace currency.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;listPrice&lt;/code&gt;: the crossed-out price, or &lt;code&gt;null&lt;/code&gt; when the card shows none. On the captured page, 11 of 22 results had one. Check it is above &lt;code&gt;price&lt;/code&gt; before you use it: on the amazon.in capture, 5 of 48 rows carried a per-unit price (such as "/100 ml") here instead, and their &lt;code&gt;discountPercentage&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;discountPercentage&lt;/code&gt;: computed by the Actor from &lt;code&gt;price&lt;/code&gt; and &lt;code&gt;listPrice&lt;/code&gt;, rounded; &lt;code&gt;null&lt;/code&gt; unless the list price is higher. The captured page ran from 14 to 48 percent.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rating&lt;/code&gt;: stars out of 5, or &lt;code&gt;null&lt;/code&gt;. Two captured rows had none.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;reviewsCount&lt;/code&gt;: the exact count from Amazon's "N ratings" label; the India card above shows "(1.6K)", the row 1,687.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;url&lt;/code&gt;: a clean &lt;code&gt;https://www.&amp;lt;domain&amp;gt;/dp/&amp;lt;ASIN&amp;gt;&lt;/code&gt; link.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;image&lt;/code&gt;: the thumbnail URL.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;isPrime&lt;/code&gt;, &lt;code&gt;isSponsored&lt;/code&gt;: flags read from the card.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;country&lt;/code&gt;: the marketplace code.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;scrapedAt&lt;/code&gt;: an ISO 8601 UTC timestamp.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Pro tips and advanced usage
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Read &lt;code&gt;isPrime&lt;/code&gt; as "labelled Prime on this visit".&lt;/strong&gt; Logged-out pages no longer show a Prime badge; the Actor sets &lt;code&gt;isPrime&lt;/code&gt; when the card shows Amazon's "Join Prime to get FREE delivery" line. On the captured amazon.com page, 8 of 22 results had it. The Actor's schema notes that amazon.in showed no Prime line on 2026-10-22, so India rows are &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check ratings next to review counts.&lt;/strong&gt; Two captured ThinkPads had 5.0 stars, from 2 and 3 reviews. Sort on both columns, not one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch keywords in one run.&lt;/strong&gt; Put several phrases in &lt;code&gt;searchQueries&lt;/code&gt;; rows are de-duplicated by ASIN across them, and &lt;code&gt;maxItems&lt;/code&gt; caps the total.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Amazon's sort for depth.&lt;/strong&gt; With at most 7 pages per query, &lt;code&gt;price_low_to_high&lt;/code&gt; or &lt;code&gt;review_rank&lt;/code&gt; changes which products you reach.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skip the polling.&lt;/strong&gt; Attach a webhook for the &lt;code&gt;ACTOR.RUN.SUCCEEDED&lt;/code&gt; event. Its payload's &lt;code&gt;resource&lt;/code&gt; is "the response of the Get Actor run API endpoint" (&lt;a href="https://docs.apify.com/integrations/webhooks/actions" rel="noopener noreferrer"&gt;Apify docs&lt;/a&gt;), which carries &lt;code&gt;defaultDatasetId&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Troubleshooting common issues
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A run saved 0 rows (status message "0 results for ...").&lt;/strong&gt; A run that is blocked, cannot read a result page or finds a page without product cards ends FAILED. If the pages loaded with product cards but the filters rejected them all, it ends SUCCEEDED with an empty dataset. The log's summary line lists rejections by reason (&lt;code&gt;keyword_mismatch&lt;/code&gt;, &lt;code&gt;price_bounds&lt;/code&gt;, &lt;code&gt;rating_threshold&lt;/code&gt;, &lt;code&gt;prime_required&lt;/code&gt;, &lt;code&gt;sponsored_excluded&lt;/code&gt;, &lt;code&gt;duplicate&lt;/code&gt;), so you can see which filter removed everything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;primeOnly&lt;/code&gt; returns nothing.&lt;/strong&gt; Likely on amazon.in, where no Prime line was seen; turn it off there.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fewer rows than &lt;code&gt;maxItems&lt;/code&gt;.&lt;/strong&gt; The search ran out of pages (7 at most), or your filters dropped the rest. Each page logs how many cards it parsed and kept.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The run is refused at the start.&lt;/strong&gt; A &lt;code&gt;country&lt;/code&gt; or &lt;code&gt;sortBy&lt;/code&gt; value outside the schema's list never starts a run; the caller gets an error instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Questions?&lt;/strong&gt; Use the Actor's &lt;a href="https://apify.com/reventadata/amazon-scraper" rel="noopener noreferrer"&gt;Store page&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;For current pricing and details, see the &lt;a href="https://apify.com/reventadata/amazon-scraper" rel="noopener noreferrer"&gt;Store page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To repeat a search, save your input as a task and add a schedule; Apify schedules use cron expressions. To push rows into other tools, Apify integrates with n8n, Make and Zapier.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://apify.com/reventadata/amazon-scraper" rel="noopener noreferrer"&gt;Amazon Product &amp;amp; Price Scraper on Apify Store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.apify.com/api/client/python/docs" rel="noopener noreferrer"&gt;Apify Python client docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What are you planning to track on Amazon? Drop a comment! 💬&lt;/p&gt;

</description>
      <category>python</category>
      <category>webscraping</category>
      <category>apify</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Scrape AliExpress Search Results with Python</title>
      <dc:creator>ReventaData</dc:creator>
      <pubDate>Mon, 02 Nov 2026 10:04:34 +0000</pubDate>
      <link>https://dev.to/reventadata/how-to-scrape-aliexpress-search-results-with-python-18p8</link>
      <guid>https://dev.to/reventadata/how-to-scrape-aliexpress-search-results-with-python-18p8</guid>
      <description>&lt;p&gt;By the end of this tutorial, you will have a short Python script that turns AliExpress search results into structured JSON: one row per product with its id, title, canonical product URL, price, currency, star rating, units sold, image links and the shipping tag the card shows.&lt;/p&gt;

&lt;p&gt;We use the Apify Actor &lt;strong&gt;AliExpress Scraper&lt;/strong&gt; (&lt;code&gt;reventadata/aliexpress-scraper&lt;/code&gt;). It is for anyone who tracks prices on AliExpress, sizes up a product niche by units sold, or compares listings by rating, and would rather read rows than scroll result cards.&lt;/p&gt;

&lt;p&gt;⏱️ &lt;strong&gt;Time:&lt;/strong&gt; setting this up takes a few minutes: an account, a token and one script.&lt;/p&gt;

&lt;p&gt;You will learn how to configure the input, run the Actor from Python, read every field it returns, and avoid the filter traps that make a run come back empty.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A free &lt;strong&gt;Apify account&lt;/strong&gt; (&lt;a href="https://console.apify.com/sign-up" rel="noopener noreferrer"&gt;sign up for free&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Your &lt;strong&gt;Apify API token&lt;/strong&gt;, found at &lt;a href="https://console.apify.com/settings/integrations" rel="noopener noreferrer"&gt;console.apify.com/settings/integrations&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python 3.11 or newer&lt;/strong&gt;, which &lt;code&gt;apify-client&lt;/code&gt; requires.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install the client:&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; &lt;span class="s2"&gt;"apify-client~=3.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;No scraping code is needed: the Actor fetches the search pages, reads the cards and saves the rows. You send an input and read the results.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What you'll achieve
&lt;/h2&gt;

&lt;p&gt;You will send one or more search queries (for example &lt;code&gt;phone case&lt;/code&gt; or &lt;code&gt;mechanical keyboard&lt;/code&gt;) and receive one clean row per product card on the AliExpress search results. The Actor reads the search result cards only; it does not open product pages one by one.&lt;/p&gt;

&lt;p&gt;That keeps each row to what a card shows: title, price, rating, the sold count, images and a shipping tag. There is no seller profile, description or variant table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example use case:&lt;/strong&gt; you want the best-rated phone cases with real sales behind them. Set &lt;code&gt;minRating&lt;/code&gt; to &lt;code&gt;4.5&lt;/code&gt; and &lt;code&gt;minSold&lt;/code&gt; to &lt;code&gt;100&lt;/code&gt;, and the Actor keeps only cards that clear both bars.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Access AliExpress Scraper
&lt;/h2&gt;

&lt;p&gt;Open the &lt;a href="https://apify.com/reventadata/aliexpress-scraper" rel="noopener noreferrer"&gt;AliExpress Scraper&lt;/a&gt; page on Apify Store. In Apify Console, an Actor opens on its &lt;strong&gt;Input&lt;/strong&gt; tab, where you can fill the same fields this tutorial sets from code.&lt;/p&gt;

&lt;p&gt;We will run it from Python, so keep your API token at hand and export it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;APIFY_API_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;your token&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 2: Configure your queries and the caps
&lt;/h2&gt;

&lt;p&gt;The one required field is &lt;code&gt;searchQueries&lt;/code&gt;: a list of search terms. For each query the Actor builds an AliExpress search URL and walks its pages. For the prefill query &lt;code&gt;phone case&lt;/code&gt;, page 1 is:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://www.aliexpress.com/w/wholesale-phone-case.html?page=1&amp;amp;SearchText=phone+case&amp;amp;shipTo=US&amp;amp;currency=USD&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here is the script. Its input is the Actor's own prefill: one query, 5 rows, one page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&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="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;APIFY_API_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_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;phone case&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;maxItems&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maxPages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;country&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;US&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;currency&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;USD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;proxyConfiguration&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;useApifyProxy&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;apifyProxyGroups&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;UNBLOCKER&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="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;reventadata/aliexpress-scraper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SUCCEEDED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Run did not succeed (status: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;default_dataset_id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;iterate_items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;|&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][:&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;|&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;currency&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;|&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rating&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;|&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;soldCount&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;&lt;code&gt;maxItems&lt;/code&gt; is the total number of rows to save across all queries. &lt;code&gt;maxPages&lt;/code&gt; caps the pages walked per query. Without them, the defaults are 60 and 5.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Add filters
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;country&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;&lt;code&gt;US&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sent to AliExpress as &lt;code&gt;shipTo&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;currency&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;&lt;code&gt;USD&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sent to AliExpress as &lt;code&gt;currency&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;minPrice&lt;/code&gt;, &lt;code&gt;maxPrice&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;number&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;td&gt;Price band. A card with no readable price is dropped when either is set.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;minRating&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;number&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;td&gt;Minimum star rating, 0 to 5. Unrated cards are dropped when set.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;minSold&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;integer&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;td&gt;Minimum units sold. Cards without a sold count are dropped when set.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;proxyConfiguration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;object&lt;/td&gt;
&lt;td&gt;Unblocker&lt;/td&gt;
&lt;td&gt;Apify Unblocker proxy by default.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three details worth knowing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The filters run on the cards the Actor reads&lt;/strong&gt;, after each page is fetched. A tight &lt;code&gt;minSold&lt;/code&gt; can leave a page with few kept rows, so raise &lt;code&gt;maxPages&lt;/code&gt; when you filter hard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every word of a query must appear in the title&lt;/strong&gt;, ignoring case and accents. That is how the Actor drops the unrelated recommendation cards AliExpress shows when nothing matches a query.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessory and damaged listings are dropped.&lt;/strong&gt; Titles with words like case, cover, cable, strap or holder are treated as accessories, unless your query itself contains case, cover, protector, cable, strap or tip. Titles admitting damage (broken, faulty, cracked, for parts, not working) are dropped too, but a negation such as "anti scratch" keeps the row.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 4: Run the Actor
&lt;/h2&gt;

&lt;p&gt;Run the script with &lt;code&gt;python aliexpress.py&lt;/code&gt;. &lt;code&gt;.call()&lt;/code&gt; starts the Actor on Apify and waits until it finishes. Behind the scenes the Actor requests each search page (through Apify's Unblocker proxy, unless you change &lt;code&gt;proxyConfiguration&lt;/code&gt;), reads the result cards, applies your filters and saves the rows. A product that shows up under two of your queries is saved once.&lt;/p&gt;

&lt;p&gt;A query stops at the first page with no cards, or when you reach &lt;code&gt;maxPages&lt;/code&gt;. Rows stop being saved at &lt;code&gt;maxItems&lt;/code&gt;: the current query may still read its remaining pages, and later queries are skipped.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Tip:&lt;/strong&gt; &lt;code&gt;.call()&lt;/code&gt; blocks until the run ends. To fire and forget, use a webhook instead (see the pro tips below).&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 5: View and download results
&lt;/h2&gt;

&lt;p&gt;The script prints one line per row. In Apify Console, results appear in the run's &lt;strong&gt;Output&lt;/strong&gt; tab, and &lt;strong&gt;Export&lt;/strong&gt; downloads them. Datasets export as JSON, CSV, XML, Excel, HTML table, RSS or JSONL.&lt;/p&gt;

&lt;p&gt;Here is a sample row, a sample from a capture dated 2026-10-16: one search card saved from the Spanish storefront in a browser and parsed with the Actor's own row builder. It is not output of the prefill input above, which is why the price is in euros. &lt;code&gt;matchedKeyword&lt;/code&gt; and &lt;code&gt;scrapedAt&lt;/code&gt; are left out:&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1005010497678198"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Auriculares Inalámbricos Bluetooth 5.3 HiFi Estéreo Resistente al Sudor Cascos Calgante Deportivo TEISCHE SW-08"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&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://www.aliexpress.com/item/1005010497678198.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;7.71&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"originalPrice"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"discountPercent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rating"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;4.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"soldCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;38&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"soldText"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"38 vendidos"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"thumbnailUrl"&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://ae-pic-a1.aliexpress-media.com/kf/E8a248d80dbf340dfa7bb04ad6b8d07a0h.jpg_480x480q75.jpg_.avif"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"galleryImages"&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://ae-pic-a1.aliexpress-media.com/kf/E8a248d80dbf340dfa7bb04ad6b8d07a0h.jpg_480x480q75.jpg_.avif"&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://ae-pic-a1.aliexpress-media.com/kf/Eb36c445f517d42efa7b4f1b916048f2ef.jpg_480x480q75.jpg_.avif"&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://ae-pic-a1.aliexpress-media.com/kf/E95a75f15f62543ccbbd8d0aba4ee4293s.jpg_480x480q75.jpg_.avif"&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://ae-pic-a1.aliexpress-media.com/kf/E34099cc5d0ee42f59a3a636328810addc.jpg_480x480q75.jpg_.avif"&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://ae-pic-a1.aliexpress-media.com/kf/E8c10f199c77049a0a5cb4fa099b304efF.jpg_480x480q75.jpg_.avif"&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;"shippingDisplay"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Envío gratis a partir de 10,9€"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"isFreeShipping"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Understanding your results
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;id&lt;/code&gt; is the AliExpress product id, and &lt;code&gt;url&lt;/code&gt; is rebuilt from it as &lt;code&gt;https://www.aliexpress.com/item/&amp;lt;id&amp;gt;.html&lt;/code&gt;, with the long query string of the card link dropped.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;price&lt;/code&gt; is the price shown on the card, as a number. &lt;code&gt;currency&lt;/code&gt; is read from the card when it shows a euro, pound or dollar sign or code, else it is the currency you asked for.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;originalPrice&lt;/code&gt; and &lt;code&gt;discountPercent&lt;/code&gt; are null in every row of the current version, so do not build a discount report on them yet.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;soldCount&lt;/code&gt; is the digits of &lt;code&gt;soldText&lt;/code&gt;: "38 vendidos" becomes 38, and a text like "1,000+ sold" becomes 1000, a floor rather than an exact count.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;isFreeShipping&lt;/code&gt; is true only when the tag says plain "Free shipping" (or "Envío gratis"). A conditional tag, like the "free shipping from 10,9€" one above, stays in &lt;code&gt;shippingDisplay&lt;/code&gt; and leaves the flag false.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;galleryImages&lt;/code&gt; holds up to 5 image links from the card.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;matchedKeyword&lt;/code&gt; is the query that kept the row; &lt;code&gt;scrapedAt&lt;/code&gt; is when it was saved.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Pro tips and advanced usage
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Write queries in the words of the titles.&lt;/strong&gt; The sample card's title is Spanish, so &lt;code&gt;wireless earbuds&lt;/code&gt; would not keep it, while &lt;code&gt;auriculares inalambricos&lt;/code&gt; would: every query word must be in the title.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;minSold&lt;/code&gt; to skip untested listings.&lt;/strong&gt; Cards without a sold count are dropped when it is set, so you only get products with sales on display.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Put several queries in one run.&lt;/strong&gt; &lt;code&gt;searchQueries&lt;/code&gt; takes a list, and a product found by two of them is saved once.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hook it to your pipeline.&lt;/strong&gt; An Apify webhook fires when a run finishes; its &lt;code&gt;resource&lt;/code&gt; is "the response of the Get Actor run API endpoint" (&lt;a href="https://docs.apify.com/integrations/webhooks/actions" rel="noopener noreferrer"&gt;docs.apify.com/integrations/webhooks/actions&lt;/a&gt;), which carries &lt;code&gt;defaultDatasetId&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check &lt;code&gt;currency&lt;/code&gt; in your own rows.&lt;/strong&gt; The Actor sends &lt;code&gt;country&lt;/code&gt; and &lt;code&gt;currency&lt;/code&gt; to AliExpress, and it takes the row's &lt;code&gt;currency&lt;/code&gt; from the card when the card shows one, so read it from the rows rather than assuming it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For current pricing and details, see the &lt;a href="https://apify.com/reventadata/aliexpress-scraper" rel="noopener noreferrer"&gt;Store page&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Troubleshooting common issues
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"0 results for queries ...".&lt;/strong&gt; A blocked page or a page without cards ends the run FAILED; when pages loaded but nothing passed, it ends SUCCEEDED with an empty dataset. Usually a query word is missing from the titles, or &lt;code&gt;minRating&lt;/code&gt;, &lt;code&gt;minSold&lt;/code&gt; or the price band dropped every card. Loosen one at a time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fewer rows than &lt;code&gt;maxItems&lt;/code&gt;.&lt;/strong&gt; The filters dropped cards and &lt;code&gt;maxPages&lt;/code&gt; ran out first. Raise &lt;code&gt;maxPages&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nothing happens and the log says "No searchQueries provided in input."&lt;/strong&gt; The query list is empty; add at least one query.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An input rejected at start.&lt;/strong&gt; &lt;code&gt;maxItems&lt;/code&gt; and &lt;code&gt;maxPages&lt;/code&gt; must be at least 1, the price and sold filters 0 or more, and &lt;code&gt;minRating&lt;/code&gt; between 0 and 5; an input outside the schema is refused before the run starts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The run's log shows each page fetched and how many cards were parsed and kept on it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;Save your input as an Apify task and add a schedule: schedules use cron expressions, so a daily price check is one line (&lt;a href="https://docs.apify.com/actors/running/schedules" rel="noopener noreferrer"&gt;docs.apify.com/actors/running/schedules&lt;/a&gt;). The &lt;a href="https://docs.apify.com/api/client/python/docs" rel="noopener noreferrer"&gt;Apify Python client docs&lt;/a&gt; cover the rest of the API. Start with the prefill input above and grow from there.&lt;/p&gt;

&lt;p&gt;What are you planning to scrape on AliExpress? Drop a comment! 💬&lt;/p&gt;

</description>
      <category>python</category>
      <category>webscraping</category>
      <category>apify</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Scrape Instagram Posts and Profile Stats with Python and Apify</title>
      <dc:creator>ReventaData</dc:creator>
      <pubDate>Mon, 02 Nov 2026 10:03:44 +0000</pubDate>
      <link>https://dev.to/reventadata/how-to-scrape-instagram-posts-and-profile-stats-with-python-and-apify-48mc</link>
      <guid>https://dev.to/reventadata/how-to-scrape-instagram-posts-and-profile-stats-with-python-and-apify-48mc</guid>
      <description>&lt;p&gt;By the end of this tutorial, you will have a short Python script that turns public Instagram usernames and post links into structured rows: caption, like and comment counts, image link and date for each post, plus follower, following and post counts for each profile.&lt;/p&gt;

&lt;p&gt;We use two Apify Actors that share one input style: &lt;strong&gt;Instagram Posts &amp;amp; Engagement Scraper&lt;/strong&gt; (&lt;code&gt;reventadata/instagram-scraper&lt;/code&gt;) for posts, and &lt;strong&gt;Instagram Profile &amp;amp; Followers Scraper&lt;/strong&gt; (&lt;code&gt;reventadata/instagram-profile-scraper&lt;/code&gt;) for profile stats. Both read the public pages a logged-out browser sees and send no login.&lt;/p&gt;

&lt;p&gt;The two sample rows below are a sample from a capture dated 2026-10-22 (a National Geographic post) and a sample from a capture dated 2026-10-17 (the &lt;code&gt;@instagram&lt;/code&gt; profile), parsed with each Actor's own parser.&lt;/p&gt;

&lt;p&gt;⏱️ &lt;strong&gt;Time estimate:&lt;/strong&gt; one sitting: install one package, set one token, run two short Python blocks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To follow this tutorial, you will need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Python 3.11+&lt;/strong&gt; (&lt;code&gt;apify-client&lt;/code&gt; 3.3.0 requires it).&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Apify API client&lt;/strong&gt; for Python.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;Apify account&lt;/strong&gt; and its API token, which sits on the &lt;strong&gt;API &amp;amp; Integrations&lt;/strong&gt; page in Apify Console.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Install the client:&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; &lt;span class="s2"&gt;"apify-client~=3.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code reads the token from an environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;APIFY_API_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your_apify_token_here"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What you'll achieve
&lt;/h2&gt;

&lt;p&gt;You will get two datasets from one script:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Posts:&lt;/strong&gt; one row per post with &lt;code&gt;id&lt;/code&gt; (the shortcode), &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;caption&lt;/code&gt;, &lt;code&gt;likesCount&lt;/code&gt;, &lt;code&gt;commentsCount&lt;/code&gt;, &lt;code&gt;imageUrl&lt;/code&gt;, &lt;code&gt;author&lt;/code&gt; (the account's display name) and &lt;code&gt;timestamp&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Profiles:&lt;/strong&gt; one row per username with &lt;code&gt;username&lt;/code&gt;, &lt;code&gt;fullName&lt;/code&gt;, &lt;code&gt;biography&lt;/code&gt;, &lt;code&gt;followersCount&lt;/code&gt;, &lt;code&gt;followingCount&lt;/code&gt;, &lt;code&gt;postsCount&lt;/code&gt;, &lt;code&gt;avatarUrl&lt;/code&gt; and &lt;code&gt;url&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Both Actors are unofficial and not affiliated with Instagram or Meta. They do not read comments, follower lists or private accounts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Example use case:&lt;/strong&gt; Suppose you track a handful of brand or creator accounts. The profile Actor gives you each account's follower and post counts in one row; the posts Actor gives you the captions and engagement of each account's newest posts. Join them on the username and you have a small engagement table you can refresh on a schedule.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Access the two Actors
&lt;/h2&gt;

&lt;p&gt;Go to the &lt;a href="https://apify.com/reventadata/instagram-scraper" rel="noopener noreferrer"&gt;Instagram Posts &amp;amp; Engagement Scraper&lt;/a&gt; and the &lt;a href="https://apify.com/reventadata/instagram-profile-scraper" rel="noopener noreferrer"&gt;Instagram Profile &amp;amp; Followers Scraper&lt;/a&gt; pages on Apify Store. Each README lists every input and output field. In this tutorial we drive both Actors from Python, so everything after this step happens in code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Configure the inputs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Posts Actor.&lt;/strong&gt; It takes two kinds of target, and you can mix them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;directUrls&lt;/code&gt;: post or reel links such as &lt;code&gt;https://www.instagram.com/p/DeuOR-CjKE9/&lt;/code&gt;. A link without &lt;code&gt;/p/&lt;/code&gt; or &lt;code&gt;/reel/&lt;/code&gt; is read as a profile page.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;usernames&lt;/code&gt;: public usernames such as &lt;code&gt;natgeo&lt;/code&gt; (a leading &lt;code&gt;@&lt;/code&gt; is stripped). For each one the Actor opens the profile page and saves the newest posts it lists. Per the README, that was 12 per profile when checked on 2026-10-22; older posts are not reached.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Profile Actor.&lt;/strong&gt; It takes &lt;code&gt;usernames&lt;/code&gt; only. A handle, an &lt;code&gt;@handle&lt;/code&gt; or a full profile URL all work: &lt;code&gt;@natgeo&lt;/code&gt; and &lt;code&gt;https://www.instagram.com/natgeo/&lt;/code&gt; both become &lt;code&gt;natgeo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Both Actors have &lt;code&gt;maxItems&lt;/code&gt; (1 to 5,000, default 20), which caps the rows saved in the run. A value outside that range is refused before the run starts.&lt;/p&gt;

&lt;p&gt;Here is the setup. It defines one helper that runs an Actor and returns its rows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&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="c1"&gt;# 1. Initialize ApifyClient with the token from the environment
&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="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;APIFY_API_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# 2. Run an Actor, wait for it, and return its dataset rows
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_actor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;actor_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;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="n"&gt;actor_id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SUCCEEDED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;actor_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; did not succeed (status: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;).&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;default_dataset_id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;list_items&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; start with &lt;code&gt;maxItems: 5&lt;/code&gt;, the value both input forms prefill, until your downstream code handles the fields.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Add the optional filter and proxy
&lt;/h2&gt;

&lt;p&gt;The profile Actor has one filter: &lt;code&gt;minFollowers&lt;/code&gt;. Profiles below it are dropped before they are saved, and so is a profile whose follower count could not be read.&lt;/p&gt;

&lt;p&gt;Both Actors take &lt;code&gt;proxyConfiguration&lt;/code&gt;. Leave it out: when none is given, they fetch through Apify Unblocker (proxy group &lt;code&gt;UNBLOCKER&lt;/code&gt;).&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Actor&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;directUrls&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;posts&lt;/td&gt;
&lt;td&gt;Post, reel or profile links.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;usernames&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;Profiles to read (posts: newest listed posts; profiles: one row each).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxItems&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;Rows saved at most, 1 to 5,000.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;minFollowers&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;profiles&lt;/td&gt;
&lt;td&gt;Drop profiles with fewer followers.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;proxyConfiguration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;Apify proxy settings; Unblocker when unset.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Step 4: Run the Actors
&lt;/h2&gt;

&lt;p&gt;Now call the helper once per Actor. Each &lt;code&gt;call()&lt;/code&gt; starts the Actor on Apify and waits for it to finish before returning the 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="c1"&gt;# 3. Newest posts of one profile, at most 5 rows
&lt;/span&gt;&lt;span class="n"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;run_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;reventadata/instagram-scraper&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;usernames&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;natgeo&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;maxItems&lt;/span&gt;&lt;span class="sh"&gt;"&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="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 4. Profile stats, one row per username
&lt;/span&gt;&lt;span class="n"&gt;profiles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;run_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;reventadata/instagram-profile-scraper&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;usernames&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;instagram&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;natgeo&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;maxItems&lt;/span&gt;&lt;span class="sh"&gt;"&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="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;profiles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;username&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;followersCount&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; followers, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;postsCount&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; posts&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;post&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; | &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;likesCount&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; likes | &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behind the scenes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For a username, the posts Actor reads the profile page, takes the post codes it lists, then opens each post page and reads its caption, counts and image.&lt;/li&gt;
&lt;li&gt;A post or profile already saved in the run is not saved twice.&lt;/li&gt;
&lt;li&gt;Each Actor stops at &lt;code&gt;maxItems&lt;/code&gt; or when it runs out of targets.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 5: View and download results
&lt;/h2&gt;

&lt;p&gt;Here is one post row, a sample from a capture dated 2026-10-22, parsed with the posts Actor's own parser (image link shortened). A saved row also carries &lt;code&gt;scrapedAt&lt;/code&gt;, added at save time:&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DeuOR-CjKE9"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url"&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://www.instagram.com/p/DeuOR-CjKE9/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"caption"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Some of the best reasons to travel in 2027 are far from the usual destinations. 🌎&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;National Geographic’s picks for Best of the World 2027 are here and features 25 destinations across six continents. &lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;Whether you're drawn to places steeped in history or the thrill of exploring the wild, there's no shortage of experiences worth planning a trip around. &lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;Find your next adventure and see our full #BestOfTheWorld 2027 guide at the link in bio. &lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;Photograph by Thomas Ekström"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"likesCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"commentsCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;147&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"imageUrl"&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://scontent.cdninstagram.com/v/t51.82787-15/858921974_18710195065019133_277441153414192961_n.jpg?stp=c216.0.648.648a_dst-jpg_e35_s640x640_tt6&amp;amp;..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"National Geographic"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"October 20, 2026"&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;And one profile row, a sample from a capture dated 2026-10-17, parsed with the profile Actor's own parser (the avatar link is a stand-in from the test capture):&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"instagram"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"instagram"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"fullName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Instagram"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"biography"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Discover what's new on Instagram 🔎✨"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"followersCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;687000000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"followingCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;308&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"postsCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8620&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"avatarUrl"&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://scontent.cdninstagram.com/v/avatar.jpg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url"&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://www.instagram.com/instagram/"&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;Apify datasets export as JSON, CSV, XML, Excel, HTML table, RSS or JSONL.&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding your results
&lt;/h2&gt;

&lt;p&gt;The fields that matter most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;likesCount&lt;/code&gt;, &lt;code&gt;commentsCount&lt;/code&gt;: integers, rounded the way Instagram shows them. The captured post's page said &lt;code&gt;12K likes, 147 comments&lt;/code&gt;, so the row holds &lt;code&gt;12000&lt;/code&gt; and &lt;code&gt;147&lt;/code&gt;. Treat values in the thousands as approximate.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;followersCount&lt;/code&gt;, &lt;code&gt;followingCount&lt;/code&gt;, &lt;code&gt;postsCount&lt;/code&gt;: same rule. &lt;code&gt;687M&lt;/code&gt; followers became &lt;code&gt;687000000&lt;/code&gt;; &lt;code&gt;8,620&lt;/code&gt; posts became &lt;code&gt;8620&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;timestamp&lt;/code&gt;: the post date as Instagram writes it (&lt;code&gt;October 20, 2026&lt;/code&gt;), not an ISO timestamp. Parse it yourself if you need a date type.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;author&lt;/code&gt;: the display name (&lt;code&gt;National Geographic&lt;/code&gt;), not the handle. The handle is the username you passed in.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;caption&lt;/code&gt;: the full caption, line breaks kept as &lt;code&gt;\n&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;imageUrl&lt;/code&gt;, &lt;code&gt;avatarUrl&lt;/code&gt;: Instagram CDN links. They expire, so download the image soon if you need it.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;url&lt;/code&gt;: posts always come back as &lt;code&gt;/p/&amp;lt;shortcode&amp;gt;/&lt;/code&gt;, reels included; profiles as &lt;code&gt;https://www.instagram.com/&amp;lt;username&amp;gt;/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fullName&lt;/code&gt;: falls back to the username when the page shows no name, so a name equal to the handle may mean no name was shown.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Pro tips
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Mix links and usernames in one posts run.&lt;/strong&gt; Put specific post links in &lt;code&gt;directUrls&lt;/code&gt; and accounts in &lt;code&gt;usernames&lt;/code&gt;; duplicates are saved once.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use the profile Actor as a pre-filter.&lt;/strong&gt; Run it with &lt;code&gt;minFollowers&lt;/code&gt; on a long list of candidates, then pass only the usernames that came back to the posts Actor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expect the newest posts only.&lt;/strong&gt; A username yields the posts its profile page lists, not the full history. For an older post, pass its link in &lt;code&gt;directUrls&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Normalise the date column.&lt;/strong&gt; &lt;code&gt;timestamp&lt;/code&gt; is text such as &lt;code&gt;October 20, 2026&lt;/code&gt;; convert it with &lt;code&gt;datetime.strptime(value, "%B %d, %Y")&lt;/code&gt; before sorting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read rows with &lt;code&gt;iterate_items()&lt;/code&gt; for big runs.&lt;/strong&gt; &lt;code&gt;list_items()&lt;/code&gt; makes one API call; &lt;code&gt;iterate_items()&lt;/code&gt; pages through every row.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Give each integration its own token.&lt;/strong&gt; Apify's API docs advise a token with a clear description per service, never one token shared across several, the same way you would not reuse one password for different accounts.&lt;/li&gt;
&lt;/ol&gt;




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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Run FAILED with zero rows:&lt;/strong&gt; both Actors fail a run when a page is blocked or cannot be read (a typo in a username, a login wall), and the posts Actor also fails when no input is given (the profiles Actor ends SUCCEEDED with no rows); an over-strict &lt;code&gt;minFollowers&lt;/code&gt; on profiles that loaded ends SUCCEEDED with an empty dataset and a status message saying so.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fewer posts than &lt;code&gt;maxItems&lt;/code&gt;:&lt;/strong&gt; a username yields only the posts its profile page lists. A profile page with no post list is skipped with a warning in the log.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check the log:&lt;/strong&gt; a summary line near the end reads &lt;code&gt;Run finished: pushed N records to dataset.&lt;/code&gt; From Python: &lt;code&gt;client.log(run.id).get()&lt;/code&gt;, with &lt;code&gt;run&lt;/code&gt; from &lt;code&gt;call()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For help, use the Actor's &lt;a href="https://apify.com/reventadata/instagram-scraper" rel="noopener noreferrer"&gt;Store page&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pricing and next steps
&lt;/h2&gt;

&lt;p&gt;For current pricing and details, see the &lt;a href="https://apify.com/reventadata/instagram-scraper" rel="noopener noreferrer"&gt;Store page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To refresh the table, save each input as a task and add an Apify schedule, which runs an Actor or task on a cron expression (&lt;code&gt;0 8 * * *&lt;/code&gt; is every day at 8 AM). To react when a run finishes, add a webhook on &lt;code&gt;ACTOR.RUN.SUCCEEDED&lt;/code&gt;; its payload carries the run object, including &lt;code&gt;defaultDatasetId&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://apify.com/reventadata/instagram-scraper" rel="noopener noreferrer"&gt;Instagram Posts &amp;amp; Engagement Scraper on Apify Store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apify.com/reventadata/instagram-profile-scraper" rel="noopener noreferrer"&gt;Instagram Profile &amp;amp; Followers Scraper on Apify Store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.apify.com/api/client/python/docs" rel="noopener noreferrer"&gt;Apify Python client documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which accounts are you planning to track? Drop a comment! 💬&lt;/p&gt;

</description>
      <category>python</category>
      <category>webscraping</category>
      <category>apify</category>
      <category>automation</category>
    </item>
    <item>
      <title>How to Scrape Freshmile EV Charging Stations and Tariffs with Python</title>
      <dc:creator>ReventaData</dc:creator>
      <pubDate>Mon, 02 Nov 2026 08:58:58 +0000</pubDate>
      <link>https://dev.to/reventadata/how-to-scrape-freshmile-ev-charging-stations-and-tariffs-with-python-7kp</link>
      <guid>https://dev.to/reventadata/how-to-scrape-freshmile-ev-charging-stations-and-tariffs-with-python-7kp</guid>
      <description>&lt;p&gt;By the end of this tutorial, you will have a short Python script that turns a map box into structured rows of EV charging stations on the Freshmile network: name, address, coordinates, live availability, connector types, power in kW and each connector's tariff as Freshmile publishes it.&lt;/p&gt;

&lt;p&gt;There is no HTML to parse. The Actor reads Freshmile's public JSON map API, which answered with no key, token or login when it was measured on 2026-09-22, and calls it directly, with no proxy by default.&lt;/p&gt;

&lt;p&gt;In this guide, we use Python and the Apify Actor &lt;strong&gt;Freshmile Scraper&lt;/strong&gt; (&lt;code&gt;reventadata/freshmile-scraper&lt;/code&gt;). You will set a search box, run the Actor and read the rows. The sample row below is a sample from a capture dated 2026-09-22, parsed with the Actor's own parser.&lt;/p&gt;

&lt;p&gt;⏱️ &lt;strong&gt;Time estimate:&lt;/strong&gt; one sitting: install one package, set one token, run three short Python blocks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To follow this tutorial, you will need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Python 3.11+&lt;/strong&gt; (&lt;code&gt;apify-client&lt;/code&gt; 3.3.0 requires it).&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Apify API client&lt;/strong&gt; for Python.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;Apify account&lt;/strong&gt; and its API token, which sits on the &lt;strong&gt;API &amp;amp; Integrations&lt;/strong&gt; page in Apify Console.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Install the client:&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; &lt;span class="s2"&gt;"apify-client~=3.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code reads the token from an environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;APIFY_API_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your_apify_token_here"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What you'll achieve
&lt;/h2&gt;

&lt;p&gt;You will turn a bounding box (four map edges in decimal degrees) into one row per charging station. Each row carries the station &lt;code&gt;id&lt;/code&gt; (Freshmile's station ref) and &lt;code&gt;locationId&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;address&lt;/code&gt;, &lt;code&gt;city&lt;/code&gt;, &lt;code&gt;postalCode&lt;/code&gt;, &lt;code&gt;country&lt;/code&gt;, &lt;code&gt;latitude&lt;/code&gt; and &lt;code&gt;longitude&lt;/code&gt;, the &lt;code&gt;isAvailable&lt;/code&gt; flag, &lt;code&gt;evseCount&lt;/code&gt; (EVSEs, the charging points), &lt;code&gt;connectorCount&lt;/code&gt;, &lt;code&gt;maxPowerKw&lt;/code&gt;, and a &lt;code&gt;connectors&lt;/code&gt; list with each connector's power, standard and tariff.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The Actor reads station data only. Its rows carry no user fields and no map preview image link (the site's preview link embeds a third-party key, so it is left out).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Example use case:&lt;/strong&gt; Suppose you want every Freshmile station around one Paris street with its connector mix and tariff text, to compare charging prices. You draw a tight box around the street, keep &lt;code&gt;fetchDetails&lt;/code&gt; on, and each saved row carries its connectors with the tariff wording Freshmile shows.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Access Freshmile Scraper
&lt;/h2&gt;

&lt;p&gt;Go to the &lt;a href="https://apify.com/reventadata/freshmile-scraper" rel="noopener noreferrer"&gt;Freshmile Scraper&lt;/a&gt; page on Apify Store. The README lists every input and output field. In this tutorial we drive the Actor from Python, so everything after this step happens in code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Configure the search box
&lt;/h2&gt;

&lt;p&gt;The main input is the box: &lt;code&gt;bboxWest&lt;/code&gt;, &lt;code&gt;bboxSouth&lt;/code&gt;, &lt;code&gt;bboxEast&lt;/code&gt; and &lt;code&gt;bboxNorth&lt;/code&gt;, in WGS84 decimal degrees (the longitude and latitude any web map shows). All four are required. West must be smaller than east, and south smaller than north.&lt;/p&gt;

&lt;p&gt;Two caps control the size of the run:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;zoom&lt;/code&gt;: the zoom hint sent with the box (0 to 22, default 18).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;maxItems&lt;/code&gt;: the most stations the run processes (default 100).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the setup. It searches a small box in central Paris, the same box the Actor's input form is prefilled with, and processes at most 10 stations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&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="c1"&gt;# 1. Initialize ApifyClient with the token from the environment
&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="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;APIFY_API_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# 2. Define the search box (Paris, around Rue Pierre Charron) and the caps
&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;bboxWest&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2.303&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bboxSouth&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;48.869&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bboxEast&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2.3045&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bboxNorth&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;48.8705&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;zoom&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maxItems&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fetchDetails&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; keep the box tight. Freshmile groups stations into clusters by box size and density, not by zoom alone: on 2026-09-22 a tight Paris box at zoom 15 or 18 returned single stations, while a wide box over the same area (&lt;code&gt;2.0,48.5,2.7,49.0&lt;/code&gt;) at zoom 20 returned 11 clusters and no single station.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Choose how much detail you need
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;fetchDetails&lt;/code&gt; (default &lt;code&gt;true&lt;/code&gt;) decides what each row holds:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;fetchDetails&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;What the Actor does&lt;/th&gt;
&lt;th&gt;What you get&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Calls each station's detail endpoint&lt;/td&gt;
&lt;td&gt;Name, address, EVSEs, every connector with power, standard and tariff&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Keeps the search result only&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;id&lt;/code&gt;, &lt;code&gt;locationId&lt;/code&gt;, coordinates, &lt;code&gt;isAvailable&lt;/code&gt;, &lt;code&gt;isOpen&lt;/code&gt;, &lt;code&gt;evseCount&lt;/code&gt;; name, address and connectors stay empty&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Turn it off when you only need positions and availability: the run skips one detail request per station.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;proxyConfiguration&lt;/code&gt; is optional and off by default. The input form says it plainly: the API answers direct calls; enable a proxy only if direct calls are refused.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ A box edge outside the valid range (longitude -180 to 180, latitude -90 to 90) or a missing edge is refused before the run starts. A box with west not smaller than east, or south not smaller than north, stops the run with an error at its start.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 4: Run the Actor
&lt;/h2&gt;

&lt;p&gt;Now start the run with &lt;code&gt;client.actor("reventadata/freshmile-scraper").call(run_input=run_input)&lt;/code&gt;. The call starts the Actor on Apify and waits for it to finish before returning the 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="c1"&gt;# 3. Start the Actor run and wait for it to finish
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Starting Freshmile extraction...&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;reventadata/freshmile-scraper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SUCCEEDED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Run did not succeed (status: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;).&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 4. Fetch the saved stations
&lt;/span&gt;&lt;span class="n"&gt;items&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;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;default_dataset_id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;list_items&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Retrieved &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; stations.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behind the scenes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Actor sends your box to Freshmile's map search, which answers with single stations and clusters.&lt;/li&gt;
&lt;li&gt;When clusters come back, it splits the box into four quarters and searches each, up to three levels deep, and stops splitting once it has enough stations.&lt;/li&gt;
&lt;li&gt;With &lt;code&gt;fetchDetails&lt;/code&gt; on, it requests each station's detail, turns it into a row and saves it.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 5: View and download results
&lt;/h2&gt;

&lt;p&gt;Loop over the rows to print the parts you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&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="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  City: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;city&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;  Available: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;isAvailable&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Max power: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;maxPowerKw&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; kW, connectors: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;connectorCount&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;tariffs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tariffDescription&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;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;connectors&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tariffDescription&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;text&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tariffs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Tariff: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splitlines&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is one row, a sample from a capture dated 2026-09-22 (a station inside the box above), parsed with the Actor's own parser. &lt;code&gt;connectors&lt;/code&gt; is cut to the first 2 of its 8 entries, and &lt;code&gt;scrapedAt&lt;/code&gt;, the run's timestamp, is left out:&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FRV75PX08014"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"locationId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;172076&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Paris | Rue Pierre Charron  62"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"62 Rue Pierre Charron"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Paris"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"postalCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"75008"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"country"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FRA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"latitude"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;48.869644&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"longitude"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.30362&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"isAvailable"&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;"isOpen"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"twentyfourseven"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"regularHours"&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="nl"&gt;"evseCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"connectorCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxPowerKw"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;7.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"connectors"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"powerKw"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"standard"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DOMESTIC_F"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"isAttached"&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;"tariffName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Interop sortante - Normal temps (20)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"tariffCurrency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"tariffDescription"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"€ 0.25 / started kWh + € 0.07 / min.&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;The pricing continues as long as the vehicle remains plugged in."&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"powerKw"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;7.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"standard"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IEC_62196_T2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"isAttached"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"tariffName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Interop sortante - Normal temps (20)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"tariffCurrency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"tariffDescription"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"€ 0.25 / started kWh + € 0.07 / min.&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;The pricing continues as long as the vehicle remains plugged in."&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="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;For that row, the loop prints the station name, &lt;code&gt;City: Paris  Available: True&lt;/code&gt;, &lt;code&gt;Max power: 7.0 kW, connectors: 8&lt;/code&gt; and one tariff line.&lt;/p&gt;

&lt;p&gt;Apify datasets export as JSON, CSV, XML, Excel, HTML table, RSS or JSONL.&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding your results
&lt;/h2&gt;

&lt;p&gt;The fields that matter most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;id&lt;/code&gt; and &lt;code&gt;locationId&lt;/code&gt;: Freshmile's station ref, stable per station, and the numeric id its detail endpoint uses.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;isAvailable&lt;/code&gt;: at least one charge point is available at read time. In the capture, all 4 of the station's charge points showed &lt;code&gt;AVAILABLE&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;evseCount&lt;/code&gt;, &lt;code&gt;connectorCount&lt;/code&gt;, &lt;code&gt;maxPowerKw&lt;/code&gt;: charge points, connectors across them, and the highest connector power. The captured station had 4 charge points with 2 connectors each: a 2 kW &lt;code&gt;DOMESTIC_F&lt;/code&gt; and a 7 kW &lt;code&gt;IEC_62196_T2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;connectors[].tariffDescription&lt;/code&gt;: the tariff text exactly as Freshmile publishes it, not split into numbers. All 8 captured connectors carried the same tariff, in &lt;code&gt;EUR&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;isOpen&lt;/code&gt; and &lt;code&gt;twentyfourseven&lt;/code&gt;: flags as Freshmile reports them. In the 2026-09-22 captures, the same station read &lt;code&gt;isOpen: true&lt;/code&gt; in the map search and &lt;code&gt;false&lt;/code&gt; in its detail, so check both before relying on it. &lt;code&gt;twentyfourseven: false&lt;/code&gt; with empty &lt;code&gt;regularHours&lt;/code&gt; means no hours were published, not that the station is closed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;scrapedAt&lt;/code&gt;: one timestamp per run, taken when the station search finishes.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Pro tips
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Many tight boxes beat one wide box.&lt;/strong&gt; Clusters are split at most three levels deep; stations still clustered after that are not returned. For a whole city, run several small boxes, one task each.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skip details for a quick map.&lt;/strong&gt; &lt;code&gt;fetchDetails: false&lt;/code&gt; returns positions, &lt;code&gt;isAvailable&lt;/code&gt; and &lt;code&gt;evseCount&lt;/code&gt; without a detail request per station.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;maxItems&lt;/code&gt; as a budget.&lt;/strong&gt; It caps the stations processed, search hits and detail requests alike. Keep it at 10 while you test your code, then raise it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compare tariffs by text.&lt;/strong&gt; Group rows by &lt;code&gt;tariffName&lt;/code&gt; or &lt;code&gt;tariffDescription&lt;/code&gt; to see which stations share a price plan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Leave the proxy off.&lt;/strong&gt; The Actor calls the API directly by default; turn on &lt;code&gt;proxyConfiguration&lt;/code&gt; only if the log shows refused requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Track availability over time.&lt;/strong&gt; Schedule the same box and join runs on &lt;code&gt;id&lt;/code&gt;, Freshmile's stable station ref; each run's &lt;code&gt;scrapedAt&lt;/code&gt; tells you when its &lt;code&gt;isAvailable&lt;/code&gt; values were read.&lt;/li&gt;
&lt;/ol&gt;




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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero rows:&lt;/strong&gt; a run where the box search was refused or every station's detail request failed ends FAILED; a box that loads normally but holds no Freshmile station ends SUCCEEDED with an empty dataset and a status message saying so.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run stops at once:&lt;/strong&gt; check the box edges; west must be smaller than east, south smaller than north.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fewer rows than expected:&lt;/strong&gt; read the summary line near the end of the log, &lt;code&gt;Run completed. Pushed N rows. Rejected: {...}&lt;/code&gt;; it counts stations skipped by reason, such as a failed detail request. From Python: &lt;code&gt;client.log(run.id).get()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wide box, few stations:&lt;/strong&gt; split the box (Pro tip 1).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For help, use the Actor's &lt;a href="https://apify.com/reventadata/freshmile-scraper" rel="noopener noreferrer"&gt;Store page&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pricing and next steps
&lt;/h2&gt;

&lt;p&gt;For current pricing and details, see the &lt;a href="https://apify.com/reventadata/freshmile-scraper" rel="noopener noreferrer"&gt;Store page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To refresh availability on a timetable, save the input as a task and add an Apify schedule, which runs an Actor or task on a cron expression (&lt;code&gt;0 8 * * *&lt;/code&gt; is every day at 8 AM). To react when a run finishes, add a webhook on &lt;code&gt;ACTOR.RUN.SUCCEEDED&lt;/code&gt;; its payload carries the run object, including &lt;code&gt;defaultDatasetId&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://apify.com/reventadata/freshmile-scraper" rel="noopener noreferrer"&gt;Freshmile Scraper on Apify Store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.apify.com/api/client/python/docs" rel="noopener noreferrer"&gt;Apify Python client documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which charging areas are you planning to map? Drop a comment! 💬&lt;/p&gt;

</description>
      <category>python</category>
      <category>webscraping</category>
      <category>apify</category>
      <category>automation</category>
    </item>
    <item>
      <title>How to Scrape Cash Converters Spain Prices and Grades with Python</title>
      <dc:creator>ReventaData</dc:creator>
      <pubDate>Mon, 02 Nov 2026 08:58:40 +0000</pubDate>
      <link>https://dev.to/reventadata/how-to-scrape-cash-converters-spain-prices-and-grades-with-python-4e9b</link>
      <guid>https://dev.to/reventadata/how-to-scrape-cash-converters-spain-prices-and-grades-with-python-4e9b</guid>
      <description>&lt;p&gt;By the end of this tutorial, you will have a short Python script that turns a Cash Converters Spain search into structured rows: title, asking price in euros, the shop's own condition grade, the discount badge, the price when new, the saving against new, and the store that holds each unit.&lt;/p&gt;

&lt;p&gt;Cash Converters is a second-hand shop chain, not a marketplace: it grades its own stock as Perfecto, Bueno or Usado and writes its own titles. That makes its catalogue a clean reference for second-hand prices.&lt;/p&gt;

&lt;p&gt;In this guide, we use Python and the Apify Actor &lt;strong&gt;Cash Converters Spain Scraper&lt;/strong&gt; (&lt;code&gt;reventadata/cashconverters-scraper&lt;/code&gt;). The sample row shown below is a sample from a capture dated 2026-08-24 (the day it was added to the Actor's test suite), parsed with the Actor's own parser.&lt;/p&gt;

&lt;p&gt;⏱️ &lt;strong&gt;Time estimate:&lt;/strong&gt; one sitting: install one package, set one token, run three short Python blocks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To follow this tutorial, you will need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Python 3.11+&lt;/strong&gt; (&lt;code&gt;apify-client&lt;/code&gt; 3.3.0 requires it).&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Apify API client&lt;/strong&gt; for Python.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;Apify account&lt;/strong&gt; and its API token, which sits on the &lt;strong&gt;API &amp;amp; Integrations&lt;/strong&gt; page in Apify Console.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Install the client:&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; &lt;span class="s2"&gt;"apify-client~=3.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code reads the token from an environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;APIFY_API_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your_apify_token_here"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What you'll achieve
&lt;/h2&gt;

&lt;p&gt;You will turn a Cash Converters Spain search into one row per physical unit, not per model. Each row carries &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;price&lt;/code&gt; and &lt;code&gt;currency&lt;/code&gt; (&lt;code&gt;EUR&lt;/code&gt;), &lt;code&gt;condition&lt;/code&gt; (the shop's grade), &lt;code&gt;discountPercent&lt;/code&gt;, &lt;code&gt;priceWhenNew&lt;/code&gt;, &lt;code&gt;savingVsNew&lt;/code&gt;, &lt;code&gt;brand&lt;/code&gt;, &lt;code&gt;category&lt;/code&gt;, &lt;code&gt;productId&lt;/code&gt;, &lt;code&gt;storeId&lt;/code&gt;, a &lt;code&gt;url&lt;/code&gt; that opens this exact unit, and &lt;code&gt;imageUrl&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The same model can appear several times, once per branch that holds a unit. Those are different phones in different stores, not duplicates.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Example use case:&lt;/strong&gt; Suppose you want the resale price of an iPhone 13 mini 128 GB in good condition or better. You would set &lt;code&gt;searchQueries: ["iphone 13 mini"]&lt;/code&gt;, &lt;code&gt;conditions: ["a", "b"]&lt;/code&gt; and &lt;code&gt;minStorageGb: 128&lt;/code&gt;, and every saved row would be a Perfecto or Bueno unit whose title states at least 128 GB.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Access Cash Converters Spain Scraper
&lt;/h2&gt;

&lt;p&gt;Go to the &lt;a href="https://apify.com/reventadata/cashconverters-scraper" rel="noopener noreferrer"&gt;Cash Converters Spain Scraper&lt;/a&gt; page on Apify Store. The README lists every input and output field. In this tutorial we drive the Actor from Python, so everything after this step happens in code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Configure the search
&lt;/h2&gt;

&lt;p&gt;The main input is &lt;code&gt;searchQueries&lt;/code&gt;: one Cash Converters search per term, such as &lt;code&gt;iphone 13 mini&lt;/code&gt; or &lt;code&gt;macbook pro&lt;/code&gt;. There is no default; a run with no non-empty keyword fails with a &lt;code&gt;Bad input&lt;/code&gt; message instead of searching for something you did not ask for.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;maxItems&lt;/code&gt; caps the rows saved across the whole run (default 1000). Each keyword is paged until the results end, 100 items per request, up to 40 pages.&lt;/p&gt;

&lt;p&gt;Here is the setup. It searches &lt;code&gt;iphone 13 mini&lt;/code&gt; and saves at most 10 rows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&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="c1"&gt;# 1. Initialize ApifyClient with the token from the environment
&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="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;APIFY_API_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# 2. Define the search: one keyword, at most 10 rows
&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;iphone 13 mini&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;maxItems&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; the site's own search is fuzzy: &lt;code&gt;iphone 13 mini&lt;/code&gt; also returns iPhone 13 and iPhone 13 Pro. &lt;code&gt;requireKeywordMatch&lt;/code&gt; (on by default) drops any item whose title does not contain every word of your query, ignoring case and accents.&lt;/p&gt;

&lt;p&gt;No proxy setting is needed in &lt;code&gt;run_input&lt;/code&gt;. The README notes the catalogue answers plain HTTP; the input defaults to Apify Proxy, and &lt;code&gt;"proxyConfiguration": {"useApifyProxy": false}&lt;/code&gt; fetches directly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Add optional filters
&lt;/h2&gt;

&lt;p&gt;Some inputs are sent to Cash Converters with the search, so the site itself narrows what it returns. Others run on the rows the Actor reads:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Where it applies&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;conditions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;array&lt;/td&gt;
&lt;td&gt;Sent to the site: &lt;code&gt;a&lt;/code&gt; Perfecto, &lt;code&gt;b&lt;/code&gt; Bueno, &lt;code&gt;c&lt;/code&gt; Usado. Empty means any grade. One pass per grade.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;minPrice&lt;/code&gt; / &lt;code&gt;maxPrice&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;integer&lt;/td&gt;
&lt;td&gt;Sent to the site, in euros. Left out of the request when empty.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sortBy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;Sent to the site: &lt;code&gt;price-low-to-high&lt;/code&gt;, &lt;code&gt;price-high-to-low&lt;/code&gt;, &lt;code&gt;Novedad Tienda Desde&lt;/code&gt; (newest in store) or &lt;code&gt;Oferta&lt;/code&gt; (on offer). Order only.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;minStorageGb&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;integer&lt;/td&gt;
&lt;td&gt;Row filter on the capacity in the title. 1TB counts as 1024. Titles with no capacity are dropped when set.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;minDiscountPercent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;integer&lt;/td&gt;
&lt;td&gt;Row filter on the discount badge (0 to 99). Rows with no badge are dropped when set.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;requireKeywordMatch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;boolean&lt;/td&gt;
&lt;td&gt;Row filter: every query word in the title. Default on.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fetchDetails&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;boolean&lt;/td&gt;
&lt;td&gt;Not a filter: opens each product page for battery health, stock and rating.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three combinations that work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cheapest good units first:&lt;/strong&gt; &lt;code&gt;conditions: ["a", "b"]&lt;/code&gt;, &lt;code&gt;sortBy: "price-low-to-high"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Big discounts only:&lt;/strong&gt; &lt;code&gt;minDiscountPercent: 40&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Price band:&lt;/strong&gt; &lt;code&gt;minPrice: 150&lt;/code&gt;, &lt;code&gt;maxPrice: 400&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;code&gt;conditions&lt;/code&gt; accepts only &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt; and &lt;code&gt;c&lt;/code&gt;. Any other value is refused before the run starts, which matters here because Cash Converters answers an unknown grade with an empty result, not an error.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 4: Run the Actor
&lt;/h2&gt;

&lt;p&gt;Now start the run with &lt;code&gt;client.actor("reventadata/cashconverters-scraper").call(run_input=run_input)&lt;/code&gt;. The call starts the Actor on Apify and waits for it to finish before returning the 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="c1"&gt;# 3. Start the Actor run and wait for it to finish
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Starting Cash Converters extraction...&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;reventadata/cashconverters-scraper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SUCCEEDED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Run did not succeed (status: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;).&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 4. Fetch the saved rows
&lt;/span&gt;&lt;span class="n"&gt;items&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;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;default_dataset_id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;list_items&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Retrieved &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; items.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behind the scenes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Actor calls the same grid endpoint the site's own "load more" button uses, once per keyword and grade.&lt;/li&gt;
&lt;li&gt;It reads each product tile's data-layer attribute (id, name, brand, category, price, grade), applies your filters and saves the rows.&lt;/li&gt;
&lt;li&gt;It stops at &lt;code&gt;maxItems&lt;/code&gt;, at the end of the results, or at the 40-page cap, which it reports in the log when it bites.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 5: View and download results
&lt;/h2&gt;

&lt;p&gt;Loop over the rows to print the parts you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;condition&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Price: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; EUR&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;priceWhenNew&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  New: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;priceWhenNew&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; EUR, saving &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;savingVsNew&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; EUR&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Store: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;storeId&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Link: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is one row, a sample from a capture dated 2026-08-24 (the day it was added to the Actor's test suite), parsed with the Actor's own &lt;code&gt;to_row&lt;/code&gt; for the keyword &lt;code&gt;iphone 13 mini&lt;/code&gt;. Prices and stock may have changed since:&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;"batteryHealth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"batteryHealthMin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"inStock"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ratingValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"apple iphone 13 mini 128gb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;283.95&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usado"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"discountPercent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"priceWhenNew"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;439.99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"savingVsNew"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;156.04&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"brand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"apple"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"teléfonos/móviles/apple/iphone 13 mini 128gb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"productId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CC007_E1032776_0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"storeId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CC007"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url"&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://www.cashconverters.es/es/es/comprar/telefonos/moviles/apple/iphone-13-mini-128gb/?firstProduct=CC007_E1032776_0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"imageUrl"&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://images.cashconverters.es/productslive/smartphone/apple-iphone-13-mini-128gb_CC007_E1032776-0_0.jpg?d=small"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"matchedKeyword"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"iphone 13 mini"&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;Apify datasets export as JSON, CSV, XML, Excel, HTML table, RSS or JSONL.&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding your results
&lt;/h2&gt;

&lt;p&gt;The fields that matter most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;price&lt;/code&gt; and &lt;code&gt;currency&lt;/code&gt;: the asking price in euros, excluding delivery.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;condition&lt;/code&gt;: the shop's own grade, &lt;code&gt;Perfecto&lt;/code&gt;, &lt;code&gt;Bueno&lt;/code&gt; or &lt;code&gt;Usado&lt;/code&gt;. On a discounted tile the visible text reads &lt;code&gt;Nuevo 439,99 €&lt;/code&gt;, where &lt;code&gt;Nuevo&lt;/code&gt; labels the new price, not the grade; the Actor reads the grade from the tile's data attribute, so the sample row says &lt;code&gt;Usado&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;priceWhenNew&lt;/code&gt;: the struck-through figure, what the item costs new, not a former asking price. &lt;code&gt;savingVsNew&lt;/code&gt; is &lt;code&gt;priceWhenNew&lt;/code&gt; minus &lt;code&gt;price&lt;/code&gt;: 439.99 minus 283.95 gives 156.04 in the sample.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;discountPercent&lt;/code&gt;: the badge the site shows against the new price, 35 in the sample.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;storeId&lt;/code&gt;: the branch holding the unit, from the id prefix. &lt;code&gt;CC&lt;/code&gt; codes are Spanish stores, &lt;code&gt;PT&lt;/code&gt; codes Portuguese stores selling through the same catalogue.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;url&lt;/code&gt;: keeps &lt;code&gt;?firstProduct=&amp;lt;id&amp;gt;&lt;/code&gt;, so it opens this unit, not just the model page.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;batteryHealth&lt;/code&gt;, &lt;code&gt;batteryHealthMin&lt;/code&gt;, &lt;code&gt;inStock&lt;/code&gt;, &lt;code&gt;ratingValue&lt;/code&gt;: null unless &lt;code&gt;fetchDetails&lt;/code&gt; is on.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Pro tips
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Narrow on the site first.&lt;/strong&gt; &lt;code&gt;conditions&lt;/code&gt;, &lt;code&gt;minPrice&lt;/code&gt; and &lt;code&gt;maxPrice&lt;/code&gt; change what Cash Converters returns; &lt;code&gt;minStorageGb&lt;/code&gt; and &lt;code&gt;minDiscountPercent&lt;/code&gt; only drop rows after reading. A narrow row filter on a broad search reads many pages for few rows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read battery health with its floor.&lt;/strong&gt; With &lt;code&gt;fetchDetails&lt;/code&gt;, &lt;code&gt;batteryHealth&lt;/code&gt; is a figure for this unit and &lt;code&gt;batteryHealthMin&lt;/code&gt; is the warranty floor, usually 80. In the description "batería al 100% y una vida útil superior al 80%", the 100% is the charge level; the Actor's parser returns no health figure and a floor of 80 for it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch keywords in one run.&lt;/strong&gt; Put several terms in &lt;code&gt;searchQueries&lt;/code&gt;. A unit saved under one term is not saved again under the next, and a unit rejected under one term can still match a later one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mind the grade passes.&lt;/strong&gt; Each grade in &lt;code&gt;conditions&lt;/code&gt; is its own pass over the results; leave it empty for any grade in one pass.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start small.&lt;/strong&gt; Keep &lt;code&gt;maxItems: 10&lt;/code&gt; until your downstream code handles the fields, then raise it.&lt;/li&gt;
&lt;/ol&gt;




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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Run failed with "Bad input":&lt;/strong&gt; &lt;code&gt;searchQueries&lt;/code&gt; had no non-empty keyword, or &lt;code&gt;minPrice&lt;/code&gt; / &lt;code&gt;maxPrice&lt;/code&gt; was not a finite number.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Input refused before the run starts:&lt;/strong&gt; a &lt;code&gt;conditions&lt;/code&gt; value other than &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt; or &lt;code&gt;c&lt;/code&gt;, or a &lt;code&gt;sortBy&lt;/code&gt; value outside the list.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run succeeded with zero rows:&lt;/strong&gt; the status message starts &lt;code&gt;0 results for keywords ...&lt;/code&gt;, says the pages loaded normally but nothing matched, and lists the rejections. Widen the price range, drop &lt;code&gt;minStorageGb&lt;/code&gt; or &lt;code&gt;minDiscountPercent&lt;/code&gt;, or turn off &lt;code&gt;requireKeywordMatch&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run failed with "Every feed failed":&lt;/strong&gt; no feed returned product tiles, for example a keyword the site has no results for. Check the keyword on the site.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fewer rows than expected:&lt;/strong&gt; read the log's &lt;code&gt;Done. N item(s) considered, N pushed.&lt;/code&gt; line, and look for &lt;code&gt;Stopped at the 40-page cap for: ...&lt;/code&gt;; narrow the keyword or set a price range to see the rest. From Python: &lt;code&gt;client.log(run.id).get()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For help, use the Actor's &lt;a href="https://apify.com/reventadata/cashconverters-scraper" rel="noopener noreferrer"&gt;Store page&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pricing and next steps
&lt;/h2&gt;

&lt;p&gt;For current pricing and details, see the &lt;a href="https://apify.com/reventadata/cashconverters-scraper" rel="noopener noreferrer"&gt;Store page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To repeat a search, save the input as a task and add an Apify schedule, which runs an Actor or task on a cron expression (&lt;code&gt;0 8 * * *&lt;/code&gt; is every day at 8 AM). To react when a run finishes, add a webhook on &lt;code&gt;ACTOR.RUN.SUCCEEDED&lt;/code&gt;; its payload carries the run object, including &lt;code&gt;defaultDatasetId&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://apify.com/reventadata/cashconverters-scraper" rel="noopener noreferrer"&gt;Cash Converters Spain Scraper on Apify Store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.apify.com/api/client/python/docs" rel="noopener noreferrer"&gt;Apify Python client documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which models are you planning to track on Cash Converters? Drop a comment! 💬&lt;/p&gt;

</description>
      <category>python</category>
      <category>webscraping</category>
      <category>apify</category>
      <category>automation</category>
    </item>
    <item>
      <title>How to Audit Web Pages for WCAG Violations with axe-core and Python</title>
      <dc:creator>ReventaData</dc:creator>
      <pubDate>Mon, 02 Nov 2026 08:58:21 +0000</pubDate>
      <link>https://dev.to/reventadata/how-to-audit-web-pages-for-wcag-violations-with-axe-core-and-python-an9</link>
      <guid>https://dev.to/reventadata/how-to-audit-web-pages-for-wcag-violations-with-axe-core-and-python-an9</guid>
      <description>&lt;p&gt;By the end of this tutorial, you will have a short Python script that audits a list of web pages with axe-core and returns one row per failing element: the rule it broke, how serious it is, its CSS selector, its HTML and the advice for fixing it.&lt;/p&gt;

&lt;p&gt;axe-core is Deque's open-source accessibility testing engine. Running it yourself means driving a real browser, injecting the script, and flattening its nested results into rows.&lt;/p&gt;

&lt;p&gt;In this guide, we use Python and the Apify Actor &lt;strong&gt;axe-core Accessibility Audit Scraper&lt;/strong&gt; (&lt;code&gt;reventadata/axe-scraper&lt;/code&gt;). It is unofficial: it bundles axe-core 4.10.2 (MPL-2.0) and is not affiliated with Deque Systems. You will configure an audit, run it and read the rows. The sample row below is a sample from a capture dated 2026-10-12, parsed with the Actor's own code.&lt;/p&gt;

&lt;p&gt;⏱️ &lt;strong&gt;Time estimate:&lt;/strong&gt; one sitting: install one package, set one token, run three short Python blocks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To follow this tutorial, you will need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Python 3.11+&lt;/strong&gt; (&lt;code&gt;apify-client&lt;/code&gt; 3.3.0 requires it).&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Apify API client&lt;/strong&gt; for Python.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;Apify account&lt;/strong&gt; and its API token, which sits on the &lt;strong&gt;API &amp;amp; Integrations&lt;/strong&gt; page in Apify Console.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Install the client:&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; &lt;span class="s2"&gt;"apify-client~=3.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code reads the token from an environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;APIFY_API_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your_apify_token_here"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What you'll achieve
&lt;/h2&gt;

&lt;p&gt;You will turn a list of URLs into an accessibility report with one row per violating element. Each row carries &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;ruleId&lt;/code&gt; (for example &lt;code&gt;image-alt&lt;/code&gt; or &lt;code&gt;color-contrast&lt;/code&gt;), &lt;code&gt;impact&lt;/code&gt; (&lt;code&gt;minor&lt;/code&gt;, &lt;code&gt;moderate&lt;/code&gt;, &lt;code&gt;serious&lt;/code&gt; or &lt;code&gt;critical&lt;/code&gt;), &lt;code&gt;help&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;helpUrl&lt;/code&gt; (a Deque University page for the rule), &lt;code&gt;tags&lt;/code&gt;, &lt;code&gt;target&lt;/code&gt; (CSS selectors), &lt;code&gt;html&lt;/code&gt; (the element's markup) and &lt;code&gt;failureSummary&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Automated checks are a first pass, not a verdict. axe-core's own README says it finds "on average 57% of WCAG issues automatically". This Actor exports axe's violations only; the items axe marks "incomplete" (needs manual review) are not in the dataset.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Example use case:&lt;/strong&gt; Suppose you want every critical and serious issue on your sign-up and checkout pages before a release. You would list both URLs in &lt;code&gt;urls&lt;/code&gt;, set &lt;code&gt;minImpact: "serious"&lt;/code&gt;, and hand the rows to your issue tracker.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Access axe-core Accessibility Audit Scraper
&lt;/h2&gt;

&lt;p&gt;Go to the &lt;a href="https://apify.com/reventadata/axe-scraper" rel="noopener noreferrer"&gt;axe-core Accessibility Audit Scraper&lt;/a&gt; page on Apify Store. Its README lists every input and output field. In this tutorial we drive the Actor from Python, so everything after this step happens in code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Configure the pages and rules
&lt;/h2&gt;

&lt;p&gt;The main input is &lt;code&gt;urls&lt;/code&gt;: the pages to audit. Each must start with &lt;code&gt;http://&lt;/code&gt; or &lt;code&gt;https://&lt;/code&gt; and name a host; a URL that does not stops the run with an error at its start. Duplicates are removed, and pages are audited one after another in the order given.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;wcagTags&lt;/code&gt; picks which axe rules run, by tag. It defaults to &lt;code&gt;["wcag2a", "wcag2aa"]&lt;/code&gt;. Per axe-core's API docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;wcag2a&lt;/code&gt;, &lt;code&gt;wcag2aa&lt;/code&gt;: WCAG 2.0 Level A and AA.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;wcag21a&lt;/code&gt;, &lt;code&gt;wcag21aa&lt;/code&gt;: WCAG 2.1 Level A and AA.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;wcag22aa&lt;/code&gt;: WCAG 2.2 Level AA.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;best-practice&lt;/code&gt;: common accessibility best practices.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;section508&lt;/code&gt;: old Section 508 rules.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the setup. It audits one page against WCAG 2.0 A and AA rules and saves at most 50 rows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&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="c1"&gt;# 1. Initialize ApifyClient with the token from the environment
&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="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;APIFY_API_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# 2. Define the audit: one page, WCAG 2.0 A and AA rules, at most 50 rows
&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;urls&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;https://example.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wcagTags&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;wcag2a&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;wcag2aa&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;minImpact&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;minor&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;maxItems&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the Actor's prefill input. Swap in your own pages.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; use the lowercase tags above. The Actor trims and lowercases every tag before passing it to axe.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Add optional settings
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;minImpact&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;Keeps rows at or above this severity: &lt;code&gt;minor&lt;/code&gt; (all, the default), &lt;code&gt;moderate&lt;/code&gt;, &lt;code&gt;serious&lt;/code&gt; or &lt;code&gt;critical&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxItems&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;integer&lt;/td&gt;
&lt;td&gt;Caps the rows saved across all URLs (default 100).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;browserAuth&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;Optional Bright Data Scraping Browser credentials, &lt;code&gt;brd-customer-ID-zone-NAME:PASSWORD&lt;/code&gt;. A secret field.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three configurations to try:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Release gate:&lt;/strong&gt; &lt;code&gt;minImpact: "serious"&lt;/code&gt; on your key templates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WCAG 2.1 AA sweep:&lt;/strong&gt; &lt;code&gt;wcagTags: ["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best-practice review:&lt;/strong&gt; &lt;code&gt;wcagTags: ["best-practice"]&lt;/code&gt;, &lt;code&gt;minImpact: "moderate"&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ A &lt;code&gt;minImpact&lt;/code&gt; outside the four values is refused before the run starts. &lt;code&gt;browserAuth&lt;/code&gt; is a secret input: Apify's docs say such values get encrypted when the input is saved.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 4: Run the Actor
&lt;/h2&gt;

&lt;p&gt;Now start the run with &lt;code&gt;client.actor("reventadata/axe-scraper").call(run_input=run_input)&lt;/code&gt;. The call starts the Actor on Apify and waits for it to finish before returning the 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="c1"&gt;# 3. Start the Actor run and wait for it to finish
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Starting accessibility audit...&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;reventadata/axe-scraper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SUCCEEDED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Run did not succeed (status: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;).&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 4. Fetch the saved rows
&lt;/span&gt;&lt;span class="n"&gt;items&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;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;default_dataset_id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;list_items&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Retrieved &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; rows.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behind the scenes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Actor opens a real Chromium browser: Bright Data's Scraping Browser over CDP when Scraping Browser credentials are available, otherwise a headless Chromium it launches itself.&lt;/li&gt;
&lt;li&gt;For each URL it loads the page (45-second limit), waits one more second, injects axe-core 4.10.2 and runs it with your tags.&lt;/li&gt;
&lt;li&gt;It turns each violation into one row per failing element, applies &lt;code&gt;minImpact&lt;/code&gt;, and saves the rows until &lt;code&gt;maxItems&lt;/code&gt; is reached.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 5: View and download results
&lt;/h2&gt;

&lt;p&gt;Loop over the rows to print what you need:&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;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Counter&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ruleId&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;wcag-pass&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: no violations for the selected tags&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;impact&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;] &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ruleId&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;help&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Element: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;target&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Docs: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;helpUrl&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;40&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="nc"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;impact&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ruleId&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;wcag-pass&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;Here is one row, a sample from a capture dated 2026-10-12 (an axe-core result for one image without alt text), parsed with the Actor's own code. The capture stores no page address, so &lt;code&gt;url&lt;/code&gt; is the placeholder the Actor's tests pass. A saved row also carries &lt;code&gt;scrapedAt&lt;/code&gt;, the audit time:&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;"url"&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://example.com/test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ruleId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"image-alt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"impact"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"critical"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"help"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Images must have alternative text"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ensure &amp;lt;img&amp;gt; elements have alternative text or a role of none or presentation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"helpUrl"&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://dequeuniversity.com/rules/axe/4.10/image-alt?application=axeAPI"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tags"&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;"cat.text-alternatives"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"wcag2a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"wcag111"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"section508"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"section508.22.a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"TTv5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"TT7.a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"TT7.b"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"EN-301-549"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"EN-9.1.1.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"ACT"&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;"html"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;img src=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;broken.jpg&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;&amp;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;"target"&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;"img"&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;"failureSummary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Fix any of the following:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  Element does not have an alt attribute&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  aria-label attribute does not exist or is empty&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  Element has no title attribute&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;  Element's default semantics were not overridden with role=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;none&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; or role=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;presentation&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&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;Apify datasets export as JSON, CSV, XML, Excel, HTML table, RSS or JSONL.&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding your results
&lt;/h2&gt;

&lt;p&gt;The fields that matter most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ruleId&lt;/code&gt; and &lt;code&gt;help&lt;/code&gt;: the axe rule and its one-line title. &lt;code&gt;helpUrl&lt;/code&gt; opens Deque's page for that rule.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;impact&lt;/code&gt;: axe's severity for this element. When an element carries its own impact, the row uses it; otherwise the rule's.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;target&lt;/code&gt;: CSS selectors for the element. Each entry is one frame level, so an element inside one iframe has two entries.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;html&lt;/code&gt;: the element's markup, so you can find it in your templates.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;failureSummary&lt;/code&gt;: what failed, phrased as a fix. "Fix any of the following" means one of the listed changes is enough.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tags&lt;/code&gt;: the standards the rule maps to. &lt;code&gt;wcag111&lt;/code&gt; is WCAG success criterion 1.1.1.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two special rows: a page with no violations for your tags saves one row with &lt;code&gt;ruleId: "wcag-pass"&lt;/code&gt; and &lt;code&gt;impact: null&lt;/code&gt;. A rule axe reports without element details saves one row with &lt;code&gt;html: null&lt;/code&gt; and an empty &lt;code&gt;target&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pro tips
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Mind the shared cap.&lt;/strong&gt; &lt;code&gt;maxItems&lt;/code&gt; counts rows across all URLs, and once it is reached the remaining URLs are not audited. A page with many violations listed first can use the whole budget, so raise &lt;code&gt;maxItems&lt;/code&gt; or audit busy pages in their own run.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filter at the source.&lt;/strong&gt; &lt;code&gt;minImpact: "serious"&lt;/code&gt; keeps only serious and critical rows, which keeps a release check short.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick tags deliberately.&lt;/strong&gt; The default covers WCAG 2.0 A and AA. Add &lt;code&gt;wcag21a&lt;/code&gt;, &lt;code&gt;wcag21aa&lt;/code&gt; or &lt;code&gt;wcag22aa&lt;/code&gt; for the newer criteria; &lt;code&gt;best-practice&lt;/code&gt; adds rules beyond WCAG.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Group before you fix.&lt;/strong&gt; One rule often fails on many elements. Group rows by &lt;code&gt;ruleId&lt;/code&gt; and fix the shared component once.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plan manual review.&lt;/strong&gt; The dataset holds axe's violations only; the "needs review" items stay for a person to check.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make it a gate.&lt;/strong&gt; The status check in Step 4 already stops on a failed run. Add one line that exits non-zero when any row has &lt;code&gt;impact == "critical"&lt;/code&gt;, and the audit can block a deploy.&lt;/li&gt;
&lt;/ol&gt;




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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Run stops at once:&lt;/strong&gt; a URL lacks &lt;code&gt;http://&lt;/code&gt; or &lt;code&gt;https://&lt;/code&gt;, or &lt;code&gt;urls&lt;/code&gt; is empty.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero rows:&lt;/strong&gt; the status message starts "0 results for ...". FAILED means no page loaded or audited, or at least one page could not be read, so matches may have been missed. SUCCEEDED with an empty dataset means the pages were audited but every row was below &lt;code&gt;minImpact&lt;/code&gt;: lower it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One page missing from the results:&lt;/strong&gt; it failed to load and was skipped; the log has an &lt;code&gt;Audit failed for &amp;lt;url&amp;gt;&lt;/code&gt; warning. Or &lt;code&gt;maxItems&lt;/code&gt; was reached before its turn.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reading the log:&lt;/strong&gt; &lt;code&gt;client.log(run.id).get()&lt;/code&gt;. It counts rows dropped by &lt;code&gt;minImpact&lt;/code&gt; and near the end logs &lt;code&gt;Pushed N item(s) across N attempted URL(s).&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For help, use the Actor's &lt;a href="https://apify.com/reventadata/axe-scraper" rel="noopener noreferrer"&gt;Store page&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pricing and next steps
&lt;/h2&gt;

&lt;p&gt;For current pricing and details, see the &lt;a href="https://apify.com/reventadata/axe-scraper" rel="noopener noreferrer"&gt;Store page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To repeat an audit, save the input as a task and add an Apify schedule, which runs an Actor or task on a cron expression (&lt;code&gt;0 8 * * *&lt;/code&gt; is every day at 8 AM). To react when a run finishes, add a webhook on &lt;code&gt;ACTOR.RUN.SUCCEEDED&lt;/code&gt;; its payload carries the run object, including &lt;code&gt;defaultDatasetId&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://apify.com/reventadata/axe-scraper" rel="noopener noreferrer"&gt;axe-core Accessibility Audit Scraper on Apify Store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.apify.com/api/client/python/docs" rel="noopener noreferrer"&gt;Apify Python client documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which pages are you planning to audit first? Drop a comment! 💬&lt;/p&gt;

</description>
      <category>python</category>
      <category>webscraping</category>
      <category>a11y</category>
      <category>automation</category>
    </item>
    <item>
      <title>How to Scrape EV Charging Stations and Live Plug Status with Python</title>
      <dc:creator>ReventaData</dc:creator>
      <pubDate>Mon, 02 Nov 2026 08:58:02 +0000</pubDate>
      <link>https://dev.to/reventadata/how-to-scrape-ev-charging-stations-and-live-plug-status-with-python-49he</link>
      <guid>https://dev.to/reventadata/how-to-scrape-ev-charging-stations-and-live-plug-status-with-python-49he</guid>
      <description>&lt;p&gt;By the end of this tutorial, you will have a short Python script that turns a rectangle on the map into one row per EV charging station: network, coordinates, top power in kW, each connector group, and how many connectors are available, charging or out of order.&lt;/p&gt;

&lt;p&gt;The data comes from A Better Routeplanner (ABRP), an EV route planner whose web app loads chargers for the visible map area from its backend API. In this guide, we use Python and the Apify Actor &lt;strong&gt;ABRP EV Charging Scraper&lt;/strong&gt; (&lt;code&gt;reventadata/abrp-scraper&lt;/code&gt;), an unofficial tool not affiliated with ABRP or Iternio Planning AB. You will set a bounding box, run the Actor and filter by power and connector. The sample row below is a sample from a capture dated 2026-10-12, parsed with the Actor's own parser.&lt;/p&gt;

&lt;p&gt;⏱️ &lt;strong&gt;Time estimate:&lt;/strong&gt; one sitting: install one package, set one token, run three short Python blocks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To follow this tutorial, you will need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Python 3.11+&lt;/strong&gt; (&lt;code&gt;apify-client&lt;/code&gt; 3.3.0 requires it).&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Apify API client&lt;/strong&gt; for Python.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;Apify account&lt;/strong&gt; and its API token, which sits on the &lt;strong&gt;API &amp;amp; Integrations&lt;/strong&gt; page in Apify Console.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Install the client:&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; &lt;span class="s2"&gt;"apify-client~=3.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code reads the token from an environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;APIFY_API_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your_apify_token_here"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What you'll achieve
&lt;/h2&gt;

&lt;p&gt;You will turn a map rectangle into one row per charging station. Each row carries the station &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;networkName&lt;/code&gt;, &lt;code&gt;latitude&lt;/code&gt; and &lt;code&gt;longitude&lt;/code&gt;, an operational &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;maxPowerKw&lt;/code&gt;, connector totals (&lt;code&gt;totalConnectors&lt;/code&gt;, &lt;code&gt;availableConnectors&lt;/code&gt;, &lt;code&gt;chargingConnectors&lt;/code&gt;, &lt;code&gt;outOfOrderConnectors&lt;/code&gt;), a &lt;code&gt;connectors&lt;/code&gt; list with one entry per group, and a &lt;code&gt;sourceUrl&lt;/code&gt; that opens the station on ABRP.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; ABRP reports power in watts; the Actor converts it to kW, rounded to one decimal.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Example use case:&lt;/strong&gt; Suppose you want CCS chargers of at least 150 kW in one city. You would set the four box edges around the city, &lt;code&gt;minPowerKw: 150&lt;/code&gt; and &lt;code&gt;connectors: ["CCS"]&lt;/code&gt;, and every saved station would have at least one CCS group and a top power of 150 kW or more.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Access ABRP EV Charging Scraper
&lt;/h2&gt;

&lt;p&gt;Go to the &lt;a href="https://apify.com/reventadata/abrp-scraper" rel="noopener noreferrer"&gt;ABRP EV Charging Scraper&lt;/a&gt; page on Apify Store. The README lists every input and output field. In this tutorial we drive the Actor from Python, so everything after this step happens in code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Configure the bounding box
&lt;/h2&gt;

&lt;p&gt;The main input is the box: four numbers in WGS84 decimal degrees, the format GPS and most map tools use.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bboxWest&lt;/code&gt; and &lt;code&gt;bboxEast&lt;/code&gt;: the left and right longitudes (-180 to 180).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bboxSouth&lt;/code&gt; and &lt;code&gt;bboxNorth&lt;/code&gt;: the bottom and top latitudes (-90 to 90).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All four are required. &lt;code&gt;maxItems&lt;/code&gt; (default 100) caps the stations saved.&lt;/p&gt;

&lt;p&gt;Here is the setup. It uses the input schema's prefill box, which contains the centre of Madrid (40.4169, -3.7033), and saves at most 10 stations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&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="c1"&gt;# 1. Initialize ApifyClient with the token from the environment
&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="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;APIFY_API_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# 2. Define the area: the input schema's prefill box, at most 10 stations
&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;bboxWest&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;3.75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bboxSouth&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;40.40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bboxEast&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;3.65&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bboxNorth&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;40.45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maxItems&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; west must be smaller than east and south smaller than north, or the run stops with an error at its start. A box that crosses the 180th meridian therefore has to be split into two runs.&lt;/p&gt;

&lt;p&gt;No proxy setting is needed: the proxy is off by default, and in recon on 2026-10-12 direct HTTPS calls reached ABRP's API host with no proxy, browser or challenge.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Add optional filters
&lt;/h2&gt;

&lt;p&gt;Two filters run on each station after the Actor reads it. Stations they drop never reach your dataset:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;What it keeps&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;minPowerKw&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;integer&lt;/td&gt;
&lt;td&gt;Stations whose fastest connector reaches N kW. 0 (the default) turns it off.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;connectors&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;array&lt;/td&gt;
&lt;td&gt;Stations with at least one of the listed standards: &lt;code&gt;CCS&lt;/code&gt;, &lt;code&gt;TYPE2&lt;/code&gt;, &lt;code&gt;CHADEMO&lt;/code&gt;. Case does not matter; &lt;code&gt;Type 2&lt;/code&gt; with a space does not match.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;apiKey&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;secret string&lt;/td&gt;
&lt;td&gt;Not a filter: your own Iternio API key. When it is left empty, the Actor uses the key ABRP's web client sends.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three combinations that work as input:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Motorway-speed CCS:&lt;/strong&gt; &lt;code&gt;minPowerKw: 150&lt;/code&gt;, &lt;code&gt;connectors: ["CCS"]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CHAdeMO drivers:&lt;/strong&gt; &lt;code&gt;connectors: ["CHADEMO"]&lt;/code&gt;, no power floor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Everything in a box:&lt;/strong&gt; no filters, &lt;code&gt;maxItems: 100&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ A coordinate outside its range, or a missing box edge, is refused before the run starts.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 4: Run the Actor
&lt;/h2&gt;

&lt;p&gt;Now start the run with &lt;code&gt;client.actor("reventadata/abrp-scraper").call(run_input=run_input)&lt;/code&gt;. The call starts the Actor on Apify and waits for it to finish before returning the 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="c1"&gt;# 3. Start the Actor run and wait for it to finish
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Starting ABRP charger extraction...&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;reventadata/abrp-scraper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SUCCEEDED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Run did not succeed (status: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;).&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 4. Fetch the saved stations
&lt;/span&gt;&lt;span class="n"&gt;items&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;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;default_dataset_id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;list_items&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Retrieved &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; stations.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behind the scenes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Actor asks ABRP's bounding-box search for charger IDs inside your box, up to four times &lt;code&gt;maxItems&lt;/code&gt; (at least 100).&lt;/li&gt;
&lt;li&gt;It fetches the full station records in batches of 50, maps each to a row and applies your filters.&lt;/li&gt;
&lt;li&gt;It stops once &lt;code&gt;maxItems&lt;/code&gt; stations are saved or the IDs run out.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 5: View and download results
&lt;/h2&gt;

&lt;p&gt;Loop over the rows to print the parts you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;networkName&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;unknown network&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Max power: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;maxPowerKw&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; kW&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Free now: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;availableConnectors&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; of &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;totalConnectors&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;connectors&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;    &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;standard&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;powerKw&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; kW: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;available&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; of &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;count&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; free&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Map: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sourceUrl&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is one row, a sample from a capture dated 2026-10-12 (one station record of the Eviny network, not from the Madrid box above) parsed with the Actor's own parser:&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1986998632"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Eviny"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"networkId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12498&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"networkName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Eviny"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"latitude"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;55.717689514160156&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"longitude"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;13.165938377380371&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"OPEN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hasDynamicStatus"&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;"maxPowerKw"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;350.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"totalConnectors"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"availableConnectors"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"chargingConnectors"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"outOfOrderConnectors"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"connectors"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"standard"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CCS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"powerKw"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;350.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"available"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"charging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"outOfOrder"&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"standard"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CCS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"powerKw"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;200.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"available"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"charging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"outOfOrder"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
    &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="nl"&gt;"standard"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CHADEMO"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"powerKw"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;63.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"available"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"charging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"outOfOrder"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"standard"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TYPE2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"powerKw"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;22.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"count"&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="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"available"&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="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"charging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"outOfOrder"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&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="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sourceUrl"&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://abetterrouteplanner.com/?charger_id=1986998632"&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;Apify datasets export as JSON, CSV, XML, Excel, HTML table, RSS or JSONL.&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding your results
&lt;/h2&gt;

&lt;p&gt;The fields that matter most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;maxPowerKw&lt;/code&gt;: the highest power of any connector group. In the sample it is 350.0, from the first CCS group.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;connectors&lt;/code&gt;: one entry per group, with &lt;code&gt;standard&lt;/code&gt;, &lt;code&gt;powerKw&lt;/code&gt;, &lt;code&gt;count&lt;/code&gt; and the status split. The sample has four groups: CCS at 350 and at 200 kW, CHAdeMO at 63 kW and Type 2 at 22 kW.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;availableConnectors&lt;/code&gt;, &lt;code&gt;chargingConnectors&lt;/code&gt;, &lt;code&gt;outOfOrderConnectors&lt;/code&gt;: totals across groups, as ABRP reported them when the record was fetched. In the sample, 18 of 23 were available, 2 charging and 3 out of order.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;outOfOrder&lt;/code&gt; counts both statuses ABRP uses for a broken plug, &lt;code&gt;OUTOFORDER&lt;/code&gt; and &lt;code&gt;INOPERATIVE&lt;/code&gt;: the sample's 200 kW group had one of each, so it shows 2.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;totalConnectors&lt;/code&gt; sums every group's count, so a status the Actor does not bucket still counts there.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hasDynamicStatus&lt;/code&gt;: whether live connector status is available for the station.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt; currently holds the network name, the same value as &lt;code&gt;networkName&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Pro tips
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Draw a small box first.&lt;/strong&gt; The prefill box covers a slice of one city. Start there, check the fields, then widen it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Raise &lt;code&gt;maxItems&lt;/code&gt; when you filter.&lt;/strong&gt; The Actor requests four times &lt;code&gt;maxItems&lt;/code&gt; candidate IDs (at least 100) and filters after fetching, so a strict filter can leave fewer than &lt;code&gt;maxItems&lt;/code&gt; stations even when the area has more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Know what &lt;code&gt;minPowerKw&lt;/code&gt; tests.&lt;/strong&gt; It compares the station's fastest connector. A 350 kW station passes &lt;code&gt;minPowerKw: 150&lt;/code&gt; and still lists its 22 kW group in &lt;code&gt;connectors&lt;/code&gt;; filter the list yourself if you need only the fast plugs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use the standard names as written.&lt;/strong&gt; &lt;code&gt;CCS&lt;/code&gt;, &lt;code&gt;TYPE2&lt;/code&gt; and &lt;code&gt;CHADEMO&lt;/code&gt; are the values in the sample; lowercase works, extra spaces do not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Split big areas.&lt;/strong&gt; Several smaller boxes, run as separate runs or scheduled tasks, keep each run inside its &lt;code&gt;maxItems&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automate from code.&lt;/strong&gt; The same &lt;code&gt;run_input&lt;/code&gt; works with &lt;code&gt;.start()&lt;/code&gt; when you do not want to wait, and with a webhook that loads each finished dataset.&lt;/li&gt;
&lt;/ol&gt;




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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Run FAILED with zero rows:&lt;/strong&gt; the Actor fails a run that saves nothing when it cannot confirm the box really was empty: the search returned no charger IDs, or a batch of station details came back empty. A box where stations loaded normally but every one failed your filters ends SUCCEEDED with an empty dataset and a status message listing the rejections.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run stops at its start:&lt;/strong&gt; &lt;code&gt;bboxWest&lt;/code&gt; was not smaller than &lt;code&gt;bboxEast&lt;/code&gt;, or &lt;code&gt;bboxSouth&lt;/code&gt; not smaller than &lt;code&gt;bboxNorth&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Input refused before the run starts:&lt;/strong&gt; a box edge is missing or out of range.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fewer stations than expected:&lt;/strong&gt; read the log. &lt;code&gt;Discovered N charger ID(s) across bounding box.&lt;/code&gt; gives the candidates; &lt;code&gt;Sweep complete: N stations emitted, rejections: ...&lt;/code&gt; counts the filter drops. From Python: &lt;code&gt;client.log(run.id).get()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For help, use the Actor's &lt;a href="https://apify.com/reventadata/abrp-scraper" rel="noopener noreferrer"&gt;Store page&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pricing and next steps
&lt;/h2&gt;

&lt;p&gt;For current pricing and details, see the &lt;a href="https://apify.com/reventadata/abrp-scraper" rel="noopener noreferrer"&gt;Store page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To watch one area, save the input as a task and add an Apify schedule, which runs an Actor or task on a cron expression (&lt;code&gt;0 8 * * *&lt;/code&gt; is every day at 8 AM). To react when a run finishes, add a webhook on &lt;code&gt;ACTOR.RUN.SUCCEEDED&lt;/code&gt;; its payload carries the run object, including &lt;code&gt;defaultDatasetId&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://apify.com/reventadata/abrp-scraper" rel="noopener noreferrer"&gt;ABRP EV Charging Scraper on Apify Store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.apify.com/api/client/python/docs" rel="noopener noreferrer"&gt;Apify Python client documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which city or corridor are you planning to map chargers for? Drop a comment! 💬&lt;/p&gt;

</description>
      <category>python</category>
      <category>webscraping</category>
      <category>apify</category>
      <category>automation</category>
    </item>
    <item>
      <title>How to Scrape Electromaps EV Charging Stations with Python</title>
      <dc:creator>ReventaData</dc:creator>
      <pubDate>Mon, 02 Nov 2026 08:30:55 +0000</pubDate>
      <link>https://dev.to/reventadata/how-to-scrape-electromaps-ev-charging-stations-with-python-3k14</link>
      <guid>https://dev.to/reventadata/how-to-scrape-electromaps-ev-charging-stations-with-python-3k14</guid>
      <description>&lt;p&gt;By the end of this tutorial, you will have a short Python script that turns a map rectangle into a list of EV charging stations from Electromaps: name, address, coordinates, connector mix, highest power in kW, community rating, opening hours and the price text the station publishes.&lt;/p&gt;

&lt;p&gt;Electromaps is a charging-station map. It has no self-serve public API, so getting its stations into a spreadsheet by hand means clicking through the map one pin at a time.&lt;/p&gt;

&lt;p&gt;In this guide, we use Python and the Apify Actor &lt;strong&gt;Electromaps EV Charging Scraper&lt;/strong&gt; (&lt;code&gt;reventadata/electromaps-scraper&lt;/code&gt;). You will draw a bounding box, add filters, run the Actor and read the rows. The sample row shown below is a sample from a capture dated 2026-09-22, parsed with the Actor's own code.&lt;/p&gt;

&lt;p&gt;⏱️ &lt;strong&gt;Time estimate:&lt;/strong&gt; one sitting: install one package, set one token, run three short Python blocks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To follow this tutorial, you will need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Python 3.11+&lt;/strong&gt; (&lt;code&gt;apify-client&lt;/code&gt; 3.3.0 requires it).&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Apify API client&lt;/strong&gt; for Python.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;Apify account&lt;/strong&gt; and its API token, which sits on the &lt;strong&gt;API &amp;amp; Integrations&lt;/strong&gt; page in Apify Console.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Install the client:&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; &lt;span class="s2"&gt;"apify-client~=3.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code reads the token from an environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;APIFY_API_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your_apify_token_here"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What you'll achieve
&lt;/h2&gt;

&lt;p&gt;You will turn a bounding box into one row per charging station. Each row carries the station &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;address&lt;/code&gt;, &lt;code&gt;city&lt;/code&gt;, &lt;code&gt;postalCode&lt;/code&gt;, &lt;code&gt;countryCode&lt;/code&gt;, &lt;code&gt;latitude&lt;/code&gt; and &lt;code&gt;longitude&lt;/code&gt;, the site type (&lt;code&gt;locationType&lt;/code&gt;), &lt;code&gt;rating&lt;/code&gt; and &lt;code&gt;ratingCount&lt;/code&gt;, &lt;code&gt;openTime&lt;/code&gt;, &lt;code&gt;chargePrice&lt;/code&gt;, and a &lt;code&gt;connectors&lt;/code&gt; list with each connector's type, status, power, voltage and amperage.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; statuses come back exactly as Electromaps reports them. Where a station's &lt;code&gt;realtime&lt;/code&gt; flag is &lt;code&gt;false&lt;/code&gt;, its statuses are crowdsourced, not live, and &lt;code&gt;UNKNOWN&lt;/code&gt; stays &lt;code&gt;UNKNOWN&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Example use case:&lt;/strong&gt; Suppose you want every on-street or parking-lot charger of at least 50 kW inside a city. You would set the four box edges around the city, &lt;code&gt;locationTypes: ["ON_STREET", "PARKING"]&lt;/code&gt; and &lt;code&gt;minPowerKw: 50&lt;/code&gt;, and get one row per matching station with its connectors listed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Access Electromaps EV Charging Scraper
&lt;/h2&gt;

&lt;p&gt;Go to the &lt;a href="https://apify.com/reventadata/electromaps-scraper" rel="noopener noreferrer"&gt;Electromaps EV Charging Scraper&lt;/a&gt; page on Apify Store. The README lists every input and output field. In this tutorial we drive the Actor from Python, so everything after this step happens in code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Configure the bounding box
&lt;/h2&gt;

&lt;p&gt;The four required inputs are the edges of the search box, in WGS84 decimal degrees (the latitude and longitude numbers any map shows):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bboxWest&lt;/code&gt; and &lt;code&gt;bboxEast&lt;/code&gt;: the minimum and maximum longitude, between -180 and 180.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bboxSouth&lt;/code&gt; and &lt;code&gt;bboxNorth&lt;/code&gt;: the minimum and maximum latitude, between -90 and 90.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;West must be smaller than east and south smaller than north; otherwise the run stops with an error at its start. A value outside the ranges above is refused before the run starts.&lt;/p&gt;

&lt;p&gt;Here is the setup. It uses the Actor's prefill box, a small rectangle in Vilanova i la Geltrú, Spain, with on-street and parking sites, detail on, at most 10 stations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&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="c1"&gt;# 1. Initialize ApifyClient with the token from the environment
&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="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;APIFY_API_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# 2. Define the search: one small box, two site types, at most 10 stations
&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;bboxWest&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.7227&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bboxSouth&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;41.2135&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bboxEast&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.724&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bboxNorth&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;41.2145&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;locationTypes&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;ON_STREET&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;PARKING&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;maxItems&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fetchDetails&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; on a web map that displays coordinates, read the four numbers off two opposite corners of the area you want. Start with a small box; you can widen it once the rows look right.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Add optional filters
&lt;/h2&gt;

&lt;p&gt;The first four are sent to Electromaps with the box, so stations that do not match never come back; the last two are the Actor's own settings:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;locationTypes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;array&lt;/td&gt;
&lt;td&gt;Site types to keep. Omit it for all 12 the Actor knows.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;minPowerKw&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;integer&lt;/td&gt;
&lt;td&gt;Minimum connector power in kW. &lt;code&gt;0&lt;/code&gt; turns it off.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;connectors&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;array&lt;/td&gt;
&lt;td&gt;Connector codes such as &lt;code&gt;IEC_62196_T2&lt;/code&gt; or &lt;code&gt;CHADEMO&lt;/code&gt;. Empty turns it off.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;realtimeOnly&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;boolean&lt;/td&gt;
&lt;td&gt;Only stations that report live data.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;maxItems&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;integer&lt;/td&gt;
&lt;td&gt;Cap on stations processed (default 100).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fetchDetails&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;boolean&lt;/td&gt;
&lt;td&gt;Not a filter: one extra request per station for connectors, ratings and prices (default on).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The 12 site types the Actor accepts are &lt;code&gt;ON_STREET&lt;/code&gt;, &lt;code&gt;PARKING&lt;/code&gt;, &lt;code&gt;AIRPORT&lt;/code&gt;, &lt;code&gt;CAMPING&lt;/code&gt;, &lt;code&gt;HOTEL&lt;/code&gt;, &lt;code&gt;RESTAURANT&lt;/code&gt;, &lt;code&gt;SHOP&lt;/code&gt;, &lt;code&gt;WORKSHOP&lt;/code&gt;, &lt;code&gt;FUEL_STATION&lt;/code&gt;, &lt;code&gt;CAR_DEALER&lt;/code&gt;, &lt;code&gt;MALL&lt;/code&gt; and &lt;code&gt;TAXI&lt;/code&gt;. Lowercase is fine; the Actor upper-cases them.&lt;/p&gt;

&lt;p&gt;Three combinations that work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fast chargers in a city:&lt;/strong&gt; a city box, &lt;code&gt;minPowerKw: 50&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hotel chargers for a trip:&lt;/strong&gt; a region box, &lt;code&gt;locationTypes: ["HOTEL", "CAMPING"]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A quick pin map:&lt;/strong&gt; any box, &lt;code&gt;fetchDetails: false&lt;/code&gt; for id, name and coordinates only.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ A site type outside those 12 stops the run at its start, before any request is sent: Electromaps answers unknown types with HTTP 403.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 4: Run the Actor
&lt;/h2&gt;

&lt;p&gt;Now start the run with &lt;code&gt;client.actor("reventadata/electromaps-scraper").call(run_input=run_input)&lt;/code&gt;. The call starts the Actor on Apify and waits for it to finish before returning the 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="c1"&gt;# 3. Start the Actor run and wait for it to finish
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Starting Electromaps extraction...&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;reventadata/electromaps-scraper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SUCCEEDED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Run did not succeed (status: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;).&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 4. Fetch the saved stations
&lt;/span&gt;&lt;span class="n"&gt;items&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;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;default_dataset_id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;list_items&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Retrieved &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; stations.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behind the scenes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Actor sends one request for the stations inside your box, with your filters, to the JSON that Electromaps' own map reads. No HTML is scraped, and no key or login is involved.&lt;/li&gt;
&lt;li&gt;With &lt;code&gt;fetchDetails&lt;/code&gt; on, it then requests each station's detail, up to &lt;code&gt;maxItems&lt;/code&gt; stations, and turns it into one row.&lt;/li&gt;
&lt;li&gt;A station whose detail fails is logged and skipped; the run carries on with the rest.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 5: View and download results
&lt;/h2&gt;

&lt;p&gt;Loop over the rows to print the parts you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;|&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;city&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Max power: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;maxPowerKw&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; kW, connectors: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;connectorCount&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Status: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;offlineStatus&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; (realtime: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;realtime&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Price: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;chargePrice&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;not published&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;connectors&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="p"&gt;[]:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;    &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;powerKw&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; kW &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;powerType&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is one row, a sample from a capture dated 2026-09-22 (the station inside the prefill box) parsed with the Actor's own code. A saved row also carries &lt;code&gt;scrapedAt&lt;/code&gt;, the run's timestamp:&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;307432&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ribes Roges 11 Vilanova i la Geltrú"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url"&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://map.electromaps.com/en/p/307432"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passeig de Ribes Roges, 10, 08800, Vilanova i la Geltrú"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Vilanova i la Geltrú"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"postalCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"08800"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"countryCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ES"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"latitude"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;41.213871159682&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"longitude"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.723192892969&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"locationType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ON_STREET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"rating"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3.1481&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ratingCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;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;"onlineStatus"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"UNKNOWN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"offlineStatus"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"WORKING"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"realtime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"openTime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"24h"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"chargePrice"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Gratuito"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"parkingPrice"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&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;"priceKwhFrom"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"instructions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"App EVCharge"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"contact"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Etecnic"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"reservable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"onlyTesla"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"connectorCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"maxPowerKw"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;22.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"connectors"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IEC_62196_T2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"UNKNOWN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"powerKw"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;22.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"powerType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AC_3_PHASE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"voltage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"amperage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"format"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SOCKET"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IEC_62196_T2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"WORKING"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"powerKw"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;22.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"powerType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AC_3_PHASE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"voltage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"amperage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"format"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SOCKET"&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="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;Apify datasets export as JSON, CSV, XML, Excel, HTML table, RSS or JSONL.&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding your results
&lt;/h2&gt;

&lt;p&gt;The fields that matter most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;id&lt;/code&gt; and &lt;code&gt;url&lt;/code&gt;: Electromaps' numeric station id and the station's page on its map (&lt;code&gt;map.electromaps.com/en/p/&amp;lt;id&amp;gt;&lt;/code&gt;), handy as a join key between runs.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;maxPowerKw&lt;/code&gt; and &lt;code&gt;connectorCount&lt;/code&gt;: the highest connector power and the number of connectors. In the sample, two 22 kW connectors.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;connectors&lt;/code&gt;: one object per connector. &lt;code&gt;type&lt;/code&gt; is Electromaps' code (&lt;code&gt;IEC_62196_T2&lt;/code&gt; here), &lt;code&gt;powerType&lt;/code&gt; is the current type (&lt;code&gt;AC_3_PHASE&lt;/code&gt; here), plus &lt;code&gt;voltage&lt;/code&gt;, &lt;code&gt;amperage&lt;/code&gt; and &lt;code&gt;format&lt;/code&gt; (&lt;code&gt;SOCKET&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;status&lt;/code&gt;, &lt;code&gt;offlineStatus&lt;/code&gt;, &lt;code&gt;onlineStatus&lt;/code&gt;, &lt;code&gt;realtime&lt;/code&gt;: verbatim. The sample has &lt;code&gt;realtime: false&lt;/code&gt;, so its statuses are crowdsourced; one connector reads &lt;code&gt;WORKING&lt;/code&gt; and the other &lt;code&gt;UNKNOWN&lt;/code&gt;, and the Actor guesses neither.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chargePrice&lt;/code&gt; and &lt;code&gt;parkingPrice&lt;/code&gt;: text as the station publishes it. &lt;code&gt;Gratuito&lt;/code&gt; is Spanish for free; the sample's &lt;code&gt;parkingPrice&lt;/code&gt; is an empty string. &lt;code&gt;priceKwhFrom&lt;/code&gt; is a number only when a per-kWh price is published.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rating&lt;/code&gt; and &lt;code&gt;ratingCount&lt;/code&gt;: the community rating, 3.1481 from 27 ratings in the sample.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;instructions&lt;/code&gt; and &lt;code&gt;contact&lt;/code&gt;: access notes (&lt;code&gt;App EVCharge&lt;/code&gt;) and the operator's name (&lt;code&gt;Etecnic&lt;/code&gt;). Uploader usernames, avatars and ads are dropped.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Pro tips
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Size the box to &lt;code&gt;maxItems&lt;/code&gt;.&lt;/strong&gt; A Barcelona-area box in the 2026-09-22 capture held 1,955 stations, and &lt;code&gt;maxItems&lt;/code&gt; defaults to 100. Raise the cap or split a city into several boxes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filter on the server.&lt;/strong&gt; &lt;code&gt;locationTypes&lt;/code&gt;, &lt;code&gt;minPowerKw&lt;/code&gt;, &lt;code&gt;connectors&lt;/code&gt; and &lt;code&gt;realtimeOnly&lt;/code&gt; are applied by Electromaps, so a narrow filter shrinks the list before any detail request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skip details for a pin map.&lt;/strong&gt; &lt;code&gt;fetchDetails: false&lt;/code&gt; saves id, name and coordinates only, with no extra request per station.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treat statuses as reported, not live.&lt;/strong&gt; Check &lt;code&gt;realtime&lt;/code&gt; before you show a connector as available. For live-only data, set &lt;code&gt;realtimeOnly: true&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start small.&lt;/strong&gt; Keep &lt;code&gt;maxItems: 10&lt;/code&gt; until your downstream code handles the fields, then raise it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connect it to the rest of your pipeline.&lt;/strong&gt; A webhook on &lt;code&gt;ACTOR.RUN.SUCCEEDED&lt;/code&gt; hands your endpoint the run object with its &lt;code&gt;defaultDatasetId&lt;/code&gt;, so a script can load each new dataset as soon as a run ends. For bigger datasets, &lt;code&gt;iterate_items()&lt;/code&gt; pages through the rows instead of loading them in one call.&lt;/li&gt;
&lt;/ol&gt;




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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero rows:&lt;/strong&gt; a run that is blocked or cannot read a station's detail ends FAILED; an empty box or an over-strict filter ends SUCCEEDED with an empty dataset and a status message saying so. Widen the box or loosen &lt;code&gt;minPowerKw&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run stops at once:&lt;/strong&gt; west is not smaller than east, south is not smaller than north, or a &lt;code&gt;locationTypes&lt;/code&gt; value is not one of the 12.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Input refused before the run starts:&lt;/strong&gt; a box edge outside -180 to 180 or -90 to 90, or a required edge missing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fewer rows than expected:&lt;/strong&gt; read the summary line near the end of the log, &lt;code&gt;Run completed. Pushed N rows. Rejected: {...}&lt;/code&gt;; it counts skipped stations by reason, such as a failed detail request. From Python: &lt;code&gt;client.log(run.id).get()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For help, use the Actor's &lt;a href="https://apify.com/reventadata/electromaps-scraper" rel="noopener noreferrer"&gt;Store page&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pricing and next steps
&lt;/h2&gt;

&lt;p&gt;For current pricing and details, see the &lt;a href="https://apify.com/reventadata/electromaps-scraper" rel="noopener noreferrer"&gt;Store page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To refresh a box regularly, save the input as a task and add an Apify schedule, which runs an Actor or task on a cron expression (&lt;code&gt;0 8 * * *&lt;/code&gt; is every day at 8 AM). To react when a run finishes, add a webhook on &lt;code&gt;ACTOR.RUN.SUCCEEDED&lt;/code&gt;; its payload carries the run object, including &lt;code&gt;defaultDatasetId&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://apify.com/reventadata/electromaps-scraper" rel="noopener noreferrer"&gt;Electromaps EV Charging Scraper on Apify Store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.apify.com/api/client/python/docs" rel="noopener noreferrer"&gt;Apify Python client documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which area are you planning to map? Drop a comment! 💬&lt;/p&gt;

</description>
      <category>python</category>
      <category>webscraping</category>
      <category>apify</category>
      <category>automation</category>
    </item>
    <item>
      <title>How to Search Brazilian Company Records with CNPJ Brasil Scraper</title>
      <dc:creator>ReventaData</dc:creator>
      <pubDate>Mon, 02 Nov 2026 08:30:37 +0000</pubDate>
      <link>https://dev.to/reventadata/how-to-search-brazilian-company-records-with-cnpj-brasil-scraper-5a0g</link>
      <guid>https://dev.to/reventadata/how-to-search-brazilian-company-records-with-cnpj-brasil-scraper-5a0g</guid>
      <description>&lt;p&gt;By the end of this tutorial, you will have a short Python script that turns a company-name search into structured Brazilian company records: CNPJ, legal name (razão social), trade name (nome fantasia), registration status, primary CNAE activity, share capital, size tier and address.&lt;/p&gt;

&lt;p&gt;Every Brazilian company has a CNPJ, the 14-digit national registry number. If you build B2B lead lists or check suppliers, you usually want those records filtered by state, status and activity, not looked up one by one.&lt;/p&gt;

&lt;p&gt;In this guide, we use Python and the Apify Actor &lt;strong&gt;CNPJ Brasil Scraper&lt;/strong&gt; (&lt;code&gt;reventadata/cnpj-brasil-scraper&lt;/code&gt;). The sample rows below come from a local test run dated 2026-10-24, made with the input shown in the code. The Actor is unofficial and not affiliated with Casa dos Dados or Receita Federal.&lt;/p&gt;

&lt;p&gt;⏱️ &lt;strong&gt;Time estimate:&lt;/strong&gt; one sitting: install one package, set one token, run three short Python blocks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To follow this tutorial, you will need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Python 3.11+&lt;/strong&gt; (&lt;code&gt;apify-client&lt;/code&gt; 3.3.0 requires it).&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Apify API client&lt;/strong&gt; for Python.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;Apify account&lt;/strong&gt; and its API token, which sits on the &lt;strong&gt;API &amp;amp; Integrations&lt;/strong&gt; page in Apify Console.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Install the client:&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; &lt;span class="nt"&gt;-U&lt;/span&gt; &lt;span class="s2"&gt;"apify-client~=3.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code reads the token from an environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;APIFY_API_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your_apify_token_here"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What you'll achieve
&lt;/h2&gt;

&lt;p&gt;You will turn a keyword search into one row per company. Each row carries &lt;code&gt;cnpj&lt;/code&gt; and &lt;code&gt;cnpjFormatted&lt;/code&gt;, &lt;code&gt;legalName&lt;/code&gt;, &lt;code&gt;tradeName&lt;/code&gt; (null when none is registered in the data), &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;openingDate&lt;/code&gt;, &lt;code&gt;cnaeCode&lt;/code&gt; and &lt;code&gt;cnaeDescription&lt;/code&gt;, &lt;code&gt;shareCapital&lt;/code&gt; in reais, &lt;code&gt;legalNature&lt;/code&gt;, &lt;code&gt;companySize&lt;/code&gt;, the &lt;code&gt;isSimplesNacional&lt;/code&gt;, &lt;code&gt;isMei&lt;/code&gt; and &lt;code&gt;isMatriz&lt;/code&gt; flags, and the address split into &lt;code&gt;city&lt;/code&gt;, &lt;code&gt;state&lt;/code&gt;, &lt;code&gt;neighborhood&lt;/code&gt;, &lt;code&gt;street&lt;/code&gt; and &lt;code&gt;zipCode&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; rows hold company fields only. The row has no partner list, CPF, phone or e-mail field, and the name search does not look at partner names.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Example use case:&lt;/strong&gt; Suppose you want active software firms headquartered in Paraná. You would set &lt;code&gt;searchQueries: ["software"]&lt;/code&gt;, &lt;code&gt;state: "PR"&lt;/code&gt;, &lt;code&gt;status: "ATIVA"&lt;/code&gt;, &lt;code&gt;cnaeCode: "6201501"&lt;/code&gt; and &lt;code&gt;onlyMatriz: true&lt;/code&gt;, and every saved row would be an active company registered in PR whose name contains "software", found by a search limited to headquarters with that primary CNAE.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Access CNPJ Brasil Scraper
&lt;/h2&gt;

&lt;p&gt;Go to the &lt;a href="https://apify.com/reventadata/cnpj-brasil-scraper" rel="noopener noreferrer"&gt;CNPJ Brasil Scraper&lt;/a&gt; page on Apify Store. The README lists every input and output field. In this tutorial we drive the Actor from Python, so everything after this step happens in code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Configure the search
&lt;/h2&gt;

&lt;p&gt;The main input is &lt;code&gt;searchQueries&lt;/code&gt;: one search per keyword, matched against the legal name and the trade name. A company is kept only if every word of the keyword appears in the two names taken together, ignoring case and accents, so &lt;code&gt;seguranca eletronica&lt;/code&gt; also matches &lt;code&gt;SEGURANÇA ELETRÔNICA&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Two inputs set the scope:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;state&lt;/code&gt;: a two-letter code (&lt;code&gt;SP&lt;/code&gt;, &lt;code&gt;RJ&lt;/code&gt;, &lt;code&gt;MG&lt;/code&gt;, &lt;code&gt;PR&lt;/code&gt;, ...) or &lt;code&gt;ALL&lt;/code&gt; for nationwide. Default &lt;code&gt;SP&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;status&lt;/code&gt;: &lt;code&gt;ATIVA&lt;/code&gt; (active), &lt;code&gt;BAIXADA&lt;/code&gt; (closed) or &lt;code&gt;ALL&lt;/code&gt;. Default &lt;code&gt;ATIVA&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;maxItems&lt;/code&gt; (1 to 5,000, default 50) caps the rows saved across all keywords.&lt;/p&gt;

&lt;p&gt;Here is the setup. It searches &lt;code&gt;tecnologia&lt;/code&gt; among active companies in São Paulo state and saves at most 5 rows, the same input as the sample 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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;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="c1"&gt;# 1. Initialize ApifyClient with the token from the environment
&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="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;APIFY_API_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# 2. Define the search: active companies in SP whose name contains "tecnologia"
&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;tecnologia&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;state&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;SP&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ATIVA&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;maxItems&lt;/span&gt;&lt;span class="sh"&gt;"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; a keyword matches names, not activities. To find companies by what they do, combine a short keyword with &lt;code&gt;cnaeCode&lt;/code&gt; (Step 3).&lt;/p&gt;

&lt;p&gt;No proxy setting is needed: by default the Actor connects directly, and a direct connection returned real rows in the test run on 2026-10-24.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Add optional filters
&lt;/h2&gt;

&lt;p&gt;These inputs go into the search itself, and state, status and capital are checked again on each finished row:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;What it keeps&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;minCapital&lt;/code&gt; / &lt;code&gt;maxCapital&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;integer&lt;/td&gt;
&lt;td&gt;Companies whose registered share capital in reais is inside the band. Rows without a capital figure are dropped when either is set.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cnaeCode&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;Companies whose primary activity is this 7-digit CNAE code, for example &lt;code&gt;6201501&lt;/code&gt; (custom software development). Non-digits are stripped, so &lt;code&gt;6201-5/01&lt;/code&gt; works too.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;onlyMatriz&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;boolean&lt;/td&gt;
&lt;td&gt;Headquarters only; branches (filiais) are left out.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three combinations that work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Established IT firms in Rio:&lt;/strong&gt; &lt;code&gt;searchQueries: ["tecnologia"]&lt;/code&gt;, &lt;code&gt;state: "RJ"&lt;/code&gt;, &lt;code&gt;minCapital: 100000&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Closed logistics companies nationwide:&lt;/strong&gt; &lt;code&gt;searchQueries: ["logistica"]&lt;/code&gt;, &lt;code&gt;state: "ALL"&lt;/code&gt;, &lt;code&gt;status: "BAIXADA"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Software headquarters in Minas Gerais:&lt;/strong&gt; &lt;code&gt;searchQueries: ["sistemas"]&lt;/code&gt;, &lt;code&gt;state: "MG"&lt;/code&gt;, &lt;code&gt;cnaeCode: "6201501"&lt;/code&gt;, &lt;code&gt;onlyMatriz: true&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;code&gt;state&lt;/code&gt; and &lt;code&gt;status&lt;/code&gt; only accept the listed values; anything else is refused before the run starts. Maranhão (&lt;code&gt;MA&lt;/code&gt;) is not in the state list: use &lt;code&gt;ALL&lt;/code&gt; and filter &lt;code&gt;state&lt;/code&gt; in your own code.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 4: Run the Actor
&lt;/h2&gt;

&lt;p&gt;Now start the run with &lt;code&gt;client.actor("reventadata/cnpj-brasil-scraper").call(run_input=run_input)&lt;/code&gt;. The call starts the Actor on Apify and waits for it to finish before returning the 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="c1"&gt;# 3. Start the Actor run and wait for it to finish
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Starting CNPJ search...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;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;reventadata/cnpj-brasil-scraper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SUCCEEDED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Run did not succeed (status: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;).&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 4. Fetch the saved company records
&lt;/span&gt;&lt;span class="n"&gt;items&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;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;default_dataset_id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;list_items&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Retrieved &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; companies.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behind the scenes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Actor sends your keyword and filters to Casa dos Dados' public company search and reads the results in pages of 20.&lt;/li&gt;
&lt;li&gt;For each match, it looks up the CNPJ's registry details on minhareceita.org: opening date, CNAE, capital, size, tax flags and address.&lt;/li&gt;
&lt;li&gt;It drops companies already saved under an earlier keyword, applies the checks, and stops at &lt;code&gt;maxItems&lt;/code&gt; or when the search runs dry.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 5: View and download results
&lt;/h2&gt;

&lt;p&gt;Loop over the rows to print the parts you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cnpjFormatted&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;  &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;legalName&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Trade name: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;tradeName&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;none&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  CNAE: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cnaeCode&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cnaeDescription&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  City: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;city&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;state&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Share capital (BRL): &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;shareCapital&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is one row from the local test run dated 2026-10-24, exactly as the Actor saved it:&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;"cnpj"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"97552676000120"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cnpjFormatted"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"97.552.676/0001-20"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"legalName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"H&amp;amp;M TECNOLOGIA DA INFORMACAO LTDA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tradeName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MASSIMUS CONSULTING AND TRAINING"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ATIVA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"openingDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2011-07-05"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cnaeCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"8599603"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cnaeDescription"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Treinamento em informática"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"shareCapital"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;20000.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"legalNature"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sociedade Empresária Limitada"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"companySize"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MICRO EMPRESA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"isSimplesNacional"&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;"isMei"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"isMatriz"&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;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Barueri"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"state"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SP"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"neighborhood"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Alphaville Centro Industrial E Empresarial/Alphav"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"street"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Rio Negro, 503"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"zipCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"06454000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"matchedQuery"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tecnologia"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scrapedAt"&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-10-24T18:07:59.445160+00:00"&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;Apify datasets export as JSON, CSV, XML, Excel, HTML table, RSS or JSONL.&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding your results
&lt;/h2&gt;

&lt;p&gt;The fields that matter most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cnpj&lt;/code&gt; / &lt;code&gt;cnpjFormatted&lt;/code&gt;: the 14 digits, and the same number as &lt;code&gt;XX.XXX.XXX/XXXX-XX&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;legalName&lt;/code&gt; / &lt;code&gt;tradeName&lt;/code&gt;: razão social and nome fantasia. In the five sample rows, 3 had no trade name (&lt;code&gt;null&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;status&lt;/code&gt;: &lt;code&gt;ATIVA&lt;/code&gt; or &lt;code&gt;BAIXADA&lt;/code&gt;; with &lt;code&gt;status: "ALL"&lt;/code&gt; other registry statuses such as &lt;code&gt;INAPTA&lt;/code&gt; or &lt;code&gt;SUSPENSA&lt;/code&gt; can appear.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cnaeCode&lt;/code&gt; / &lt;code&gt;cnaeDescription&lt;/code&gt;: the primary activity. The five sample rows had five different codes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;shareCapital&lt;/code&gt;: registered capital in reais, from 1,000 to 150,000 across the sample.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;companySize&lt;/code&gt;: &lt;code&gt;MEI&lt;/code&gt;, &lt;code&gt;MICRO EMPRESA&lt;/code&gt;, &lt;code&gt;EMPRESA DE PEQUENO PORTE&lt;/code&gt; or &lt;code&gt;DEMAIS&lt;/code&gt; (other). &lt;code&gt;DEMAIS&lt;/code&gt; is also what the Actor writes when the registry lookup gives no size.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;isSimplesNacional&lt;/code&gt;, &lt;code&gt;isMei&lt;/code&gt;: tax-regime flags. &lt;code&gt;isMatriz&lt;/code&gt;: true for a headquarters, false for a branch.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;openingDate&lt;/code&gt;: the registration start date as &lt;code&gt;YYYY-MM-DD&lt;/code&gt;. All five sample rows opened in 2011.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;city&lt;/code&gt;, &lt;code&gt;neighborhood&lt;/code&gt;, &lt;code&gt;street&lt;/code&gt;, &lt;code&gt;zipCode&lt;/code&gt;: the registered address; &lt;code&gt;street&lt;/code&gt; joins the street name and number, and was null in one sample row.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;matchedQuery&lt;/code&gt;: which keyword produced the row.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Pro tips
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Search names, filter activities.&lt;/strong&gt; The keyword only looks at company names. One sample row had "TECNOLOGIA" in its name and an equipment-installation CNAE, so add &lt;code&gt;cnaeCode&lt;/code&gt; when the activity matters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use short, distinctive keywords.&lt;/strong&gt; Every word must appear in a name, so &lt;code&gt;tecnologia sistemas&lt;/code&gt; keeps fewer companies than &lt;code&gt;tecnologia&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch keywords in one run.&lt;/strong&gt; Put several in &lt;code&gt;searchQueries&lt;/code&gt;; a company saved under one keyword is not saved again under the next.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bound by capital, not just count.&lt;/strong&gt; &lt;code&gt;minCapital&lt;/code&gt; and &lt;code&gt;maxCapital&lt;/code&gt; are a quick proxy for company size when building lead lists.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start small.&lt;/strong&gt; Keep &lt;code&gt;maxItems: 5&lt;/code&gt; until your downstream code handles the fields, then raise it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automate the hand-off.&lt;/strong&gt; A webhook on &lt;code&gt;ACTOR.RUN.SUCCEEDED&lt;/code&gt; hands your code the finished run, so a scheduled search can land in a CRM or a sheet without polling. Key your table on &lt;code&gt;cnpj&lt;/code&gt;: it identifies the company, so a rerun can update rows instead of duplicating them.&lt;/li&gt;
&lt;/ol&gt;




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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero rows:&lt;/strong&gt; a run that is blocked or cannot read a search page ends FAILED. A search that loads normally but returns nothing your filters keep ends SUCCEEDED with an empty dataset and a status message saying so. Loosen the keyword, the state or the capital band.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fewer rows than expected:&lt;/strong&gt; read the summary line near the end of the log, &lt;code&gt;Run finished. Total companies pushed: N. Rejection breakdown: {...}&lt;/code&gt;. It counts drops such as &lt;code&gt;keyword_mismatch&lt;/code&gt;, &lt;code&gt;state_mismatch&lt;/code&gt; and &lt;code&gt;capital_out_of_range&lt;/code&gt;. From Python: &lt;code&gt;client.log(run.id).get()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fields are null:&lt;/strong&gt; when the registry lookup for a CNPJ fails, the row keeps the search fields only (&lt;code&gt;companySize&lt;/code&gt; falls back to &lt;code&gt;DEMAIS&lt;/code&gt;); with a specific &lt;code&gt;state&lt;/code&gt;, such rows are dropped.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Input refused:&lt;/strong&gt; a &lt;code&gt;state&lt;/code&gt; or &lt;code&gt;status&lt;/code&gt; value outside the list.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For help, use the Actor's &lt;a href="https://apify.com/reventadata/cnpj-brasil-scraper" rel="noopener noreferrer"&gt;Store page&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pricing and next steps
&lt;/h2&gt;

&lt;p&gt;For current pricing and details, see the &lt;a href="https://apify.com/reventadata/cnpj-brasil-scraper" rel="noopener noreferrer"&gt;Store page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To repeat a search, save the input as a task and add an Apify schedule, which runs it on a cron expression (&lt;code&gt;0 8 * * *&lt;/code&gt; is every day at 8 AM). To react when a run finishes, add a webhook on &lt;code&gt;ACTOR.RUN.SUCCEEDED&lt;/code&gt;; its payload carries the run object, including &lt;code&gt;defaultDatasetId&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://apify.com/reventadata/cnpj-brasil-scraper" rel="noopener noreferrer"&gt;CNPJ Brasil Scraper on Apify Store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.apify.com/api/client/python/" rel="noopener noreferrer"&gt;Apify Python client documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which sectors or states are you planning to map? Drop a comment! 💬&lt;/p&gt;

</description>
      <category>python</category>
      <category>webscraping</category>
      <category>apify</category>
      <category>automation</category>
    </item>
    <item>
      <title>How to Scrape Imovirtual Property Listings in Portugal with Python</title>
      <dc:creator>ReventaData</dc:creator>
      <pubDate>Mon, 02 Nov 2026 08:30:18 +0000</pubDate>
      <link>https://dev.to/reventadata/how-to-scrape-imovirtual-property-listings-in-portugal-with-python-3mnn</link>
      <guid>https://dev.to/reventadata/how-to-scrape-imovirtual-property-listings-in-portugal-with-python-3mnn</guid>
      <description>&lt;p&gt;By the end of this tutorial, you will have a short Python script that turns an Imovirtual search into structured rows: listing title, asking price in euros, price per m², area, rooms, floor, street, parish, council and district, the agency or developer behind the ad, and when it was listed.&lt;/p&gt;

&lt;p&gt;Imovirtual (imovirtual.com) is a Portuguese real-estate portal for homes, land and commercial property, for sale or for rent.&lt;/p&gt;

&lt;p&gt;In this guide, we use Python and the Apify Actor &lt;strong&gt;Imovirtual Scraper&lt;/strong&gt; (&lt;code&gt;reventadata/imovirtual-scraper&lt;/code&gt;). You will configure a search, run the Actor and read the rows. The sample row below is a sample from a capture dated 2026-10-20, parsed with the Actor's own parser.&lt;/p&gt;

&lt;p&gt;⏱️ &lt;strong&gt;Time estimate:&lt;/strong&gt; one sitting: install one package, set one token, run three short Python blocks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To follow this tutorial, you will need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Python 3.11+&lt;/strong&gt; (&lt;code&gt;apify-client&lt;/code&gt; 3.3.0 requires it).&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Apify API client&lt;/strong&gt; for Python.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;Apify account&lt;/strong&gt; and its API token, which sits on the &lt;strong&gt;API &amp;amp; Integrations&lt;/strong&gt; page in Apify Console.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Install the client:&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; &lt;span class="s2"&gt;"apify-client~=3.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code reads the token from an environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;APIFY_API_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your_apify_token_here"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What you'll achieve
&lt;/h2&gt;

&lt;p&gt;You will turn one Imovirtual search into one row per listing. Each row carries the listing &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;price&lt;/code&gt; with &lt;code&gt;currency&lt;/code&gt;, &lt;code&gt;pricePerSquareMeter&lt;/code&gt;, &lt;code&gt;areaM2&lt;/code&gt;, &lt;code&gt;rooms&lt;/code&gt; and &lt;code&gt;roomsLabel&lt;/code&gt;, &lt;code&gt;floor&lt;/code&gt;, the address levels (&lt;code&gt;street&lt;/code&gt;, &lt;code&gt;neighborhood&lt;/code&gt;, &lt;code&gt;parish&lt;/code&gt;, &lt;code&gt;council&lt;/code&gt;, &lt;code&gt;district&lt;/code&gt;), &lt;code&gt;agencyName&lt;/code&gt; and &lt;code&gt;agencyType&lt;/code&gt;, &lt;code&gt;isPrivateOwner&lt;/code&gt;, &lt;code&gt;createdAt&lt;/code&gt; and &lt;code&gt;pushedUpAt&lt;/code&gt;, and one &lt;code&gt;imageUrl&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A row carries no phone number or e-mail address. The ad &lt;code&gt;url&lt;/code&gt; leads to the full listing page.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Example use case:&lt;/strong&gt; Suppose you want two-bedroom flats for sale in Lisbon city under 400,000 EUR. You would set &lt;code&gt;propertyType: "apartamento"&lt;/code&gt;, &lt;code&gt;location: "lisboa/lisboa"&lt;/code&gt;, &lt;code&gt;typology: "t2"&lt;/code&gt; and &lt;code&gt;maxPrice: 400000&lt;/code&gt;, and Imovirtual itself applies the filters before a single row comes back.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Access Imovirtual Scraper
&lt;/h2&gt;

&lt;p&gt;Go to the &lt;a href="https://apify.com/reventadata/imovirtual-scraper" rel="noopener noreferrer"&gt;Imovirtual Scraper&lt;/a&gt; page on Apify Store. The README lists every input and output field. In this tutorial we drive the Actor from Python, so everything after this step happens in code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Configure the search
&lt;/h2&gt;

&lt;p&gt;Three inputs define the search:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;transaction&lt;/code&gt;: &lt;code&gt;buy&lt;/code&gt; or &lt;code&gt;rent&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;propertyType&lt;/code&gt;: &lt;code&gt;apartamento&lt;/code&gt; (apartment), &lt;code&gt;moradia&lt;/code&gt; (house), &lt;code&gt;terreno&lt;/code&gt; (land), &lt;code&gt;imoveis-comerciais&lt;/code&gt; (commercial), &lt;code&gt;armazens&lt;/code&gt; (warehouse) or &lt;code&gt;garagem&lt;/code&gt; (garage).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;location&lt;/code&gt;: Imovirtual's own location slug, as it appears in a search URL: a district such as &lt;code&gt;lisboa&lt;/code&gt; or &lt;code&gt;porto&lt;/code&gt;, a council such as &lt;code&gt;lisboa/lisboa&lt;/code&gt; or &lt;code&gt;porto/porto&lt;/code&gt;, or &lt;code&gt;todo-o-pais&lt;/code&gt; for the whole country.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To find a slug, search on imovirtual.com and copy the part of the URL after the property type: &lt;code&gt;lisboa/lisboa&lt;/code&gt; from &lt;code&gt;/pt/resultados/comprar/apartamento/lisboa/lisboa&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Each result page holds 36 listings. &lt;code&gt;maxPages&lt;/code&gt; caps the pages read, and &lt;code&gt;maxItems&lt;/code&gt; (default 1000) caps the rows saved.&lt;/p&gt;

&lt;p&gt;Here is the setup. It searches apartments for sale in Lisboa district and reads one result page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&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="c1"&gt;# 1. Initialize ApifyClient with the token from the environment
&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="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;APIFY_API_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# 2. Define the search: apartments for sale in Lisboa district, one result page
&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;transaction&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&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;propertyType&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;apartamento&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;location&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lisboa&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;maxPages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; &lt;code&gt;lisboa&lt;/code&gt; is the whole district, not the city. In the capture, page 1 of this search spanned 8 councils, from Lisboa itself to Sintra, Loures and Vila Franca de Xira. Use &lt;code&gt;lisboa/lisboa&lt;/code&gt; for the city.&lt;/p&gt;

&lt;p&gt;No proxy setting is needed: the proxy is off by default, and plain requests with no proxy reached imovirtual.com when the Actor was tested on 2026-10-20.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Narrow the search
&lt;/h2&gt;

&lt;p&gt;These inputs go into the search URL, so Imovirtual filters before anything is fetched:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;typology&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;t0&lt;/code&gt; to &lt;code&gt;t5&lt;/code&gt;: the Portuguese bedroom count.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;minPrice&lt;/code&gt; / &lt;code&gt;maxPrice&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;integer&lt;/td&gt;
&lt;td&gt;Price band in EUR.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;minArea&lt;/code&gt; / &lt;code&gt;maxArea&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;integer&lt;/td&gt;
&lt;td&gt;Area band in m².&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ownerType&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;any&lt;/code&gt;, or &lt;code&gt;private&lt;/code&gt; for private owners only (no agencies or developers).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sortBy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;relevance&lt;/code&gt; (the site's default), &lt;code&gt;priceAsc&lt;/code&gt; (cheapest first) or &lt;code&gt;newest&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;An empty numeric filter is left out of the request, never sent as 0.&lt;/p&gt;

&lt;p&gt;Three combinations that work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lisbon city T2 flats under 400,000 EUR:&lt;/strong&gt; &lt;code&gt;location: "lisboa/lisboa"&lt;/code&gt;, &lt;code&gt;typology: "t2"&lt;/code&gt;, &lt;code&gt;maxPrice: 400000&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rentals in Porto, cheapest first:&lt;/strong&gt; &lt;code&gt;transaction: "rent"&lt;/code&gt;, &lt;code&gt;location: "porto/porto"&lt;/code&gt;, &lt;code&gt;sortBy: "priceAsc"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Houses sold by their owners, nationwide:&lt;/strong&gt; &lt;code&gt;propertyType: "moradia"&lt;/code&gt;, &lt;code&gt;location: "todo-o-pais"&lt;/code&gt;, &lt;code&gt;ownerType: "private"&lt;/code&gt;, &lt;code&gt;sortBy: "newest"&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ A &lt;code&gt;typology&lt;/code&gt;, &lt;code&gt;sortBy&lt;/code&gt;, &lt;code&gt;ownerType&lt;/code&gt;, &lt;code&gt;transaction&lt;/code&gt; or &lt;code&gt;propertyType&lt;/code&gt; outside its list is refused before the run starts. A &lt;code&gt;location&lt;/code&gt; slug Imovirtual does not know stops the run with an error at its first page.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 4: Run the Actor
&lt;/h2&gt;

&lt;p&gt;Now start the run with &lt;code&gt;client.actor("reventadata/imovirtual-scraper").call(run_input=run_input)&lt;/code&gt;. The call starts the Actor on Apify and waits for it to finish before returning the 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="c1"&gt;# 3. Start the Actor run and wait for it to finish
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Starting Imovirtual extraction...&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;reventadata/imovirtual-scraper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SUCCEEDED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Run did not succeed (status: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;).&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 4. Fetch the saved listings
&lt;/span&gt;&lt;span class="n"&gt;items&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;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;default_dataset_id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;list_items&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Retrieved &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; listings.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behind the scenes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Actor builds the search URL (&lt;code&gt;/pt/resultados/comprar/apartamento/lisboa&lt;/code&gt; here, plus &lt;code&gt;?page=N&lt;/code&gt; from page 2 on).&lt;/li&gt;
&lt;li&gt;It reads the listing data Imovirtual embeds in its own search page, so no browser is involved, and turns each listing into one row.&lt;/li&gt;
&lt;li&gt;It stops at &lt;code&gt;maxItems&lt;/code&gt;, at &lt;code&gt;maxPages&lt;/code&gt;, or at the last page the site reports, whichever comes first. The premium tile Imovirtual repeats across pages is saved once.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 5: View and download results
&lt;/h2&gt;

&lt;p&gt;Loop over the rows to print the parts you need:&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;seen_urls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Skip a second id that points to a listing already printed
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;seen_urls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;
    &lt;span class="n"&gt;seen_urls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&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;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Price: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; EUR&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Price: not published&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Per m2: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pricePerSquareMeter&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; EUR, area &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;areaM2&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; m2&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Rooms: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;roomsLabel&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, floor &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;floor&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Where: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;parish&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;council&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Seller: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;agencyName&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;private owner&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is one row, a sample from a capture dated 2026-10-20 (page 1 of the search above) parsed with the Actor's own parser:&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"19316271"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url"&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://www.imovirtual.com/pt/anuncio/apartamento-t3-a-venda-na-praca-das-novas-nacoes-arroios-ID1j32L"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Apartamento T3 à venda na Praça das Novas Nações, Arroios"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"propertyType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FLAT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"transaction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SELL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;555000.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"pricePerSquareMeter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;6686.75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"priceFromPerSquareMeter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"areaM2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;83.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"rooms"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"roomsLabel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FOUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"floor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SECOND"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"street"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Praça das Novas Nações"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"neighborhood"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Anjos"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"parish"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Arroios"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"council"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Lisboa"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"district"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Lisboa"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"agencyName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Century 21 CasaBela"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"agencyType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AGENCY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"advertiserName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Century 21 CasaBela"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"contactNames"&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;"Sofia Dias"&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;"isPrivateOwner"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"isPromoted"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"isExclusiveOffer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"createdAt"&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-10-20T18:14:18+00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"pushedUpAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"imageUrl"&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://ireland.apollo.olxcdn.com/v1/files/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmbiI6Ijd0a3lyMXJxdTdnYjMtRUNPU1lTVEVNIiwidyI6W3siZm4iOiI2OW5scGE3ZWNxbTcxLUFQVCIsInMiOiIxNiIsImEiOiIwIiwicCI6IjEwLC0xMCJ9XX0.YzJy2krk122zcGgyU5_lDEsJbUD59FTBaXjmIhte5Qk/image;s=1280x1024;q=80"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"searchUrl"&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://www.imovirtual.com/pt/resultados/comprar/apartamento/lisboa"&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;Apify datasets export as JSON, CSV, XML, Excel, HTML table, RSS or JSONL.&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding your results
&lt;/h2&gt;

&lt;p&gt;The fields that matter most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;price&lt;/code&gt;, &lt;code&gt;currency&lt;/code&gt;: the asking price in EUR, or the monthly rent on rent searches. Development listings publish no total price: &lt;code&gt;price&lt;/code&gt; is null and &lt;code&gt;priceFromPerSquareMeter&lt;/code&gt; holds the site's "from" price per m².&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pricePerSquareMeter&lt;/code&gt;, &lt;code&gt;areaM2&lt;/code&gt;: as the site publishes them. In the 37-row capture, prices ran from 355,000 to 9,000,000 EUR and price per m² from 1,446.95 to 6,875.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rooms&lt;/code&gt;, &lt;code&gt;roomsLabel&lt;/code&gt;: rooms, not bedrooms. The sample's title says T3 and its &lt;code&gt;roomsLabel&lt;/code&gt; is &lt;code&gt;FOUR&lt;/code&gt;: three bedrooms plus the living room. Imovirtual's &lt;code&gt;MORE&lt;/code&gt; has no number, so &lt;code&gt;rooms&lt;/code&gt; is null there (4 rows in the capture).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;floor&lt;/code&gt;: the site's value (&lt;code&gt;GROUND&lt;/code&gt;, &lt;code&gt;SECOND&lt;/code&gt;, ...); null on 10 of the 37 captured rows.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;agencyType&lt;/code&gt;: &lt;code&gt;AGENCY&lt;/code&gt; or &lt;code&gt;DEVELOPER&lt;/code&gt;, null for a private owner (31, 5 and 1 in the capture).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;createdAt&lt;/code&gt;, &lt;code&gt;pushedUpAt&lt;/code&gt;: first listed and last bumped. 14 of the 37 captured rows were first listed on the capture day.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;searchUrl&lt;/code&gt;: the page-1 search URL the row came from.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Pro tips
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Deduplicate on &lt;code&gt;url&lt;/code&gt;.&lt;/strong&gt; The Actor removes repeated ids, but in the capture one listing also appeared under a second id (&lt;code&gt;9000062240&lt;/code&gt;) with the same &lt;code&gt;url&lt;/code&gt;, no image and a &lt;code&gt;createdAt&lt;/code&gt; of &lt;code&gt;1999-02-29 00:00:01&lt;/code&gt;. The loop above keys on &lt;code&gt;url&lt;/code&gt; for that reason.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parse dates defensively.&lt;/strong&gt; That same &lt;code&gt;createdAt&lt;/code&gt; is not a real date. Wrap date parsing in a try/except instead of letting one row stop a pipeline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filter on the site, not in pandas.&lt;/strong&gt; Price, area, typology and owner type go into the URL, so you read fewer pages for the same rows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use council slugs.&lt;/strong&gt; &lt;code&gt;lisboa/lisboa&lt;/code&gt; instead of &lt;code&gt;lisboa&lt;/code&gt; keeps the suburbs out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep sale and rent apart.&lt;/strong&gt; On a rent search &lt;code&gt;price&lt;/code&gt; is the monthly rent, so a sale and a rent dataset in one column mix two different numbers. Run them as separate searches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start small.&lt;/strong&gt; Keep &lt;code&gt;maxPages: 1&lt;/code&gt; until your downstream code handles the fields, then raise it or leave it out to walk every page the site reports.&lt;/li&gt;
&lt;/ol&gt;




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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero rows:&lt;/strong&gt; a run that is blocked, cannot read a page or gets a wrong slug ends FAILED; an over-strict filter ends SUCCEEDED with an empty dataset and a status message saying so. Widen the price or area band, or drop &lt;code&gt;ownerType: "private"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run stops at its first page with a 404 error:&lt;/strong&gt; the &lt;code&gt;location&lt;/code&gt; slug does not exist on Imovirtual. Copy it from a real imovirtual.com search URL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Input refused before the run starts:&lt;/strong&gt; a value outside a select list, such as &lt;code&gt;typology: "t6"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fewer rows than expected:&lt;/strong&gt; read the run log. Near the end it logs &lt;code&gt;Skipped N: ...&lt;/code&gt; lines and &lt;code&gt;Pushed N row(s).&lt;/code&gt;. From Python: &lt;code&gt;client.log(run.id).get()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For help, use the Actor's &lt;a href="https://apify.com/reventadata/imovirtual-scraper" rel="noopener noreferrer"&gt;Store page&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pricing and next steps
&lt;/h2&gt;

&lt;p&gt;For current pricing and details, see the &lt;a href="https://apify.com/reventadata/imovirtual-scraper" rel="noopener noreferrer"&gt;Store page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To repeat a search, save the input as a task and add an Apify schedule, which runs an Actor or task on a cron expression (&lt;code&gt;0 8 * * *&lt;/code&gt; is every day at 8 AM). Pair it with &lt;code&gt;sortBy: "newest"&lt;/code&gt;. To react when a run finishes, add a webhook on &lt;code&gt;ACTOR.RUN.SUCCEEDED&lt;/code&gt;; its payload carries the run object, including &lt;code&gt;defaultDatasetId&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://apify.com/reventadata/imovirtual-scraper" rel="noopener noreferrer"&gt;Imovirtual Scraper on Apify Store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.apify.com/api/client/python/docs" rel="noopener noreferrer"&gt;Apify Python client documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which part of Portugal are you planning to track on Imovirtual? Drop a comment! 💬&lt;/p&gt;

</description>
      <category>python</category>
      <category>webscraping</category>
      <category>apify</category>
      <category>realestate</category>
    </item>
  </channel>
</rss>
