What the TipRanks scraper collects
Give it one or more stock tickers and it reads each one's TipRanks forecast page: Smart Score, the Buy/Hold/Sell consensus, analyst counts and the average, high and low price targets, plus the same set for TipRanks' best-performing analysts. It reads the same JSON the page loads for itself, never the DOM, and writes JSON or CSV.
Ticker forecast snapshot
Input: One or more ticker symbols, or a file of themOne row per ticker: Smart Score, consensus label, buy/hold/sell counts, price targets and upside, the best-analyst subset, and a best-effort current price.
From zero to TipRanks data in 3 steps
Install
Clone the repository and install one browser engine. Python 3.9+.
$ git clone https://github.com/2scraper/tipranks-scraper.git && cd tipranks-scraper $ pip install -r requirements-playwright.txt $ playwright install chromium $ python3 playwright_scraper.py --ticker AAPL --ticker MSFT --format json --out results.json
Run a scraper
Pick what you need and run it. Every flag is documented in the README.
$ python3 playwright_scraper.py --ticker AAPL --ticker MSFT --format json --out results.jsonGet structured data
Rows land in JSON or CSV (
--format), with a.meta.jsonsidecar recording status, pages fetched and why the run stopped.
TipRanks data fields
28 columns per row in a predictable schema. The most useful ones:
| Field | What it holds |
|---|---|
ticker | The stock symbol asked for |
company_name | Company name |
smart_score | TipRanks' own 1-10 Smart Score |
smart_score_updated | When the Smart Score was last updated |
consensus_rating_id | The site's raw consensus id, e.g. moderateBuy |
consensus_rating_label | Human-readable consensus, e.g. Moderate Buy |
analyst_count | Analysts in the consensus |
buy_count | Buy ratings |
hold_count | Hold ratings |
sell_count | Sell ratings |
price_target_average | Average analyst price target |
price_target_high | Highest price target |
price_target_low | Lowest price target |
price_target_upside | Upside to the average target, as a fraction (-0.018 = -1.8%) |
best_consensus_rating_label | Consensus among TipRanks' best-performing analysts |
current_price | Best-effort quote; can lag the page's own price |
[
{
"ticker": "AAPL",
"source": "tipranks",
"source_url": "https://www.tipranks.com/stocks/aapl/stock-analysis",
"scraped_at": "2026-09-27T09:37:57+00:00",
"company_name": "Apple",
"currency": "USD",
"smart_score": 7,
"smart_score_updated": "2026-09-27T00:00:00.000Z",
"consensus_rating_id": "moderateBuy",
"consensus_rating_label": "Moderate Buy",
"analyst_count": 30,
"buy_count": 15,
"hold_count": 11,
"sell_count": 4,
"price_target_average": 334.8982608695652,
"price_target_high": 400,
"price_target_low": 245,
"price_target_upside": -0.01809522716871903,
"best_consensus_rating_id": "moderateBuy",
"best_consensus_rating_label": "Moderate Buy",
"best_analyst_count": 23,
"best_buy_count": 12,
"best_hold_count": 8,
"best_sell_count": 3,
"best_price_target_average": 334.8623529411765,
"current_price": 319.97,
"current_price_asof": "2026-08-31T14:10:19.000Z",
"current_price_source": "open"
}
]First 2 of 1 rows from a real run — sample_output.json. Long values shortened here.
Handles what breaks naive TipRanks scrapers
Reads the page's own JSON
The forecast page loads its data from a same-origin payload.json. The scraper drives a real browser to the page and reads that JSON, so no field depends on a CSS selector.
Best analysts kept separate
TipRanks' Best Performing Analysts subset is a different, smaller population. Its figures go in best_* columns and are never merged with the full consensus.
Missing analyst data is not an error
Some tickers carry a price target with no buy/hold/sell breakdown, and some none at all. Those fields come back null, and an unknown ticker is a completed ticker with zero rows, not a failure.
Blocks told apart from outages
A Cloudflare interstitial or a real 403/429 exits 3, a network failure exits 5, some tickers failing exits 6 — so a caller knows whether it was rejected or simply disconnected.
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 TipRanks snapshots by id — new, removed and changed rows for monitoring.
What teams do with TipRanks data
Watchlist consensus tracking
Snapshot analyst consensus and price targets for a list of tickers daily and diff runs to catch rating and target changes.
Screening by upside
Rank tickers by price_target_upside or Smart Score as one input into a screen.
Analyst sentiment research
Compare the full analyst consensus with the best-performing analysts' view for the same stock.
Portfolio dashboards
Feed Smart Score and consensus for your holdings into a spreadsheet or BI tool via CSV.
Free to run. Pay only for what the site requires.
Free to run · paid add-ons optional
A normal run needs no account, no proxy and no captcha key: a local headless Chromium read roughly 20 tickers over 35+ requests with clean 200s. Cloudflare has since shown its JS interstitial after repeated runs from one environment, and to GitHub's datacentre runners. For that, --proxy gives a fresh exit and --cdp-endpoint the Scraping Browser API's managed device identity; captcha solving is wired in for parity, though no captcha widget has been met on this site.
Optional 2Captcha services — captcha solving, the Scraping Browser API, residential proxies and fingerprints — work behind one key.
Good to know
- Only the ticker forecast page — no screeners, insider-trading or hedge-fund pages.
- The --scraper-api and --scraper-api-cdp paths are wired and unit-tested but not yet exercised against the live site.
- Non-USD tickers are untested.
2scraper vs. hosted scraper APIs
| 2scraper | Typical hosted API | |
|---|---|---|
| Code | Open source, MIT — read and patch it | Closed |
| Cost | Free; optional services billed only when used | Subscription or per request / per result |
| Runs on | Your machine, server or CI | The vendor's infrastructure |
| Output | JSON/CSV files + run metadata | API responses |
| When the site changes | Fix it yourself or open an issue / PR | Wait for the vendor |
TipRanks scraper FAQ
Do I need a TipRanks account?
No. It reads the free, unauthenticated forecast page data that any visitor sees.
How do I scrape many tickers?
Repeat --ticker, or pass --tickers-file with one symbol per line.
Why is current_price different from the website?
The payload's quote sits behind edge caching and can lag the page's own rendered price, so treat it as a possibly stale snapshot, not a real-time quote.
Why are some consensus fields null?
Some tickers have a price target with no buy/hold/sell breakdown, and some have no analyst data at all. That is the site's real shape, not a parser bug.
What does robots.txt allow?
It disallows /api/* but not the /stocks/ forecast pages this repo reads, and the scraper re-checks robots.txt at runtime.
Is scraping TipRanks legal?
It reads public, free data. Follow TipRanks' terms and the law in your jurisdiction.