DEV Community

Cover image for How to Scrape Vivanuncios Mexico Real Estate Listings with Python
ReventaData
ReventaData

Posted on Originally published at apify.com

How to Scrape Vivanuncios Mexico Real Estate Listings with Python

By the end of this tutorial, you will have a working Python script that extracts live Mexican property listings from Vivanuncios into clean, structured JSON datasets. You will be able to capture asking prices in Mexican pesos (MXN) or US dollars (USD), property dimensions, bedroom and bathroom counts, neighbourhood details, geographic coordinates, and WhatsApp contact numbers for listing agents.

Vivanuncios is a Mexican real estate classifieds portal, featuring houses, apartments, commercial premises, offices, and new developments; the Actor can target any of 32 Mexican states. Harvesting property data manually from the platform is repetitive and time-consuming, while requests face Cloudflare bot challenges that block standard automated clients.

In this guide, we use Python and the cloud Actor Vivanuncios Scraper (reventadata/vivanuncios-scraper) with Apify Unblocker proxies to collect structured property records reliably.

⏱️ Time estimate: About 15 minutes.


Prerequisites

To follow this tutorial, make sure you have the following ready:

  1. Python 3.11+ installed on your machine (apify-client 3.x requires Python 3.11 or newer).
  2. The official Apify API client package installed via pip:
pip install -U "apify-client~=3.0"
Enter fullscreen mode Exit fullscreen mode
  1. An Apify account and personal API token. You can sign up with email or GitHub, then locate your secret token under API & Integrations in Apify Console.

Export your API token to your environment before running any code:

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

What you'll achieve

By completing this tutorial, you will build an automated pipeline that queries Vivanuncios and delivers structured records directly into an exportable dataset. Each extracted record standardizes listing attributes including asking prices, monthly maintenance fees, lot sizes, built surface areas, room counts, publisher metadata, and direct agent contacts.

Note on Data Boundaries: This Actor reads public search result pages on vivanuncios.com.mx. The site's robots.txt allows pages 1 through 5 (30 listings per page), resulting in a site ceiling of 150 listings per search URL. Filter parameters are evaluated locally after fetching each listing.

Example use case: Suppose you want to analyze the rental market in Jalisco for apartments with at least 1 bedroom under 25,000 MXN per month. You can configure the scraper to sweep that market segment, drop non-compliant rows, and output clean records for market research.


Step 1: Access Vivanuncios Scraper

Start by visiting the Vivanuncios Scraper page on the Apify Store.

Clicking "Try for free" opens the Actor configuration tab inside Apify Console, where you can view input fields, documentation, and dataset schemas. In this guide, we drive the Actor programmatically via Python rather than manually in the browser.


Step 2: Configure search parameters

The Actor accepts search parameters to build valid Vivanuncios directory paths:

  • operation: 'sale' (default) or 'rent'.
  • propertyTypes: Property types to query, such as ['houses'], ['apartments'], ['land'] (sale only), ['commercial'], ['offices'], ['vacation'] (rent only), or ['all'].
  • states: Any of Mexico's 32 states (such as 'distrito-federal', 'jalisco', 'nuevo-leon', or 'yucatan'). An empty list targets the whole country.
  • startUrls: Specific Vivanuncios search URLs (for city or neighbourhood-level queries).

In Python, initialize ApifyClient and define your extraction criteria in run_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 extraction parameters
run_input = {
    "operation": "rent",
    "propertyTypes": ["apartments"],
    "states": ["jalisco"],
    "minBedrooms": 1,
    "maxPrice": 25000,
    "maxItems": 20,
}
Enter fullscreen mode Exit fullscreen mode

(Note: This demonstration snippet uses maxItems: 20 for a fast initial test. The sample row cited below was captured from page 1 of this search on 2026-10-21.)


Step 3: Configure optional settings and filters

Because Vivanuncios' robots.txt disallows query parameters like ?pr= (price) and ?fe= (features), the Actor fetches allowed search pages and applies all numeric and keyword filters inside the Actor:

Parameter Type Default Description
operation string "sale" Operation: "sale" or "rent". Refused before start if invalid.
propertyTypes array ["houses"] Types: "houses", "apartments", "land", "commercial", "offices", "vacation", "all".
states array [] 32 state slugs (e.g. "distrito-federal"). Empty means nationwide.
startUrls array [] Listing URLs. Overrides operation/propertyTypes/states. No query strings.
maxItems integer 100 Maximum listings to store across all searches after filtering.
maxPages integer 5 Pages per search (clamped to 5 by robots.txt, 30 per page).
priceCurrency string "MXN" Currency for price limits: "MXN" or "USD".
minPrice, maxPrice number None Price boundaries applied post-fetch.
minBedrooms integer None Minimum bedrooms required.
minBathrooms integer None Minimum full bathrooms required. Half bathrooms excluded.
minParkingSpaces integer None Minimum parking spots required.
minBuiltAreaM2 integer None Minimum built square metres.
minLandAreaM2 integer None Minimum lot size square metres.
includeKeywords array [] Keep listings containing at least one keyword.
excludeKeywords array [] Drop listings containing any of these keywords.
proxyConfiguration object Unblocker Apify Unblocker proxy configuration.

Filtered-out rows are dropped before they are pushed to the dataset.


Step 4: Run the Actor

Now trigger the Actor using client.actor("reventadata/vivanuncios-scraper").call(run_input=run_input). This executes the task in the Apify cloud, streams execution progress, and awaits completion:

# 3. Start the Actor run and wait for it to complete
print("Starting Vivanuncios Mexico extraction...")
run = client.actor("reventadata/vivanuncios-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 routes HTTP requests through Apify Unblocker proxies. In October 2026 testing, direct, datacenter, and 24 of 25 residential requests met Cloudflare challenges, while Apify Unblocker achieved 24 of 25 successful responses.
  • The scraper fetches server-rendered search pages, decodes embedded state records, parses property attributes, evaluates your configured filters, and stores matching rows into the run's dataset.

Step 5: View and download results

Once the extraction finishes, you can iterate through the returned dataset items in Python or export them to JSON, CSV, or Excel formats:

for item in dataset:
    title = item.get("title") or item.get("generatedTitle")
    price = item.get("price")
    currency = item.get("currency") or "MXN"
    city = item.get("city")
    state = item.get("state")
    bedrooms = item.get("bedrooms")
    built_m2 = item.get("builtAreaM2")

    print(f"Listing: {title}")
    if price is None:
        print("  Price: unpriced")
    else:
        print(f"  Price: {price:,} {currency}")
    print(f"  Location: {city}, {state}")
    specs = []
    if bedrooms is not None:
        specs.append(f"{bedrooms} rec.")
    if built_m2 is not None:
        specs.append(f"{built_m2} m²")
    if specs:
        print(f"  Specs: {' · '.join(specs)}")
    print("-" * 50)
Enter fullscreen mode Exit fullscreen mode

Here is a verbatim sample row from a capture dated 2026-10-21 (from search path /s-departamentos-en-renta/jalisco/v1c1300l1013p1, scrapedAt omitted):

{
  "id": "151221071",
  "url": "https://www.vivanuncios.com.mx/a-renta-departamento/moderna/departamento-en-renta-en-colonia-moderna-coordenada-lafayette/151221071",
  "title": "Departamento en Renta en Colonia Moderna, Coordenada Lafayette",
  "generatedTitle": "Departamento · 43m² · 1 Recámara · 1 Estacionamiento",
  "listingKind": "property",
  "operation": "Renta",
  "propertyType": "Departamentos",
  "price": 18000,
  "currency": "MXN",
  "maintenanceFee": null,
  "landAreaM2": 43,
  "builtAreaM2": 43,
  "bedrooms": 1,
  "bathrooms": 1,
  "halfBathrooms": null,
  "ageYears": 2,
  "parkingSpaces": 1,
  "description": "Departamento totalmente amueblado tipo loft en Coordenada Lafayette. Es ideal para quienes disfrutan de un estilo de vida dinámico, con fácil acceso a la cultura, el entretenimiento y los servicios. Es un lugar con carácter y mucha vida. Explorar las calles aledañas a la avenida Chapultepec que ofrecen un equilibrio entre la cercanía a la acción y un ambiente más bohemio y tranquilo. Características: Construcción: 43. 5 M2. 1 habitación. 1 baño completo. Cocina equipada. 1 lugar de estacionamiento. Amenidades: Lobby. Co-working. Sky Bar. bbq Zone. Ciclopuertos. Terraza de usos múltiples. * Se permiten Mascota Pequeña* *Mantenimiento Incluido* Cambios de información o precios sin previo aviso. Eb-th8015. pqGqjpm",
  "neighborhood": "Moderna",
  "city": "Guadalajara",
  "state": "Jalisco",
  "street": "Calle Juan Ruiz de Alarcón 519",
  "latitude": 20.6661433,
  "longitude": -103.3760042,
  "publisherId": "102342120",
  "publisherName": "FINCA INMUEBLES",
  "publisherTypeId": "2",
  "publisherUrl": "https://www.vivanuncios.com.mx/u-anuncios-del-vendedor/finca-inmuebles/v1u102342120p1",
  "publisherPhone": null,
  "contactWhatsapp": "523312564414",
  "premier": true,
  "imageCount": 8,
  "imageUrls": [
    "https://img10.naventcdn.com/avisos/18/01/51/22/06/81/720x532/1634354544.jpg?rapc=bXZhX2ltYWdl?isFirstImage=true",
    "https://img10.naventcdn.com/avisos/18/01/51/22/06/81/720x532/1634354545.jpg?rapc=bXZhX2ltYWdl",
    "https://img10.naventcdn.com/avisos/18/01/51/22/06/81/720x532/1634354548.jpg?rapc=bXZhX2ltYWdl",
    "https://img10.naventcdn.com/avisos/18/01/51/22/06/81/720x532/1634354541.jpg?rapc=bXZhX2ltYWdl",
    "https://img10.naventcdn.com/avisos/18/01/51/22/06/81/720x532/1634354552.jpg?rapc=bXZhX2ltYWdl",
    "https://img10.naventcdn.com/avisos/18/01/51/22/06/81/720x532/1634354556.jpg?rapc=bXZhX2ltYWdl",
    "https://img10.naventcdn.com/avisos/18/01/51/22/06/81/720x532/1634354551.jpg?rapc=bXZhX2ltYWdl",
    "https://img10.naventcdn.com/avisos/18/01/51/22/06/81/720x532/1634354547.jpg?rapc=bXZhX2ltYWdl"
  ],
  "hasVideo": false,
  "hasTour360": false,
  "hasPlans": false,
  "modifiedAt": "2026-10-21T17:28:50-0400",
  "source": "state",
  "searchPath": "/s-departamentos-en-renta/jalisco/v1c1300l1013p1",
  "searchPage": 1
}
Enter fullscreen mode Exit fullscreen mode

Understanding your results

Each record stored in the Apify dataset adheres to the schema fields defined by the Actor:

  • id & url: Vivanuncios unique listing identifier string and canonical listing URL.
  • title & generatedTitle: Advertiser listing headline and the portal's summarized attributes string.
  • listingKind: Categorized as 'property' for individual homes, or 'development' for multi-unit projects.
  • operation & propertyType: The transaction type ('Venta' or 'Renta') and category ('Casas', 'Departamentos', 'Terrenos').
  • price & currency: Numerical asking price or monthly rental rate and currency ('MXN' or 'USD').
  • maintenanceFee: Monthly condominium maintenance amount when reported by the advertiser.
  • landAreaM2 & builtAreaM2: Total lot surface and constructed area in square metres.
  • bedrooms, bathrooms, halfBathrooms: Standardized room counts (recamaras and baños).
  • parkingSpaces & ageYears: Garage capacity and building age in years.
  • neighborhood, city, state, street: Location hierarchy (colonia, alcaldia/municipio, state, and street address).
  • latitude & longitude: Coordinate geolocation points when provided by the listing.
  • publisherName, publisherId, publisherTypeId: Agency or merchant details (type 2 was seen on agencies; the site does not publish what 3 and 4 mean).
  • contactWhatsapp: Direct mobile WhatsApp phone contact formatted with international country code.
  • source: Extraction origin flag: 'state' (full page data block) or 'card' (HTML card fallback).

Pro tips

  1. Ceiling awareness on search pages: Vivanuncios' robots.txt allows pages 1 through 5 only. Each search path yields at most 150 listings (30 per page). To scrape larger volumes across Mexico, iterate across multiple state slugs or supply city-level startUrls.
  2. City and neighbourhood targeting: If you need listings from a specific neighbourhood or municipality (such as Polanco or San Pedro Garza García), paste its exact Vivanuncios directory URL into startUrls. The Actor cleans pagination segments and walks pages 1 to 5.
  3. Card fallback resilience: When target pages occasionally return without the embedded data script, the Actor makes up to three attempts and falls back to parsing raw HTML cards (source: "card"). These rows preserve price, lot area, room counts, and location.
  4. Keyword filtering without latency: Because URL query parameters like ?q= are disallowed by robots.txt, use includeKeywords and excludeKeywords. The Actor checks title, description, and location strings locally, ignoring case and accents.
  5. Enforce budget boundaries: Use maxItems to cap the total listings stored. The Actor stops starting new page fetches once the item limit is reached.

Troubleshooting

  • Actor fails with zero rows: If zero listings pass your filters, the Actor deliberately raises a RuntimeError to prevent silent downstream pipeline failures. Review your price bounds and ensure keywords are not overly restrictive.
  • Refused enum input values: The Apify platform validates operation, propertyTypes, states, and priceCurrency against official schema enums. Supplying an unsupported state slug or invalid operation causes the run to be refused before execution starts.
  • Incompatible property type and operation: Vivanuncios does not offer land for rent or vacation houses for sale. Requesting 'rent' with 'land' is refused during option validation.
  • Missing built area on card rows: When a listing is parsed from an HTML fallback card (source: "card"), builtAreaM2 is null because cards only display lot dimensions. If needed, filter by source: "state".

Pricing and Next Steps

For current pricing and details, see the Store page.

To automate your extractions, save your configuration as an Apify Actor task and attach an Apify schedule using standard cron syntax (e.g. 0 8 * * * to run daily at 8:00 AM UTC). You can also configure webhooks listening for ACTOR.RUN.SUCCEEDED events to automatically receive payload data containing defaultDatasetId.

Helpful resources:

What Mexican real estate markets or investment deals are you planning to track on Vivanuncios? Let us know in the comments below!

Top comments (0)