1. 2scraper
  2. Finance & markets
  3. Screener.in
Open source · MITRuns with no key, proxy or account

Screener.in Scraper

Any screener.in stock screen or sector listing to JSON/CSV — market cap, P/E, ROCE and every column the page shows.

  • Playwright
  • Selenium
  • Puppeteer
  • Plain HTTP
  • Scraping Browser API
  • JSON
  • CSV
screener-scraper
# Sector & industry listings
$ python3 playwright_scraper.py --url "https://www.screener.in/market/IN08/IN0801/IN080101/" --pages 1 --out it_software
✓ 5 sample rows · 22 columns in sample_output.json
0keys, proxies or accounts needed
164 of 164companies in a full sector run, ranks with no gap, Sep 2026
4engines incl. plain HTTP, plus the Scraper API
8typed metric columns, plus every extra column
Available Screener.in scrapers

What the Screener.in scraper collects

Scrapes screener.in result tables — any stock screen (/screens/{id}/{slug}/) and any sector or industry listing (/market/…) — into JSON and CSV, one row per company in the table's own order. Rows carry price in INR, market cap, P/E, dividend yield, quarterly sales and profit with their changes, ROCE, and every other column the page shows under its own name and unit. A .meta.json sidecar records the site's own result count and whether the run was exhaustive.

Sector & industry listings

Input: A /market/… sector or industry URL

One row per company in the sector, sorted by market cap as the site shows it, with the listing's heading as category.

Stock screens

Input: A /screens/{id}/{slug}/ URL — any public screen

The screen's result table: the standard metrics plus every custom column the screen adds, kept under its own name and unit in extra_metrics.

Plain HTTP, no browser

Input: Any screen or sector URL

The same rows from the served HTML with only requirements.txt installed: 1.2 s and 47 MB RSS against Playwright's 2.9 s and 150 MB, measured 2026-09-28.

Quick start

From zero to Screener.in data in 3 steps

  1. Install

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

    $ git clone https://github.com/2scraper/screener-scraper && cd screener-scraper
    $ python3 -m venv venv && ./venv/bin/pip install -r requirements.txt -r requirements-playwright.txt
    $ ./venv/bin/playwright install chromium
  2. Run a scraper

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

    $ python3 playwright_scraper.py --url "https://www.screener.in/market/IN08/IN0801/IN080101/" --pages 1 --out it_software
  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

Screener.in data fields

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

FieldWhat it holds
skuThe site's own company id
titleCompany name as the table links it
tickerWhat the company URL carries: letters (TCS) or a six-digit code
priceCurrent market price
currencyINR, read from the price column's own unit
rankThe site's own S.No., global across pages
consolidatedWhether the row links consolidated or standalone figures
market_cap_crMarket capitalisation, Rs. crore
pePrice to earnings
dividend_yield_pctDividend yield, %
net_profit_qtr_crLatest quarter net profit, Rs. crore
qtr_profit_var_pctQuarterly profit change, %
sales_qtr_crLatest quarter sales, Rs. crore
qtr_sales_var_pctQuarterly sales change, %
roce_pctReturn on capital employed, %
extra_metricsEvery other column, keyed by the site's own name and unit
[
  {
    "source": "screener.in",
    "scraped_at": "2026-09-25T09:16:57.869422+00:00",
    "url": "https://www.screener.in/company/SPARC/",
    "sku": "3244",
    "title": "SPARC",
    "price": 210.0,
    "currency": "INR",
    "category": "Magic Formula",
    "page": 1,
    "position": 1,
    "rank": 1,
    "ticker": "SPARC",
    "consolidated": false,
    "market_cap_cr": 6814.96,
    "pe": 4.34,
    "dividend_yield_pct": 0.0,
    "net_profit_qtr_cr": -20.98,
    "qtr_profit_var_pct": 59.68,
    "sales_qtr_cr": 39.92,
    "qtr_sales_var_pct": 314.11,
    "roce_pct": 164.99,
    "extra_metrics": {
      "Return on invested capital (%)": 134.34,
      "Earnings yield (%)": 22.73,
      "Book value (Rs.)": 41.09
    }
  },
  {
    "source": "screener.in",
    "scraped_at": "2026-09-25T09:16:57.869917+00:00",
    "url": "https://www.screener.in/company/532015/",
    "sku": "1203",
    "title": "Gravity (India)",
    "price": 14.46,
    "currency": "INR",
    "category": "Magic Formula",
    "page": 1,
    "position": 2,
    "rank": 2,
    "ticker": "532015",
    "consolidated": false,
    "market_cap_cr": 112.82,
    "pe": 6.03,
    "dividend_yield_pct": 0.0,
    "net_profit_qtr_cr": 6.01,
    "qtr_profit_var_pct": 8485.71,
    "sales_qtr_cr": 60.0,
    "qtr_sales_var_pct": 19254.84,
    "roce_pct": 158.68,
    "extra_metrics": {
      "Return on invested capital (%)": 88.05,
      "Earnings yield (%)": 22.28,
      "Book value (Rs.)": 1.91
    }
  }
]

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

Built for Screener.in

Handles what breaks naive Screener.in scrapers

Columns matched by name and unit, not position

A screen that adds a column moves every column after it. Each header is identified by its metric name and unit, and a header in a different unit goes to extra_metrics rather than into a typed column that promises the wrong unit.

Out-of-range pages detected

?page=8 of a 7-page listing returns page 7's rows with HTTP 200. The scraper reads which page the site says it served and plans against "Showing page 1 of 7", so it never duplicates the last page.

Lost pages proven by rank

The site numbers rows globally across pages, so the sidecar's rank_gaps lists any site rank missing from the merged rows — proof of a lost page rather than a guess.

The registration wall is not an empty screen

When screener.in answers with its /register/ page, the run reports it as blocked (exit 3) with advice, and never parses it as a screen with no results.

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.

Scraping Browser API

Point --cdp-endpoint at a managed Chromium with its own exit country — no browser infrastructure to run yourself.

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 Screener.in snapshots by id — new, removed and changed rows for monitoring.

Use cases

What teams do with Screener.in data

Screen result tracking

Run a public stock screen such as Magic Formula on a schedule and diff the companies entering and leaving it by sku.

Sector fundamentals snapshots

Pull every company in an industry with market cap, P/E, ROCE and quarterly sales and profit for comparison.

Quant research inputs

Feed typed fundamentals and a screen's custom metrics (ROIC, earnings yield, book value) into a model or spreadsheet.

Lightweight scheduled jobs

Use the plain-HTTP engine on a small server: no browser, about 1 second per page.

Access & pricing

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

Runs with no key, proxy or account

From an ordinary connection you need no key, no proxy and no account: on 2026-09-25 plain curl from a residential connection was served sector and screen pages in full, and the daily canary passes from a bare GitHub runner. 2Captcha proxies add volume and an Indian exit; the Scraping Browser API gives a remote browser with a chosen country. No captcha is configured on any page captured; the solver is wired in and bounded to one solve per page in case one appears.

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

Good to know

  • Pages after the first are disallowed by screener.in's robots.txt; every engine warns when a run would request them.
  • Prices and ranks move during Indian market hours, so compare runs by sku.
  • --concurrency and --fingerprint are implemented in the Playwright engine only; the plain-HTTP engine has no captcha solving.

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

Screener.in scraper FAQ

Which pages does it scrape?

Any stock screen (/screens/{id}/{slug}/) and any sector or industry listing (/market/…). Nothing is hardcoded: the URL you give decides what a run covers.

Do I need a proxy or a 2Captcha key?

No, not from an ordinary connection. Paid products buy volume, an Indian exit or no local browser.

Can I get every page of a listing?

The scraper can plan every page from the site's own page count, but pages after the first are ?page= URLs, which screener.in's robots.txt disallows for all user agents. Read the robots.txt and the site's terms before running multi-page jobs.

Can I get 50 rows per page?

No. ?limit=10 and ?limit=50 both returned 25 rows to an anonymous visitor, so there is deliberately no --limit flag.

What formats does it write?

JSON and CSV, plus a .meta.json sidecar with status, total_results, pages_available, coverage (exhaustive, tail or window) and a SHA-256 of each data file.

Is scraping screener.in legal?

It reads publicly available tables. Respect robots.txt and the site's terms, rate-limit with --delay, and follow the law where you operate; the data itself is supplied to screener.in by a third party.