A Playwright-powered Python package for extracting structured financial data from Screener.in.
Project description
openscreener
openscreener is a Playwright-powered Python library for extracting structured financial data from Screener.in.
It loads live stock and index pages, detects the page type, and returns normalized Python dictionaries and lists for the sections you care about.
Highlights
- High-level APIs for single stocks, indexes, and batch stock fetches
- Normalized outputs for summary, analysis, peers, quarterly results, profit and loss, balance sheet, cash flow, ratios, and shareholding
- Index support with constituent pagination handling
- Pretty terminal output, JSON export, and optional pandas DataFrame conversion
- Helpful errors when a section is missing or the wrong class is used for a page
Installation
openscreener requires Python 3.10+.
Install the package:
pip install openscreener
Install Playwright browser binaries:
python -m playwright install chromium
Install pandas if you want to_dataframe() support:
pip install pandas
Install development dependencies when working on the repo:
pip install -e .[dev]
Quick Start
Stock
from openscreener import Stock
stock = Stock("TCS")
summary = stock.summary()
print(summary["company_name"])
print(summary["current_price"])
print(summary["ratios"]["market_cap"])
analysis = stock.pros_cons()
print(analysis["pros"][0])
payload = stock.fetch(["summary", "ratios", "shareholding"])
print(payload["ratios"]["roce_percent"])
stock.pretty("summary")
stock.pretty("cash_flow")
print(stock.metadata())
Index
from openscreener import Index
index = Index("CNX500")
print(index.page_type()) # index
print(index.summary()["company_name"])
constituents = index.constituents(limit=70)
print(constituents["returned_companies"])
print(constituents["companies"][0]["symbol"])
index.pretty("constituents", constituents_limit=20)
Batch
from openscreener import Stock
batch = Stock.batch(["TCS", "INFY"])
ratios_by_symbol = batch.fetch("ratios")
print(ratios_by_symbol["TCS"]["roce_percent"])
payload_by_symbol = batch.fetch(["summary", "shareholding"])
print(payload_by_symbol["INFY"]["summary"]["company_name"])
JSON And DataFrame Helpers
from openscreener import Stock
stock = Stock("TCS")
print(stock.to_json())
frame = stock.to_dataframe("peers")
print(frame.head())
Public API
from openscreener import BatchStock, Index, PlaywrightScraper, Stock
Stock
Stock(symbol: str, consolidated: bool = False, scraper: PlaywrightScraper | None = None)
Main methods:
summary()pros_cons()pros()cons()peers()quarterly_results()profit_loss()balance_sheet()cash_flow()ratios()shareholding(frequency="quarterly")shareholding_quarterly()shareholding_yearly()fetch(sections, constituents_limit=None)all()available_sections()page_type()is_stock()is_index()pretty(section=None, constituents_limit=None)print_section(section, constituents_limit=None)to_json(indent=2, constituents_limit=None)to_dataframe(section)metadata()
Index
Index(symbol: str, scraper: PlaywrightScraper | None = None)
Main methods:
summary()constituents(limit=None)fetch(sections, constituents_limit=None)all(constituents_limit=None)available_sections()page_type()pretty(section=None, constituents_limit=None)print_section(section, constituents_limit=None)to_json(indent=2, constituents_limit=None)to_dataframe(section)metadata()
BatchStock
BatchStock(
symbols,
consolidated: bool = False,
scraper: PlaywrightScraper | None = None,
)
Main method:
fetch(sections)
Shortcut constructor:
from openscreener import Stock
batch = Stock.batch(["TCS", "INFY"])
PlaywrightScraper
PlaywrightScraper(
base_url="https://www.screener.in/company/{symbol}{path_suffix}",
consolidated=False,
headless=True,
timeout_ms=30000,
)
Main methods:
fetch_page(symbol)fetch_pages(symbols)fetch_constituent_pages(symbol, page_numbers, page_size=50)
Supported Sections
Stock Sections
| Canonical section | Accepted aliases | Method | Return shape |
|---|---|---|---|
summary |
summary |
summary() |
dict |
analysis |
analysis, pros_cons |
pros_cons() |
dict |
peers |
peers |
peers() |
dict |
quarterly_results |
quarters, quarterly_results |
quarterly_results() |
list[dict] |
profit_loss |
profit-loss, profit_loss |
profit_loss() |
list[dict] |
balance_sheet |
balance-sheet, balance_sheet |
balance_sheet() |
list[dict] |
cash_flow |
cash-flow, cash_flow |
cash_flow() |
list[dict] |
ratios |
ratios |
ratios() |
dict |
shareholding |
shareholding |
shareholding() |
list[dict] |
Index Sections
| Canonical section | Accepted aliases | Method | Return shape |
|---|---|---|---|
summary |
summary |
summary() |
dict |
constituents |
constituents, companies |
constituents(limit=None) |
dict |
Helper-Only Section Names
These work with pretty(), print_section(), and to_dataframe() where applicable:
prosconsshareholding_quarterlyshareholding_yearly
Behavior Notes
Stock("TCS")is for stock pages.Index("CNX500")orIndex("NIFTY")is for index pages.page_type()returnsstock,index, orunknown.- Using the wrong class for a page raises
EntityTypeMismatchError. available_sections()depends on whether the resolved page is a stock or an index.stock.fetch("ratios")returns{"ratios": {...}}.index.all(constituents_limit=100)limits the returned constituent rows in the payload.summary()["ratios"]contains top-card metrics such as market cap, current price, high/low, and similar values.ratios()returns the latest annual ratios row, not the whole historical ratios table.shareholding()defaults to quarterly data.metadata()returns source metadata such as symbol, entity type, currency, units, and company or index name when available.
Output Helpers
Pretty-print one section or the full payload:
from openscreener import Stock
stock = Stock("TCS")
stock.pretty()
stock.pretty("summary")
stock.print_section("pros")
Index pretty-printing works the same way:
from openscreener import Index
index = Index("CNX500")
index.pretty("constituents", constituents_limit=50)
If pandas is installed, you can convert tabular sections to DataFrames:
from openscreener import Stock
stock = Stock("TCS")
frame = stock.to_dataframe("cash_flow")
print(frame.head())
If pandas is not installed, to_dataframe() raises an ImportError with an install hint.
Data Conventions
- Numeric values are converted to
intorfloatwhere possible. - Missing values are returned as
None. - Period labels remain strings such as
Dec 2025,Mar 2025, orTTM. - Monetary values and units follow Screener's presentation.
- Default metadata reports
INRcurrency andcroresunits.
Development
Repository layout:
src/openscreener/ Package source
src/openscreener/parsers/ Section parsers
tests/ Automated tests
Run the local checks:
python -m pytest -q
python -m build --no-isolation
python -m twine check dist/*
Releasing A New Version
- Bump the version in
pyproject.toml. - Run the test and build checks.
- Upload the new distribution files.
python -m pytest -q
python -m build --no-isolation
python -m twine check dist/*
python -m twine upload dist/*
Each PyPI upload must use a new version number.
Limitations
- Parsing depends on Screener.in's current HTML structure.
- Live usage requires Playwright and installed browser binaries.
- Missing sections raise
SectionNotFoundError. - Large index fetches depend on Screener's pagination remaining accessible.
- The project exposes a Python API; it does not currently provide a packaged CLI.
Use the live scraper responsibly and in a way that respects Screener.in's terms and rate limits.
License
MIT. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file openscreener-0.1.0.tar.gz.
File metadata
- Download URL: openscreener-0.1.0.tar.gz
- Upload date:
- Size: 20.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7d9dd7f822a0ac4f36300f2c8f93ea0da4fe1e8e948dd6b1e443f496579437f0
|
|
| MD5 |
1071489deb73216d9151c880e95b53ee
|
|
| BLAKE2b-256 |
42861c4805ae25898907e171308a7b18e2408925a05aad7990300d2a7d9fc5cb
|
File details
Details for the file openscreener-0.1.0-py3-none-any.whl.
File metadata
- Download URL: openscreener-0.1.0-py3-none-any.whl
- Upload date:
- Size: 27.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ba5e95b85c82cd531b3c152aef9282288c4369674bef377ff71fa5268e302058
|
|
| MD5 |
b099ae242af123cf460074957fdc32fa
|
|
| BLAKE2b-256 |
b1061e15fb281607653a818dac2ba56bad294dd33b7b7dcb8484a57ea1b914cf
|