A Python library and CLI tool that scrapes portfolio holdings from Racional, a Chilean investment platform. Since Racional has no public API, this tool uses headless browser automation (Playwright) to log in, handle email-based 2FA, and intercept the internal API responses to extract your positions.
For each position in your Racional Stocks account:
| Field | Description |
|---|---|
symbol |
Ticker symbol (e.g. VRT, CEG) |
shares |
Number of shares (supports fractional) |
avg_cost |
Average cost basis per share (USD) |
market_value_usd |
Current market value (USD) |
unrealized_pl |
Unrealized profit/loss (USD) |
unrealized_pl_pct |
Unrealized P/L as percentage |
weight_pct |
Position weight in portfolio (%) |
It also extracts cash (buying power available for trading).
1. Launch headless Chromium via Playwright
2. Navigate to app.racional.cl/login
3. Fill email + password, submit
4. Detect 2FA modal -> read OTP code from Gmail via IMAP
5. Submit 2FA code
6. Navigate to portfolio page
7. Intercept api.racional.cl/positions JSON response
8. Return structured holdings data
The tool intercepts Racional's internal api.racional.cl/positions endpoint (which powers the frontend) rather than scraping DOM elements, making it more reliable.
- Python 3.10+
- A Racional account
- A Gmail account (for reading 2FA codes via IMAP)
- A Gmail App Password (requires 2-Step Verification on your Google account)
# Clone the repository
git clone https://github.com/maximilianomilitzer/RacionalScrapper.git
cd RacionalScrapper
# Install the package
pip install .
# Install Playwright's Chromium browser
playwright install chromiumOr install in development mode:
pip install -e .
playwright install chromiumCopy the example environment file and fill in your credentials:
cp .env.example .envEdit .env:
RACIONAL_EMAIL=your-email@gmail.com
RACIONAL_PASSWORD=your-racional-password
# Gmail App Password for reading 2FA emails
IMAP_USER=your-email@gmail.com
IMAP_PASSWORD=abcd-efgh-ijkl-mnop- Go to myaccount.google.com/apppasswords
- You need 2-Step Verification enabled on your Google account
- Create a new App Password (select "Mail" or "Other")
- Copy the 16-character password into
IMAP_PASSWORD
# Scrape holdings (table output)
racional-scrapper
# Scrape holdings (JSON output)
racional-scrapper --json
# Discovery mode: dump all intercepted API responses
racional-scrapper --discover
# Run with visible browser for debugging
racional-scrapper --no-headless
# Verbose logging
racional-scrapper -vExample output:
Scraped 4 holdings (cash: $0)
Symbol Shares Avg Cost Value (USD) P/L %
------------------------------------------------------------
AEM 1.5804 250.97 367.81 -7.27%
CEG 1.5614 322.85 504.10 9.62%
SGOV 8.5000 100.02 850.20 0.01%
VRT 15.2000 92.65 1408.58 49.35%
from racional_scrapper import scrape_holdings
result = scrape_holdings(
email="your-email@gmail.com",
password="your-racional-password",
imap_user="your-email@gmail.com",
imap_password="your-gmail-app-password",
)
for holding in result["holdings"]:
print(f"{holding['symbol']}: {holding['shares']} shares @ ${holding['avg_cost']:.2f}")
print(f"Cash available: ${result['cash']}")The scrape_holdings() function returns:
{
"holdings": [
{
"symbol": "VRT",
"shares": 15.2,
"avg_cost": 92.65,
"market_value_usd": 1408.58,
"unrealized_pl": 468.72,
"unrealized_pl_pct": 49.85,
"weight_pct": 45.0,
},
# ...
],
"cash": Decimal("0"),
"account_summary": { ... }, # Raw DriveWealth account summary JSON
}If the scraper breaks (e.g. Racional updates their app), use discovery mode to inspect what API calls the app is making:
from racional_scrapper import discover
result = discover(
email="your-email@gmail.com",
password="your-racional-password",
imap_user="your-email@gmail.com",
imap_password="your-gmail-app-password",
)
for url in result["urls"]:
print(url)If you want to run this in a container:
FROM python:3.12-slim
WORKDIR /app
COPY . .
RUN pip install --no-cache-dir . && \
playwright install chromium && \
playwright install-deps
CMD ["racional-scrapper", "--json"]- Racional uses email-based 2FA on every login. The scraper handles this automatically by reading the OTP code from Gmail via IMAP.
- The 2FA code expires after 5 minutes. The IMAP poller waits up to 90 seconds for the email to arrive.
- Racional is an Ionic/Angular SPA that uses Firebase for authentication and DriveWealth as the brokerage backend.
- This tool only reads your portfolio data. It does not execute trades or modify your account in any way.
This tool is not affiliated with, endorsed by, or associated with Racional SpA. Use it at your own risk and in compliance with Racional's terms of service. The author is not responsible for any consequences of using this tool.
MIT