Read data from a Weather Underground personal weather station - temperature, feels-like (wind chill or heat index), dewpoint, humidity, wind and pressure - from the returned api request's JSON.
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-11-01 12:51:01 -07:00
.gitignore initial commit 2026-11-01 12:51:01 -07:00
.python-version initial commit 2026-11-01 12:51:01 -07:00
main.py initial commit 2026-11-01 12:51:01 -07:00
pyproject.toml initial commit 2026-11-01 12:51:01 -07:00
README.md initial commit 2026-11-01 12:51:01 -07:00
uv.lock initial commit 2026-11-01 12:51:01 -07:00
wunderground_scraper.py initial commit 2026-11-01 12:51:01 -07:00

Weather Underground scraper

Built with Claude: https://claude.ai/code/session_01RVqY2qqn2TPjqZPaMBCTxv

Setup

sudo apt install libnss3 libnspr4
uv sync
uv run playwright install chromium

Usage

uv run python wunderground_scraper.py KCASANFR2249
uv run python wunderground_scraper.py KCASANFR2249 --json
uv run python wunderground_scraper.py KCASANFR2249 --headed

Other options: --timeout SECONDS, --user-agent STRING, --debug-dir DIR (pass '' to disable).

How it gets the reading

  1. API capture (preferred): while the dashboard loads, the scraper listens for the page's own request to api.weather.com/v2/pws/observations/current and reads temperature, feels-like (wind chill or heat index), dewpoint, humidity, wind and pressure from the JSON. This keeps working when Wunderground restyles the page.
  2. DOM fallback: the original .main-temp lib-display-unit span.wu-value selector.

The output says which one it used: [via api] or [via dom].

When it fails

It prints a diagnosis instead of a generic timeout, and saves debug/<station>-<timestamp>.png, .html and .txt:

  • HTTP 403/429 or "Access Denied" page: bot/rate-limit blocking (Akamai). Try --headed, wait a while, or run it from another IP.
  • API call returned no temperature: the station is offline or not reporting.
  • Dashboard never booted, no API call made: the page itself changed; check the screenshot.