1. 2scraper
  2. Classifieds, property & travel
  3. Avito
Open source · MITNeeds a residential exit or the Scraping Browser API

Avito Scraper

Category and search listings, item pages and seller profiles from avito.ru, through its GeeTest firewall.

  • Playwright
  • Selenium
  • Puppeteer
  • Scraping Browser API
  • JSON
  • CSV
avito-scraper
# Category & search listings
$ python3 playwright_scraper.py --mode listing --url "https://www.avito.ru/moskva?q=iphone+15" --pages 2
✓ 10 sample rows · 29 columns in sample_output.json
3modes: listing, item, seller
147rows from a 3-page listing run, Oct 2026
3 of 3GeeTest walls solved via the browser's own exit, Oct 2026
3browser engines sharing one run loop
Available Avito scrapers

What the Avito scraper collects

Scrapes avito.ru category and search listings, full item pages and seller profiles: the price the buyer sees (with the old price and discount where Avito states them), location, condition, item parameters, photos, views and the seller's rating, reviews and tenure. Output is JSON or CSV plus a run-metadata sidecar that says whether the result is complete.

Category & search listings

Input: An avito.ru category path or a ?q= search URL

One row per card: displayed price, old price and discount where stated, region and metro location, summary parameters, seller name, type, rating and reviews, promoted flag and badges.

Item pages

Input: Item URLs, or a previous listing run's JSON via --from

Everything a listing row has, plus the description, all characteristics as params, every photo, category path, address with lat/lng, view counts, seller tenure and reply time.

Seller profiles

Input: A seller profile URL (/brands/<seller>)

The seller's name, rating, reviews, tenure, subscribers and active-ad counter, plus the listing cards the profile page renders as listing rows.

Quick start

From zero to Avito data in 3 steps

  1. Install

    Clone the repository and install one browser engine. Python 3.9+.

    $ git clone https://github.com/2scraper/avito-scraper && cd avito-scraper
    $ pip install -r requirements.txt
    $ pip install -r requirements-playwright.txt && playwright install chromium
    $ cp .env.example .env
  2. Run a scraper

    Pick what you need and run it. Every flag is documented in the README.

    $ python3 playwright_scraper.py --mode listing --url "https://www.avito.ru/moskva?q=iphone+15" --pages 2
  3. Get structured data

    Rows land in JSON or CSV (--format), with a .meta.json sidecar recording status, pages fetched and why the run stopped.

Output

Avito data fields

29 columns per row in a predictable schema. The most useful ones:

FieldWhat it holds
skuAvito's item id
titleListing title as printed on the card
priceThe displayed price the buyer sees, as a number
currencyRUB
original_priceAvito's own old price on a discounted item
discount_pctThe site's own discount figure
price_sourceWhich rendering the price came from: state (embedded JSON) or dom
region_slugRegion from the URL, present on every row
locationMetro station or district as printed
summary_paramsThe card's one-line summary, e.g. new or used
published_atPublication time, where the rendering states it
seller_nameCompany or shop name; empty for private persons, whom Avito anonymises
seller_typecompany or private, where the card states it
seller_ratingSeller's rating
seller_reviewsNumber of seller reviews
promotedWhether the card is a promoted placement
[
  {
    "source": "avito.ru",
    "scraped_at": "2026-10-06T11:43:07.634024+00:00",
    "url": "https://www.avito.ru/moskva/telefony/iphone_17_256_gb_sim_esim_8212942358",
    "sku": "8212942358",
    "title": "iPhone 17, 256 ГБ, SIM + eSIM",
    "image_url": "https://b00.img.avito.st/image/1/1.ZNuvMraAyDK5kmoz639ju6mSyjYdhcwyHeKpNh0xyZAakcwouZJq…",
    "price": 64935.0,
    "currency": "RUB",
    "category": null,
    "price_source": "dom",
    "original_price": null,
    "discount_pct": null,
    "region_slug": "moskva",
    "city": "Москва",
    "location": "Багратионовская, 6–10 мин.",
    "summary_params": "Новый",
    "published_at": null,
    "published_text": null,
    "seller_name": "Продавец 1",
    "seller_type": null,
    "seller_id": "seller1",
    "seller_url": "https://www.avito.ru/brands/seller1",
    "seller_rating": 5.0,
    "seller_reviews": 624,
    "promoted": true,
    "badges": [
      "Реквизиты проверены",
      "яПомогаю"
    ],
    "delivery": null,
    "page": 1,
    "position": 1
  },
  {
    "source": "avito.ru",
    "scraped_at": "2026-10-06T11:43:07.639160+00:00",
    "url": "https://www.avito.ru/moskva/telefony/iphone_17_pro_512_gb_8286114224",
    "sku": "8286114224",
    "title": "iPhone 17 Pro, 512 ГБ",
    "image_url": "https://c70.img.avito.st/image/1/1.gxuaVbaAL_KM9Y3zkF_ZKYD1LfYo4ivyKIVO9ihWLlAv9ivojPWN…",
    "price": 103090.0,
    "currency": "RUB",
    "category": null,
    "price_source": "dom",
    "original_price": null,
    "discount_pct": null,
    "region_slug": "moskva",
    "city": "Москва",
    "location": "Фили, 6–10 мин.",
    "summary_params": "Новый",
    "published_at": null,
    "published_text": null,
    "seller_name": "Продавец 2",
    "seller_type": null,
    "seller_id": "seller2",
    "seller_url": "https://www.avito.ru/brands/seller2",
    "seller_rating": 5.0,
    "seller_reviews": 706,
    "promoted": true,
    "badges": [
      "Реквизиты проверены"
    ],
    "delivery": null,
    "page": 1,
    "position": 2
  }
]

First 2 of 10 rows from a real run — sample_output.json. Long values shortened here.

Built for Avito

Handles what breaks naive Avito scrapers

The displayed price, not the stale one

On a discounted item Avito's bare price field holds the OLD price. price is always the one shown on the page and original_price is the site's own old figure; JSON, microdata and the item page agreed on 50 of 50 cards.

Firewall walls cleared in the browser's own session

The proof-of-work page clears itself in a real browser; the GeeTest v4 wall is solved through the page's own form, with the solve sent through the same IP the browser uses. The scraper refuses to pay for a solve that would not.

Substitute results are not results

A search with no matches still returns fifty «similar listings» cards. The run reports the page as empty (exit 4) instead of a complete-looking answer to a different question.

Two renderings, one schema

The same URL can come back as plain markup or with embedded JSON state. price_source records which one a row came from, and diff_runs.py does not report that difference as a price change. Promoted cards repeated across pages are deduplicated in page order.

Everything built in

Scraping infrastructure included

The same tested core runs every 2scraper repository, so the hard parts work the same way on every site.

CAPTCHA handling

Detects the challenge a page really serves and, with a 2Captcha key, solves it only when it blocks the data — a capped number of solves per page.

Proxy rotation

Single proxy or a pool from a file, rotated on blocks with a fresh browser per exit. Credentials stay out of argv and logs.

Fingerprints

Optional complete device identity from the 2Captcha Fingerprint API — user agent, client hints, locale and timezone that agree with each other.

Honest run metadata

Every run writes a .meta.json sidecar and distinct exit codes: complete, blocked, empty and partial are never confused, and a failed run never overwrites good data.

Diff two runs

diff_runs.py compares two complete Avito snapshots by id — new, removed and changed rows for monitoring.

Use cases

What teams do with Avito data

Second-hand price tracking

Follow displayed prices, old prices and discounts for a category such as used iPhones in Moscow, run after run, compared by sku with diff_runs.py.

Regional market comparison

Scrape the same category across city paths and group by region_slug to compare supply and price levels between regions.

Dealer and shop monitoring

Track a company seller's profile: rating, review count, subscribers and active-ad counter over time.

Item-level catalogue data

Turn a listing run into full item records with every characteristic, all photos, coordinates and view counts for analysis.

Access & pricing

Free to run. Pay only for what the site requires.

Needs a residential exit or the Scraping Browser API

There is no free path on avito.ru, measured on 2026-10-06: a plain HTTP client was refused 6 of 6 times and a local browser met the GeeTest wall on every fresh session. You need a Russian residential exit (2Captcha proxies), and the recommended transport is the Scraping Browser API, which clears the proof-of-work page by itself and keeps the clearance in a persistent profile. A 2Captcha key solves the GeeTest v4 wall through GeeTestTask, $0.00299 per solve in that measurement.

Optional 2Captcha services — captcha solving, the Scraping Browser API, residential proxies and fingerprints — work behind one key.

Good to know

  • Seller mode returns only the cards a profile page renders (15 measured, of 107–353 active); the rest load on scroll and are not fetched by this version.
  • city is often empty in the markup rendering; region_slug is on every row.
  • Selenium cannot use the Scraping Browser API, and --concurrency above 1 is refused.

2scraper vs. hosted scraper APIs

2scraperTypical hosted API
CodeOpen source, MIT — read and patch itClosed
CostFree; optional services billed only when usedSubscription or per request / per result
Runs onYour machine, server or CIThe vendor's infrastructure
OutputJSON/CSV files + run metadataAPI responses
When the site changesFix it yourself or open an issue / PRWait for the vendor
FAQ

Avito scraper FAQ

What output formats does it write?

JSON or CSV, plus a <out>.meta.json sidecar recording status and which pages failed. A run that finds nothing writes nothing, so a good previous output is never replaced with an empty file.

Do I need a proxy and a captcha key?

Yes on this site. The README measured no plain-HTTP route and a GeeTest wall on every fresh local browser session, so a Russian residential exit and a 2Captcha key are part of the normal setup.

How does pagination work?

The scraper builds ?p=N pages and stops at the site's own last page, when a page adds no new item, or at --max-products.

Can I use sort or filter parameters in the URL?

No. avito.ru's robots.txt disallows ?s=, ?f=, ?radius= and ?view=, and the scraper refuses those URLs before fetching. Narrow by path instead: city, category, subcategory. ?q= search and ?p= pages are allowed.

Does it collect phone numbers or private sellers' names?

No. Phone numbers are behind login and are never read; private persons are anonymised by Avito itself, so their seller_name is empty and seller_type is private.

Is scraping Avito legal?

The repo reads public pages only, without logging in, and respects robots.txt. It is public data, but follow the site's terms and the law where you operate, including personal-data law such as Russia's 152-FZ for seller names.