Monitoring stock market data programmatically lets you track prices, build alert systems, backtest strategies, and create custom dashboards without paying for premium financial platforms. Python has a rich ecosystem for financial data, but many free APIs have limitations -- delayed data, low rate limits, or restricted access to historical data.
This tutorial shows how to build a stock monitoring system using SearchHive's web scraping APIs alongside Python's data analysis tools. You'll scrape real-time quotes, track a watchlist, and set up price alerts.
Key Takeaways
- SearchHive's SwiftSearch and ScrapeForge can scrape stock data from public financial sites
- DeepDive extracts structured financial data (price, volume, market cap) from any page
- Python's
schedulelibrary automates periodic data collection - Store time-series data in SQLite for trend analysis and alerting
- The free tier handles thousands of data points before needing a paid plan
Prerequisites
- Python 3.10+
- A SearchHive API key (free here)
- Basic Python knowledge
Install dependencies:
pip install requests pandas schedule
Step 1: Scrape Stock Quotes
Use SearchHive to scrape stock data from financial sites that publish real-time or near-real-time quotes.
import requests
import json
API_KEY = "your_searchhive_api_key"
def get_stock_quote(symbol: str) -> dict:
# Scrape current stock data for a given ticker symbol
url = f"https://finance.yahoo.com/quote/{symbol}"
response = requests.post(
"https://api.searchhive.dev/v1/deepdive",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
},
json={
"url": url,
"prompt": (
f"Extract the following for {symbol}: "
"current price, previous close, open, day high, day low, "
"volume, average volume, market cap, PE ratio, "
"52-week high, 52-week low. Return as JSON."
)
}
)
response.raise_for_status()
return response.json()
quote = get_stock_quote("AAPL")
print(json.dumps(quote, indent=2))
Step 2: Build a Watchlist Monitor
Track multiple stocks simultaneously with a watchlist system.
import time
DEFAULT_WATCHLIST = ["AAPL", "GOOGL", "MSFT", "AMZN", "TSLA"]
def scan_watchlist(symbols: list) -> list:
# Fetch quotes for all symbols in the watchlist
results = []
for symbol in symbols:
try:
data = get_stock_quote(symbol)
data["symbol"] = symbol
data["timestamp"] = time.strftime("%Y-%m-%d %H:%M:%S")
results.append(data)
print(f" {symbol}: ${data.get('current price', 'N/A')}")
time.sleep(0.5) # Rate limiting
except Exception as e:
print(f" {symbol}: Error - {e}")
return results
stocks = scan_watchlist(DEFAULT_WATCHLIST)
Step 3: Store Data in SQLite
Build a time-series database for historical tracking and analysis.
import sqlite3
from datetime import datetime
def init_stock_db():
conn = sqlite3.connect("stocks.db")
conn.execute("""
CREATE TABLE IF NOT EXISTS stock_quotes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
symbol TEXT NOT NULL,
price REAL,
volume INTEGER,
market_cap TEXT,
timestamp TEXT NOT NULL,
UNIQUE(symbol, timestamp)
)
""")
conn.execute("""
CREATE INDEX IF NOT EXISTS idx_symbol
ON stock_quotes(symbol, timestamp)
""")
conn.commit()
return conn
def store_quote(conn, symbol: str, data: dict):
price = data.get("current price")
if price is None:
return
price_str = str(price).replace("$", "").replace(",", "")
try:
price_float = float(price_str)
except ValueError:
return
conn.execute("""
INSERT OR IGNORE INTO stock_quotes
(symbol, price, volume, market_cap, timestamp)
VALUES (?, ?, ?, ?, ?)
""", (
symbol,
price_float,
data.get("volume"),
data.get("market cap"),
datetime.now().isoformat()
))
conn.commit()
conn = init_stock_db()
for stock in stocks:
store_quote(conn, stock["symbol"], stock)
print(f"Stored {len(stocks)} quotes")
Step 4: Calculate Moving Averages
Analyze stored data for technical indicators.
import pandas as pd
def get_price_history(conn, symbol: str, days: int = 30) -> pd.DataFrame:
df = pd.read_sql_query(
"SELECT price, timestamp FROM stock_quotes "
f"WHERE symbol = '{symbol}' "
"ORDER BY timestamp DESC LIMIT ?",
conn, params=(days * 24 * 4,)
)
df["timestamp"] = pd.to_datetime(df["timestamp"])
df = df.sort_values("timestamp")
return df
def calculate_indicators(df: pd.DataFrame) -> pd.DataFrame:
if len(df) < 2:
return df
df["sma_5"] = df["price"].rolling(window=5).mean()
df["sma_20"] = df["price"].rolling(window=20).mean()
df["price_change"] = df["price"].pct_change() * 100
return df
history = get_price_history(conn, "AAPL")
indicators = calculate_indicators(history)
print(indicators.tail())
Step 5: Set Up Price Alerts
Get notified when stocks cross price thresholds.
class PriceAlert:
def __init__(self, symbol: str, condition: str, target: float):
self.symbol = symbol
self.condition = condition # "above", "below"
self.target = target
def check(self, current_price: float) -> bool:
if self.condition == "above":
return current_price >= self.target
elif self.condition == "below":
return current_price <= self.target
return False
def check_alerts(conn, alerts: list) -> list:
triggered = []
for alert in alerts:
df = get_price_history(conn, alert.symbol, days=1)
if df.empty:
continue
current = df["price"].iloc[-1]
if alert.check(current):
triggered.append({
"symbol": alert.symbol,
"condition": alert.condition,
"target": alert.target,
"current": current
})
print(f"ALERT: {alert.symbol} is {alert.condition} "
f"${alert.target} (current: ${current:.2f})")
return triggered
# Set up alerts
alerts = [
PriceAlert("AAPL", "above", 200.0),
PriceAlert("TSLA", "below", 150.0),
]
triggered = check_alerts(conn, alerts)
Step 6: Automate with Scheduled Monitoring
Run the monitor on a schedule using Python's schedule library.
import schedule
def monitor_job():
print(f"\n[{time.strftime('%H:%M:%S')}] Running monitor...")
data = scan_watchlist(DEFAULT_WATCHLIST)
for stock in data:
store_quote(conn, stock["symbol"], stock)
# Check alerts
triggered = check_alerts(conn, alerts)
if triggered:
for t in triggered:
print(f"ALERT: {t['symbol']} {t['condition']} "
f"${t['target']} (now ${t['current']:.2f})")
# Schedule every 15 minutes during market hours
schedule.every(15).minutes.do(monitor_job)
print("Stock monitor started. Press Ctrl+C to stop.")
while True:
schedule.run_pending()
time.sleep(1)
Step 7: Visualize with Matplotlib
Create price charts from your stored data.
import matplotlib.pyplot as plt
def plot_stock_price(conn, symbol: str):
df = get_price_history(conn, symbol)
if df.empty:
print(f"No data for {symbol}")
return
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8),
sharex=True, height_ratios=[3, 1])
# Price line
ax1.plot(df["timestamp"], df["price"], "b-", linewidth=1.5)
if "sma_20" in df.columns:
ax1.plot(df["timestamp"], df["sma_20"], "r--",
label="20-period SMA", alpha=0.7)
ax1.set_ylabel("Price ($)")
ax1.set_title(f"{symbol} Price History")
ax1.legend()
ax1.grid(True, alpha=0.3)
# Volume bar (if available)
if "volume" in df.columns:
ax2.bar(df["timestamp"], df["volume"], alpha=0.5)
ax2.set_ylabel("Volume")
ax2.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig(f"{symbol}_price.png", dpi=150)
print(f"Chart saved to {symbol}_price.png")
plot_stock_price(conn, "AAPL")
Complete Code Example
import requests
import sqlite3
import time
from datetime import datetime
API_KEY = "your_searchhive_api_key"
WATCHLIST = ["AAPL", "GOOGL", "MSFT"]
def get_stock_quote(symbol: str) -> dict:
response = requests.post(
"https://api.searchhive.dev/v1/deepdive",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
},
json={
"url": f"https://finance.yahoo.com/quote/{symbol}",
"prompt": f"Extract current price, volume, and market cap for {symbol}. JSON."
}
)
return response.json()
def main():
conn = sqlite3.connect("stocks.db")
conn.execute("""
CREATE TABLE IF NOT EXISTS stock_quotes (
symbol TEXT, price REAL, timestamp TEXT
)
""")
for symbol in WATCHLIST:
try:
data = get_stock_quote(symbol)
price_str = str(data.get("current price", "")).replace("$", "").replace(",", "")
price = float(price_str) if price_str else 0
conn.execute(
"INSERT INTO stock_quotes VALUES (?, ?, ?)",
(symbol, price, datetime.now().isoformat())
)
print(f"{symbol}: ${price:.2f}")
except Exception as e:
print(f"{symbol}: error - {e}")
time.sleep(1)
conn.commit()
conn.close()
if __name__ == "__main__":
main()
Common Issues
Yahoo Finance blocking requests: Yahoo Finance uses aggressive anti-scraping measures. SearchHive's proxy rotation and JS rendering handle most of this, but if issues persist, try alternative sources like Google Finance.
Stale data on cached pages: Some financial sites cache aggressively. Add cache-busting parameters or use ScrapeForge directly with the raw page URL.
Inconsistent price formats: Prices appear as "$150.23", "1,50.23" (European), or "150.23". Always strip non-numeric characters and handle decimal separators carefully.
Market hours limitation: Data is most reliable during market hours (9:30 AM - 4:00 PM ET). Outside these hours, quotes reflect the last close. Add a market hours check before alerting.
Rate limits on free tier: SearchHive's free tier (500 credits) handles about 500 stock quote lookups. For continuous monitoring, the $9/mo Starter plan gives 5,000 credits -- enough for a 15-minute polling cycle across 10 stocks for a full month.
Next Steps
- Add email/Slack notifications for triggered alerts
- Build a Streamlit dashboard for interactive price viewing
- Implement technical analysis indicators (RSI, MACD, Bollinger Bands)
- Add fundamental data (earnings, dividends) from SEC filings via DeepDive
- Set up the scheduler as a systemd service or deploy to Railway
Start monitoring stocks with 500 free credits from SearchHive. Scrape any public financial data source with JS rendering and proxy rotation built in. No credit card required.
See also: /blog/how-to-build-a-python-api-wrapper-for-web-scraping-services, /compare/serpapi, /compare/firecrawl