<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[ReventaData Blog]]></title><description><![CDATA[Turn messy second-hand marketplaces into clean, structured data feeds. Practical tutorials on web scraping with Python, reverse-engineering APIs, and Apify scrapers.]]></description><link>https://reventadata.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Tue, 20 Oct 2026 19:31:08 GMT</lastBuildDate><atom:link href="https://reventadata.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Complete Guide: How to Scrape Real Estate & Car Listings from OLX Brazil Using OLX Brazil Scraper]]></title><description><![CDATA[A complete developer guide to extracting real estate, vehicle listings, and pricing data from olx.com.br using the OLX Brazil Scraper on Apify.]]></description><link>https://reventadata.hashnode.dev/complete-guide-how-to-scrape-real-estate-car-listings-from-olx-brazil-using-olx-brazil-scraper</link><guid isPermaLink="true">https://reventadata.hashnode.dev/complete-guide-how-to-scrape-real-estate-car-listings-from-olx-brazil-using-olx-brazil-scraper</guid><category><![CDATA[web scraping]]></category><category><![CDATA[Python]]></category><category><![CDATA[api]]></category><category><![CDATA[automation]]></category><category><![CDATA[apify]]></category><dc:creator><![CDATA[ReventaData]]></dc:creator><pubDate>Sun, 11 Oct 2026 18:01:23 GMT</pubDate><content:encoded><![CDATA[<h2>1. Introduction</h2>
<p>Extracting web data from Latin America's largest classifieds marketplace—<strong>OLX Brazil (<a href="https://www.olx.com.br">olx.com.br</a>)</strong>—is one of the most common requirements for e-commerce arbitrage, real estate valuation models, and automotive market analysis. However, it is also notoriously difficult to automate reliably from scratch.</p>
<p>Modern OLX Brazil operates on a Next.js App Router architecture. It does not expose a clean, public REST API for search listings, strictly geo-fences search traffic, and deploys aggressive anti-bot defenses that serve instant HTTP 403 or ~5.8 KB challenge pages to standard HTTP clients, headless browsers, and datacenter proxy networks. Furthermore, OLX's search results feature dynamic, non-standard HTML structures and silent "phantom fallbacks" that cause brittle home-brewed scrapers to fail silently or corrupt datasets with wrong categories.</p>
<p>In this comprehensive guide, you will learn <strong>how to scrape OLX Brazil</strong> at scale using the production-ready <strong>OLX Brazil Scraper</strong> on Apify. We will cover the entire workflow: from configuring URL paths and filtering typed property/vehicle attributes to running automated batch jobs via the Apify Python SDK.</p>
<ul>
<li><strong>Target Audience</strong>: Data engineers, Python developers, growth hackers, and market researchers.</li>
<li><strong>Prerequisites</strong>: A web browser and a free Apify account. Minimal Python knowledge if integrating via API.</li>
<li><strong>⏱️ Estimated Time</strong>: 10–15 minutes to configure and complete your first production scrape.</li>
</ul>
<hr />
<h2>2. TL;DR</h2>
<ul>
<li><strong>The Problem</strong>: Scraping <code>olx.com.br</code> directly fails due to Next.js App Router client rendering, hard 100-page pagination clamps, and strict bot mitigation that bans standard residential and datacenter proxies.</li>
<li><strong>The Solution</strong>: Use the <a href="https://apify.com/reventadata/olx-scraper">OLX Brazil Scraper on Apify Store</a>—a cloud Actor that uses Apify Unblocker, parses search cards directly into typed schemas (m², bedrooms, mileage, year), filters phantom ads, and exports clean CSV, JSON, or Excel.</li>
<li><strong>Cost Model</strong>: 100% pay-per-event at <strong>$0.001 per dataset row</strong> (\(1.00 per 1,000 items) + \)0.00005 per run start. No monthly subscriptions.</li>
</ul>
<hr />
<h2>3. Prerequisites &amp; Setup</h2>
<p>Before running the Actor, ensure you have set up your Apify environment:</p>
<ol>
<li><strong>Create an Apify Account</strong>:<ul>
<li>Navigate to <a href="https://console.apify.com/sign-up">Apify Sign Up</a>.</li>
<li>Sign up using your GitHub or Google account. The free tier includes <strong>$5.00 in monthly platform usage credits</strong>, which is more than enough to scrape thousands of items during development.</li>
</ul>
</li>
<li><strong>What is the Apify Console?</strong>:<ul>
<li>The <strong>Apify Console</strong> is the centralized cloud dashboard where you configure Actor inputs, monitor execution logs in real-time, view storage datasets, and manage scheduled cron jobs.</li>
</ul>
</li>
<li><strong>API Token (Optional for CLI/SDK)</strong>:<ul>
<li>If you plan to automate your runs with Python or Node.js, grab your personal API token from <strong>Console → Settings → Integrations → API tokens</strong>.</li>
</ul>
</li>
</ol>
<hr />
<h2>4. Understanding OLX Brazil Scraper</h2>
<h3>Technical Architecture</h3>
<p>The <a href="https://apify.com/reventadata/olx-scraper">OLX Brazil Scraper</a> is built specifically around the quirks and limitations of the current <code>olx.com.br</code> platform:</p>
<ul>
<li><strong>Generic Path Routing</strong>: Rather than relying on rigid, pre-defined category dropdowns that break whenever OLX reorganizes its taxonomy, the Actor accepts raw URL path segments (e.g., <code>imoveis/aluguel/apartamentos/estado-sp</code>). You copy the path directly from your browser, and the Actor walks the pagination tree.</li>
<li><strong>Typed Field Extraction</strong>: The Actor parses ad chips into typed properties instead of doing lossy free-text guessing:<ul>
<li><em>Real Estate</em>: <code>areaM2</code>, <code>bedrooms</code>, <code>bathrooms</code>, <code>parkingSpaces</code>.</li>
<li><em>Automotive</em>: <code>mileageKm</code>, <code>color</code>, <code>engineSize</code>, <code>bodyType</code>, <code>year</code>.</li>
<li><em>Catch-All Attributes</em>: Every remaining unstructured badge (e.g., fuel type, transmission, condo fee <code>condominio</code>, property tax <code>IPTU</code>) is normalized into an <code>attributes</code> dictionary.</li>
</ul>
</li>
<li><strong>The "Phantom Fallback" Defense</strong>: When an OLX search keyword yields zero results, the website silently renders up to 8 unrelated "Mais recentes" (Most Recent) recommendations under the exact same CSS markup as genuine matches. Brittle scrapers ingest these as false positives. The OLX Brazil Scraper inspects the page's canonical <code>0 - 0 de 0 resultados</code> indicator and terminates safely with a clean exit.</li>
<li><strong>Apify Unblocker Integration</strong>: Standard datacenter and residential proxy pools fail against OLX Brazil with 100% block rates. The Actor pre-configures Apify Unblocker to bypass Akamai and Cloudflare challenge screens seamlessly.</li>
<li><strong>Privacy by Design</strong>: The Actor extracts only public search card metadata. Private seller telephone numbers, email addresses, and personal IDs are never collected.</li>
</ul>
<hr />
<h2>5. Step-by-Step Guide to Using the Actor</h2>
<h3>Step 1: Accessing the Actor</h3>
<ol>
<li>Navigate to the official store page: <a href="https://apify.com/reventadata/olx-scraper">OLX Brazil Scraper — Any Category, Any Keyword</a>.</li>
<li>Review the technical specification and pricing model ($1.00 / 1,000 items).</li>
<li>Click the blue <strong>Try for free</strong> button.</li>
<li>You will be redirected to the <strong>Apify Console</strong> with the Actor's input interface pre-loaded.</li>
</ol>


<hr />
<h3>Step 2: Configuring Input Parameters</h3>
<p>The input schema is designed to mirror native OLX navigation. Here are the core fields:</p>
<ul>
<li><strong><code>categoryPath</code> (string)</strong>: The URL path segment from OLX.<ul>
<li><em>Nationwide Cars</em>: <code>autos-e-pecas/carros-vans-e-utilitarios</code></li>
<li><em>São Paulo Real Estate</em>: <code>imoveis/venda/apartamentos/estado-sp/sao-paulo-e-regiao</code></li>
<li><em>Nationwide Browse</em>: Leave completely blank to search all of Brazil.</li>
</ul>
</li>
<li><strong><code>searchQueries</code> (array of strings)</strong>: Optional keywords. Each keyword narrows results <em>within</em> your specified <code>categoryPath</code> without overriding it.</li>
<li><strong><code>minPrice</code> / <code>maxPrice</code> (integer)</strong>: Price boundaries in Brazilian Real (<code>BRL</code>). When left unset, free listings (<code>R$ 0</code>) and unpriced items are safely preserved.</li>
<li><strong><code>sortBy</code> (enum)</strong>: <code>relevance</code> (default), <code>newest</code>, <code>priceAsc</code>, or <code>priceDesc</code>.</li>
</ul>
<h4>Example Configuration A: Used SUVs in São Paulo</h4>
<pre><code class="language-json">{
  "categoryPath": "autos-e-pecas/carros-vans-e-utilitarios/estado-sp",
  "searchQueries": ["renegade", "compass"],
  "minPrice": 70000,
  "maxPrice": 120000,
  "sortBy": "priceAsc",
  "maxItems": 150
}
</code></pre>
<h4>Example Configuration B: Rental Apartments in Brasília</h4>
<pre><code class="language-json">{
  "categoryPath": "imoveis/aluguel/apartamentos/estado-df/distrito-federal-e-regiao/brasilia",
  "searchQueries": ["asa sul"],
  "minPrice": 2000,
  "maxPrice": 4500,
  "sortBy": "newest",
  "maxItems": 100
}
</code></pre>


<hr />
<h3>Step 3: Advanced Configuration &amp; Optimization</h3>
<p>Under the configuration form, click <strong>Advanced options</strong> to customize execution constraints:</p>
<ul>
<li><strong><code>minMileageKm</code> / <code>maxMileageKm</code> (integer)</strong>: Bounded vehicle odometer limits (validated on the <code>autos</code> vertical).</li>
<li><strong><code>acceptsTradeOnly</code> (boolean)</strong>: Filters exclusively for sellers open to vehicle trades (<em>"Aceita trocas"</em>).</li>
<li><strong><code>requireKeywordMatch</code> (boolean, default: <code>true</code>)</strong>: Applies a defensive tokenization filter after extraction to ensure every word in your query appears in the ad title.</li>
<li><strong><code>maxPages</code> (integer, default: <code>100</code>)</strong>: Hard ceiling per query.<blockquote>
<p>⚠️ <strong>Platform Constraint</strong>: <code>olx.com.br</code> clamps every search at page 100 (~5,000 listings). Pages 101+ serve byte-identical duplicates of page 100. The Actor enforces this clamp automatically.</p>
</blockquote>
</li>
<li><strong><code>maxItems</code> (integer, default: <code>300</code>)</strong>: Governs maximum records returned. 300 rows finish in ~50 seconds, fitting well within Apify's platform auto-test limits.</li>
</ul>


<hr />
<h3>Step 4: Proxy Configuration</h3>
<p>OLX Brazil uses sophisticated browser profiling and TLS fingerprinting. </p>
<ul>
<li>By default, the Actor sets <code>proxyConfiguration</code> to use <strong>Apify Unblocker</strong> (<code>apifyProxyGroups: ["UNBLOCKER"]</code>).</li>
<li><strong>Do not disable this setting</strong>: Standard datacenter and residential IPs receive an immediate access denial.</li>
</ul>
<hr />
<h3>Step 5: Running the Actor</h3>
<ol>
<li>In the bottom-right corner of the Console, click <strong>Save &amp; Run</strong> (or <strong>Start</strong>).</li>
<li>The runtime status updates to <strong>Running</strong> 🟡.</li>
<li>The live log terminal will output:<ul>
<li>Initialization with Apify Unblocker.</li>
<li>Target URL construction: <code>https://www.olx.com.br/autos-e-pecas/...&amp;q=renegade</code>.</li>
<li>Page-by-page progress indicators showing rows extracted per batch.</li>
</ul>
</li>
<li>Once completed, the badge switches to <strong>SUCCEEDED</strong> 🟢.</li>
</ol>
<blockquote>
<p>💡 <strong>Background Execution</strong>: Runs execute in isolated cloud containers. You can safely close your browser or disconnect from your network; the job will continue until completion.</p>
</blockquote>


<hr />
<h3>Step 6: Examining the Results</h3>
<p>Click the <strong>Storage</strong> tab (or scroll down to <strong>Dataset</strong>) to inspect your extracted data:</p>
<pre><code class="language-json">{
  "id": "1532323306",
  "title": "Toyota Corolla Cross XRE 2.0 16V Flex AUT 2023",
  "url": "https://df.olx.com.br/distrito-federal-e-regiao/autos-e-pecas/carros-vans-e-utilitarios/toyota-corolla-cross-xre-2-0-16v-flex-aut-2023-1532323306",
  "imageUrl": "https://img.olx.com.br/images/43/430647444372585.jpg",
  "price": 114900,
  "currency": "BRL",
  "location": "Brasília - DF",
  "city": "Brasília",
  "neighbourhood": "Setor Residencial Leste (Planaltina)",
  "state": "DF",
  "postedAt": "2026-09-04T02:09:41Z",
  "category": "Carros, vans e utilitários",
  "mileageKm": 82000,
  "color": "Preto",
  "engineSize": "2.0 - 2.9",
  "bodyType": "SUV",
  "year": 2023,
  "acceptsTrade": false,
  "attributes": {
    "vehicle_brand": "Toyota",
    "vehicle_model": "Corolla Cross XRE 2.0 16V Flex",
    "fuel": "Flex",
    "gearbox": "Automático",
    "doors": "4 portas"
  }
}
</code></pre>


<hr />
<h3>Step 7: Downloading and Exporting Data</h3>
<p>Apify provides one-click export formats:</p>
<ul>
<li><strong>CSV / Excel</strong>: Best for importing into pandas, Google Sheets, or business dashboards.</li>
<li><strong>JSON / JSONL</strong>: Best for feeding downstream microservices, Elasticsearch, or vector databases.</li>
<li><strong>Field Selection</strong>: Click <strong>Select fields</strong> to omit raw columns (such as <code>imageUrl</code> or <code>attributes</code>) if you only need price and location data.</li>
</ul>


<hr />
<h2>6. Working with the API (Python SDK)</h2>
<p>To integrate the scraper into your data engineering pipelines, use the official <code>apify-client</code> Python package.</p>
<h3>Installation</h3>
<pre><code class="language-bash">pip install apify-client
</code></pre>
<h3>Production Python Script with Error Handling</h3>
<pre><code class="language-python">import os
import sys
from itertools import islice
from apify_client import ApifyClient
from apify_client.errors import ApifyApiError

# Load your token from environment variables
APIFY_TOKEN = os.getenv("APIFY_TOKEN")
if not APIFY_TOKEN:
    sys.exit("Error: APIFY_TOKEN environment variable not set.")

client = ApifyClient(APIFY_TOKEN)

run_input = {
    "categoryPath": "autos-e-pecas/carros-vans-e-utilitarios",
    "searchQueries": ["Toyota Hilux"],
    "minPrice": 120000,
    "maxPrice": 220000,
    "maxItems": 100,
    "sortBy": "newest"
}

def format_price(value):
    if value is None:
        return "Sob consulta"
    return f"R$ {value:,.0f}".replace(",", ".")

try:
    print("🚀 Triggering OLX Brazil Scraper on Apify...")
    run = client.actor("reventadata/olx-scraper").call(run_input=run_input)

    status = run.get("status")
    dataset_id = run.get("defaultDatasetId")

    # Defensive check: verify run actually succeeded before reading
    if status != "SUCCEEDED":
        print(f"⚠️ Actor finished with status: {status} (Dataset ID: {dataset_id})")
        sys.exit(1)

    print(f"✅ Run completed successfully! Dataset ID: {dataset_id}")

    # Paginate through extracted dataset items defensively
    dataset = client.dataset(dataset_id)
    items = list(islice(dataset.iterate_items(), 5))

    if not items:
        print("ℹ️ Query returned 0 results matching criteria.")
    else:
        print(f"📦 Showing first {len(items)} listings:")
        for ad in items:
            price_tag = format_price(ad.get("price"))
            location = ", ".join(filter(None, [ad.get("city"), ad.get("state")])) or "Localização não informada"
            year_tag = f" ({ad.get('year')})" if ad.get("year") else ""
            print(f"• [{price_tag}] {ad.get('title', 'Sem título')} | {location}{year_tag}")

except ApifyApiError as e:
    print(f"❌ Apify API Exception: {e}")
except Exception as e:
    print(f"❌ Unexpected Error: {e}")
</code></pre>
<hr />
<h2>7. Advanced Usage Patterns &amp; Automation</h2>
<h3>1. Daily Price Tracking via Scheduled Runs</h3>
<p>Set up a daily cron trigger inside <strong>Apify Console → Schedules</strong>:</p>
<ul>
<li>Schedule: <code>0 8 * * *</code> (Runs every day at 8:00 AM UTC).</li>
<li>Connect the output to a <strong>Webhook</strong> pointing to your Slack channel, Discord, or backend endpoint to receive automated alerts whenever a listing price drops below market value.</li>
</ul>
<h3>2. High-Volume Partitioning (Breaking the 5,000 Item Limit)</h3>
<p>Because OLX hard-clamps every search query to 100 pages (~5,000 listings), you cannot extract 50,000 ads with a single nationwide keyword. Instead, partition your jobs:</p>
<ul>
<li><strong>Partition by Brazilian State (<code>UF</code>)</strong>: Run concurrent jobs across <code>estado-sp</code>, <code>estado-rj</code>, <code>estado-mg</code>, and <code>estado-pr</code>.</li>
<li><strong>Partition by Price Brackets</strong>: Split searches into <code>minPrice: 50000, maxPrice: 75000</code>, <code>minPrice: 75001, maxPrice: 100000</code>, etc.</li>
</ul>
<hr />
<h2>8. Understanding Your Data Schema</h2>
<table>
<thead>
<tr>
<th>Field Name</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr>
<td><code>id</code></td>
<td><code>string</code></td>
<td>Unique OLX listing identifier extracted from the URL.</td>
</tr>
<tr>
<td><code>title</code></td>
<td><code>string</code></td>
<td>Full title as published by the seller.</td>
</tr>
<tr>
<td><code>url</code></td>
<td><code>string</code></td>
<td>Direct link to the listing on <code>olx.com.br</code>.</td>
</tr>
<tr>
<td><code>price</code></td>
<td><code>integer</code></td>
<td>Numerical asking price in BRL. <code>0</code> for free; <code>null</code> if unstated.</td>
</tr>
<tr>
<td><code>city</code> / <code>state</code></td>
<td><code>string</code></td>
<td>Geo-targeted municipality and UF state code (e.g. <code>SP</code>, <code>RJ</code>, <code>DF</code>).</td>
</tr>
<tr>
<td><code>postedAt</code></td>
<td><code>string</code></td>
<td>ISO 8601 publication timestamp (<code>YYYY-MM-DDTHH:MM:SSZ</code>).</td>
</tr>
<tr>
<td><code>areaM2</code></td>
<td><code>integer / null</code></td>
<td>Usable property area in square meters (real estate only).</td>
</tr>
<tr>
<td><code>bedrooms</code> / <code>bathrooms</code></td>
<td><code>integer / null</code></td>
<td>Room counts (real estate only).</td>
</tr>
<tr>
<td><code>mileageKm</code></td>
<td><code>integer / null</code></td>
<td>Odometer reading in kilometers (vehicles only).</td>
</tr>
<tr>
<td><code>year</code></td>
<td><code>integer / null</code></td>
<td>Model manufacture year (vehicles only).</td>
</tr>
<tr>
<td><code>attributes</code></td>
<td><code>object</code></td>
<td>Key-value dictionary containing fuel, gearbox, IPTU, etc.</td>
</tr>
</tbody></table>
<hr />
<h2>9. Troubleshooting &amp; Common Gotchas</h2>
<ul>
<li><strong>Issue: Run finished with status <code>FAILED</code> (0 rows found)</strong>:<ul>
<li><em>Reason</em>: The Actor intentionally raises an error if zero rows match your parameters instead of outputting an empty dataset. This prevents silent failures in production pipelines.</li>
<li><em>Fix</em>: Verify your <code>categoryPath</code> segment on <code>olx.com.br</code> directly in your browser. Ensure your price or mileage boundaries are not conflicting.</li>
</ul>
</li>
<li><strong>Issue: <code>403 Forbidden</code> or Proxy Errors</strong>:<ul>
<li><em>Reason</em>: Custom proxy settings were applied that bypassed Apify Unblocker.</li>
<li><em>Fix</em>: Always leave <code>proxyConfiguration</code> on default (<code>apifyProxyGroups: ["UNBLOCKER"]</code>).</li>
</ul>
</li>
<li><strong>Issue: Missing values in property or vehicle fields</strong>:<ul>
<li><em>Reason</em>: A car ad does not have <code>bedrooms</code>, and land plots do not have <code>bathrooms</code>. Unstated fields return <code>null</code>, never <code>0</code>, to preserve mathematical integrity for machine learning models.</li>
</ul>
</li>
</ul>
<hr />
<h2>10. Best Practices</h2>
<ol>
<li><strong>Keep Prefills Lightweight in CI/CD</strong>: When running smoke tests or automated validations, set <code>maxItems: 10</code> to avoid unnecessary compute charges.</li>
<li><strong>Handle Currency Normalization</strong>: All prices are returned in integer Brazilian Real (<code>BRL</code>). Do not divide by 100.</li>
<li><strong>Respect Upstream Limits</strong>: Avoid launching 50 parallel runs against the same narrow city category simultaneously. Spread requests across regions to maintain optimal unblocking speeds.</li>
</ol>
<hr />
<h2>11. Conclusion &amp; Next Steps</h2>
<p>Extracting data from dynamic classifieds platforms like OLX Brazil no longer requires writing custom Playwright scripts, reverse-engineering Next.js payload bundles, or maintaining expensive proxy fleets. With the <strong>OLX Brazil Scraper</strong>, you can spin up production-grade data feeds with clean, typed schemas in minutes.</p>
<ul>
<li>🚀 <strong>Try the Actor</strong>: <a href="https://apify.com/reventadata/olx-scraper">OLX Brazil Scraper on Apify Store</a></li>
<li>📖 <strong>Pricing</strong>: $1.00 per 1,000 items (Pay-per-event).</li>
<li>💬 <strong>Feedback &amp; Discussion</strong>: What market trends are you analyzing on OLX Brazil? Drop a comment below if you have questions or want to see a guide for a specific marketplace!</li>
</ul>
<h3>Cross-Platform Guides &amp; Community Formats</h3>
<ul>
<li>⚡ <strong>Developer Quickstart (DEV Community)</strong>: <a href="https://dev.to/reventadata/how-to-scrape-real-estate-car-listings-from-olx-brazil-with-olx-brazil-scraper-fae">How to Scrape Real Estate &amp; Car Listings from OLX Brazil</a></li>
<li>☕ <strong>No-Code Beginner Story (Medium)</strong>: <a href="https://medium.com/@reventadata/how-i-extracted-thousands-of-real-estate-car-deals-from-olx-brazil-in-minutes-using-olx-brazil-22f7bbd6ad99">How I Extracted Thousands of Real Estate &amp; Car Deals from OLX Brazil in Minutes</a></li>
</ul>
<hr />
<h3>About the Author</h3>
<p><strong>ReventaData</strong> builds production-grade web scrapers, automated data pipelines, and pay-per-event Apify Actors specializing in European and Latin American second-hand marketplaces, EV charging infrastructure, and public web data extraction. Follow our publications for deep dives into web scraping architecture and reverse-engineering.</p>
<pre><code>
</code></pre>
]]></content:encoded></item></channel></rss>