DEV Community

Cover image for How to Scrape Chileautos Car Listings into JSON with Python
ReventaData
ReventaData

Posted on Originally published at apify.com

How to Scrape Chileautos Car Listings into JSON with Python

By the end of this tutorial, you will have a Python script that turns a chileautos.cl search into structured JSON: one row per listing with price and currency, model year, mileage in kilometres, fuel, transmission, body type, region, and whether the seller is a dealer or a private seller.

Chileautos lists cars, motorcycles, trucks, machinery and other vehicles for sale in Chile. Copying them by hand means paging through search results 18 listings at a time, and in October 2026 testing the site answered plain, datacenter and residential connections with a bot-challenge page.

We will use Python and the Apify Actor Chileautos Scraper (reventadata/chileautos-scraper), which reads the site through Apify's Unblocker proxy by default. The sample rows in this guide come from a capture dated 2026-10-21, parsed with the Actor's own code.

⏱️ Time estimate: About 30 minutes.


Prerequisites

To follow this tutorial, you will need:

  1. Python 3.11+ installed locally (apify-client 3.x requires it).
  2. The Apify API client for Python.
  3. An Apify account and API token.

Sign up for an Apify account, then copy your API token from API & Integrations in Apify Console. Install the client:

pip install "apify-client~=3.0"
Enter fullscreen mode Exit fullscreen mode

The code loads the token from an environment variable:

export APIFY_API_TOKEN="your_apify_token_here"
Enter fullscreen mode Exit fullscreen mode

What you'll achieve

You will turn a chileautos.cl search into rows you can load into a spreadsheet or database: listing id and link, title and trim line, make and model, model year, price with its currency, odometer in kilometres, fuel, transmission, body type, region, seller type, and the dealer's business name when the seller is a dealer.

Note on data boundaries: The Actor reads search result cards only. It does not open listing detail pages, so descriptions, full photo galleries and seller phone numbers are not in the rows. Private sellers appear only as "Particular" on the site, so no personal name is read.

Example use case: You want the Toyota cars listed on chileautos.cl, newest model year first. Setting vehicleType: "autos", make: "Toyota" and sortBy: "year-desc" asks the site for exactly that search, and the rows tell you which listings come from dealers and which from private sellers.


Step 1: Access Chileautos Scraper

Go to the Chileautos Scraper page on Apify Store to try it. The page shows the input fields, an output example and the README.

You can run it from Apify Console with Try for free. In this tutorial we start it from Python instead, so the same script can run again tomorrow.


Step 2: Configure the search

There is no free-text keyword box. You describe the search with the same filters the site offers: vehicleType, make, model, condition, region, sellerType, fuel, price, year and mileage ranges, and sortBy. The Actor builds the site's own search from these fields, so the filtering happens on chileautos.cl before any row reaches you.

Spell make and model as chileautos.cl does (for example Toyota and Hilux). A model needs a make; without one the Actor stops before fetching anything.

In Python, we create the client and the input:

import os
from apify_client import ApifyClient

# 1. Initialize ApifyClient with token from environment
client = ApifyClient(os.environ["APIFY_API_TOKEN"])

# 2. Define the search: Toyota cars, newest model year first
run_input = {
    "vehicleType": "autos",
    "make": "Toyota",
    "sortBy": "year-desc",
    "maxItems": 20,
}
Enter fullscreen mode Exit fullscreen mode

(Note: the sample rows in this guide come from page 1 of this same search, Toyota cars sorted by year, newest first, captured on 2026-10-21. That page held 18 listings.)


Step 3: Optional settings and filters

Every field below except the two keyword lists and maxItems is sent to chileautos.cl as part of the search. The keyword lists are applied by the Actor after each page is read.

Parameter Type Default Description
vehicleType string "all" all, autos, motos, camiones, buses, maquinarias, casas-rodantes, nautica, aereos.
make / model string empty Brand and model as the site spells them. model needs make.
condition string "any" any, new, used.
region string "any" One of Chile's 16 regions, for example metropolitana or valparaiso.
sellerType string "any" any, dealer, private, verified-private.
fuel string "any" any, gasoline, diesel, electric, gas, hybrid, other.
minPrice / maxPrice integer empty Listed price range. The site compares the listed number whatever its currency.
minYear / maxYear integer empty Model year range.
minKm / maxKm integer empty Odometer range in kilometres.
sortBy string "featured" One of 9 site sort orders, for example price-asc or year-desc.
maxItems integer 100 Total listings to save.
includeKeywords / excludeKeywords array empty Keep or drop rows by words in title, trim, make, model, body type or dealer name, ignoring case and accents.

A few practical notes:

  • The fixed lists are checked before the run starts. A value outside a list (a misspelt region, say) is refused by the platform and the Actor is not started.
  • featured is random per request. It is the site's default sort; the Actor removes duplicate listing ids, but use another sort when you want a stable order.

Step 4: Run the Actor

Start the run and wait for it with client.actor("reventadata/chileautos-scraper").call(run_input=run_input):

# 3. Start the Actor run and wait for it to complete
print("Starting Chileautos extraction...")
run = client.actor("reventadata/chileautos-scraper").call(run_input=run_input)
if run is None or run.status != "SUCCEEDED":
    status = run.status if run else "unknown"
    raise SystemExit(f"Run did not succeed (status: {status}).")

# 4. Fetch the resulting dataset items
dataset = client.dataset(run.default_dataset_id).list_items().items

print(f"Extraction complete! Retrieved {len(dataset)} listings.\n")
Enter fullscreen mode Exit fullscreen mode

Behind the scenes:

  • The Actor sends the search to chileautos.cl through Apify's Unblocker proxy (the default). In October 2026 testing, no proxy, a datacenter proxy and a residential proxy all got the bot-challenge page; Unblocker reached the result pages.
  • It reads the result pages in order, about 18 listings per page, and saves one row per listing.
  • The site serves at most 50 pages per search, about 900 listings. When maxItems asks for more and the search is bigger than that, the Actor cuts the search into price ranges and reads each one.

Step 5: View and download results

Once the run finishes, print a short summary of each row:

for item in dataset:
    price = item.get("price")
    km = item.get("odometerKm")
    mileage = f"{km:,} km" if km is not None else "not stated"

    print(f"Listing: {item.get('title')} {item.get('trim') or ''}".rstrip())
    if price is None:
        print("  Price: not listed")
    else:
        print(f"  Price: {price:,} {item.get('currency')}")
    print(f"  Mileage: {mileage}")
    print(f"  Seller: {item.get('sellerType')} ({item.get('sellerName') or 'no dealer name'})")
    print(f"  Region: {item.get('region')}")
    print("-" * 50)
Enter fullscreen mode Exit fullscreen mode

Apify datasets also export as JSON, CSV, XML, Excel, HTML table, RSS or JSONL.

Here is one row, a sample from a capture dated 2026-10-21, parsed with the Actor's own code (a real run also adds scrapedAt, the time the row was saved):

{
  "id": "CL-AD-21005905",
  "url": "https://www.chileautos.cl/vehiculos/detalles/2026-toyota-yaris-1-5-e-4x2-sdn-mt-4p/CL-AD-21005905/",
  "title": "2026 Toyota Yaris",
  "trim": "1.5 E 4X2 SDN MT 4P",
  "make": "Toyota",
  "model": "Yaris",
  "year": 2026,
  "price": 12800000,
  "currency": "CLP",
  "odometerKm": 3700,
  "fuelType": "Bencina",
  "transmission": "Manual",
  "bodyType": "Sedán",
  "fuelEconomy": "16,9 Kms/Lt.",
  "condition": null,
  "sellerType": "private",
  "sellerName": null,
  "region": "Metropolitana de Santiago",
  "imageUrl": "https://chileautos.pxcrush.net/chileautos/cars/private/azlhefud9wald3p8l8dwrt5uu.jpg?pxc_method=fitfill&pxc_bgtype=self&pxc_size=432,288",
  "imageCount": 8,
  "badges": [],
  "page": 1
}
Enter fullscreen mode Exit fullscreen mode

Understanding your results

The key fields:

  • id: chileautos.cl listing id. In the 18-row sample, private listings start CL-AD- and dealer listings CP-AD- or GI-AD-.
  • title / trim: the headline (year, make, model) and the version line under it.
  • price / currency: the listed number and the currency printed next to it (all 18 sample rows were CLP; the site also lists in USD). null when no price is listed.
  • odometerKm: kilometres as typed by the seller. 13 of the 18 sample rows had none: all 13 were new cars at dealers.
  • fuelType, transmission, bodyType: as the site writes them, in Spanish (Bencina is gasoline).
  • condition: new or used for dealers; null for private sellers, which the site does not label.
  • sellerType / sellerName: dealer, private or verified-private; the dealer's business name, or null.
  • badges: promotion badges on the card. 15 of the 18 sample rows showed Premium.

In the sample page, 15 rows came from dealers, 3 from private sellers and 0 from verified private sellers.


Pro tips

  1. Mind the 900-row ceiling. The site stops at 50 pages of 18 listings per search. The capture's Toyota search had 2,382 results over 133 pages, so a maxItems above about 900 makes the Actor read it in price slices. A listing with no price cannot be reached by a price slice.
  2. Narrow on the site, not afterwards. region, sellerType, fuel, condition and the ranges go into the site's search, so you only read pages you want.
  3. Price ranges compare raw numbers. A listing priced in USD is compared by its dollar amount, as the site does. Check currency before comparing prices across rows.
  4. Use the keyword lists for trims. includeKeywords: ["4x4"] keeps rows whose title, trim, make, model, body type or dealer name contains "4x4", ignoring case and accents.
  5. Start small. Begin with maxItems: 20 to check the fields on one page of results, then raise it.

Troubleshooting

  • 0 rows saved: a run that is blocked or cannot read a page ends FAILED. A search that loads normally but matches nothing ends SUCCEEDED with an empty dataset and a status message saying so; loosen your ranges or check the make spelling.
  • Run FAILED with "The site did not apply make=...": chileautos.cl answers a malformed make or model term (not a misspelling, which returns no results) with every vehicle. The Actor checks page 1 and stops rather than export the wrong cars. Copy the spelling from chileautos.cl.
  • Run not started: a value outside a fixed list (vehicleType, region, sortBy, ...) is refused by the platform before the run starts.
  • Reading the log: the run's summary line reads Run finished: N rows pushed. Rejections: .... Read it from Python with client.log(run.id).get(). For help, use the Store page.

Pricing and next steps

For current pricing and details, see the Store page.

To repeat a search, save it as a task and add an Apify schedule, which runs Actors and tasks on a cron expression. A webhook on ACTOR.RUN.SUCCEEDED sends the run object, including defaultDatasetId, to your endpoint.

Links:

Which vehicles or regions are you planning to track on Chileautos? Drop a comment! 💬

Top comments (0)