Skip to main content

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:

  • pros
  • cons
  • shareholding_quarterly
  • shareholding_yearly

Behavior Notes

  • Stock("TCS") is for stock pages.
  • Index("CNX500") or Index("NIFTY") is for index pages.
  • page_type() returns stock, index, or unknown.
  • 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 int or float where possible.
  • Missing values are returned as None.
  • Period labels remain strings such as Dec 2025, Mar 2025, or TTM.
  • Monetary values and units follow Screener's presentation.
  • Default metadata reports INR currency and crores units.

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

  1. Bump the version in pyproject.toml.
  2. Run the test and build checks.
  3. 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

openscreener-0.1.0.tar.gz (20.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

openscreener-0.1.0-py3-none-any.whl (27.4 kB view details)

Uploaded Python 3

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

Hashes for openscreener-0.1.0.tar.gz
Algorithm Hash digest
SHA256 7d9dd7f822a0ac4f36300f2c8f93ea0da4fe1e8e948dd6b1e443f496579437f0
MD5 1071489deb73216d9151c880e95b53ee
BLAKE2b-256 42861c4805ae25898907e171308a7b18e2408925a05aad7990300d2a7d9fc5cb

See more details on using hashes here.

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

Hashes for openscreener-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ba5e95b85c82cd531b3c152aef9282288c4369674bef377ff71fa5268e302058
MD5 b099ae242af123cf460074957fdc32fa
BLAKE2b-256 b1061e15fb281607653a818dac2ba56bad294dd33b7b7dcb8484a57ea1b914cf

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page