-
Notifications
You must be signed in to change notification settings - Fork 0
Add robustness and engineering polish #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
996d235
Rename package to breach_scraper
noderaven bf0ad3c
Add pyproject with console script and dev tooling config
noderaven dff1fd3
Add retries, HTTP 403 handling, offline input, and CLI guard
noderaven a23634d
Apply ruff, mypy strict, and bandit clean-up
noderaven 8adb211
Add GitHub Actions CI (ruff, mypy, bandit, tests on 3.10-3.13)
noderaven e1c3a53
Expand README and gitignore
noderaven 10ed280
Harden fetch error handling per review (HTTPException, charset, backo…
noderaven File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| name: CI | ||
|
|
||
| on: | ||
| push: | ||
| branches: [main] | ||
| pull_request: | ||
| branches: [main] | ||
|
|
||
| jobs: | ||
| test: | ||
| runs-on: ubuntu-latest | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| python-version: ["3.10", "3.11", "3.12", "3.13"] | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Set up Python ${{ matrix.python-version }} | ||
| uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: ${{ matrix.python-version }} | ||
| - name: Install | ||
| run: | | ||
| python -m pip install --upgrade pip | ||
| pip install -e ".[dev]" | ||
| - name: Ruff lint | ||
| run: ruff check . | ||
| - name: Ruff format check | ||
| run: ruff format --check . | ||
| - name: Mypy | ||
| run: mypy | ||
| - name: Bandit | ||
| run: bandit -r breach_scraper | ||
| - name: Tests | ||
| run: python -m unittest discover -s tests -v |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,8 @@ | ||
| __pycache__/ | ||
| *.pyc | ||
| .venv/ | ||
| .mypy_cache/ | ||
| .ruff_cache/ | ||
| dist/ | ||
| build/ | ||
| *.egg-info/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,28 +1,60 @@ | ||
| # breach-web-scraper | ||
| A Python tool for scraping breach websites to provide a nice summary. | ||
|
|
||
| ## WA AG scraper (initial source) | ||
| This repository now includes a scraper for Washington Attorney General data breach notifications: | ||
| [](https://github.com/noderaven/breach-web-scraper/actions/workflows/ci.yml) | ||
| [](LICENSE) | ||
| [](pyproject.toml) | ||
|
|
||
| - Source URL: `https://www.atg.wa.gov/data-breach-notifications` | ||
| - Script: `scraper/wa_atg_scraper.py` | ||
| A Python tool for scraping breach websites to provide a nice summary. The first | ||
| supported source is the Washington State Attorney General data breach | ||
| notifications page. Runtime dependencies: none (standard library only). | ||
|
|
||
| ## Install | ||
|
|
||
| ### Usage | ||
| ```bash | ||
| python scraper/wa_atg_scraper.py --output json --limit 10 | ||
| python scraper/wa_atg_scraper.py --output markdown --out-file wa_breaches.md | ||
| python scraper/wa_atg_scraper.py --output csv --out-file wa_breaches.csv | ||
| pip install . | ||
| ``` | ||
|
|
||
| ### Output fields | ||
| The parser normalizes column names from the HTML table to `snake_case`. For cells containing links, it also emits a `<column>_url` field. | ||
| This installs the `breach-scraper` console command. | ||
|
|
||
| ### Known hurdles / maintenance notes | ||
| - The scraper depends on the page containing a parseable HTML table. | ||
| - If WA AG changes table structure or field names, parsing/normalization may need updates. | ||
| - For production automation, add retries/backoff, persistence, and monitoring around this script. | ||
| ## Usage | ||
|
|
||
| ### Tests | ||
| ```bash | ||
| python -m unittest discover -s tests | ||
| # Fetch live and print JSON (default), limited to 10 rows | ||
| breach-scraper --output json --limit 10 | ||
|
|
||
| # Markdown / CSV to a file | ||
| breach-scraper --output markdown --out-file wa_breaches.md | ||
| breach-scraper --output csv --out-file wa_breaches.csv | ||
|
|
||
| # Offline: parse a previously saved page (no network) | ||
| breach-scraper --input-html saved_page.html --output json | ||
|
|
||
| # Override the User-Agent or retry count | ||
| breach-scraper --user-agent "my-agent/1.0" --retries 5 | ||
| ``` | ||
|
|
||
| If the source returns HTTP 403, the tool prints an actionable message; use | ||
| `--input-html` with a saved copy of the page, a different network, or a | ||
| different `--user-agent`. | ||
|
|
||
| ## Output fields | ||
|
|
||
| Column names from the HTML table are normalized to `snake_case`. Cells that | ||
| contain links also emit a `<column>_url` field. | ||
|
|
||
| ## Development | ||
|
|
||
| ```bash | ||
| pip install -e ".[dev]" | ||
| ruff check . | ||
| ruff format --check . | ||
| mypy | ||
| bandit -r breach_scraper | ||
| python -m unittest discover -s tests -v | ||
| ``` | ||
|
|
||
| ## Source / maintenance notes | ||
|
|
||
| - Source URL: `https://www.atg.wa.gov/data-breach-notifications` | ||
| - The scraper depends on the page exposing a parseable HTML table; if the WA AG | ||
| changes the table structure or field names, parsing may need updates. |
File renamed without changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| [build-system] | ||
| requires = ["hatchling"] | ||
| build-backend = "hatchling.build" | ||
|
|
||
| [project] | ||
| name = "breach-web-scraper" | ||
| version = "0.1.0" | ||
| description = "A Python tool for scraping breach websites to provide a nice summary." | ||
| readme = "README.md" | ||
| requires-python = ">=3.10" | ||
| license = { text = "MIT" } | ||
| authors = [{ name = "noderaven" }] | ||
| keywords = ["breach", "scraper", "security", "washington", "data-breach"] | ||
| classifiers = [ | ||
| "Programming Language :: Python :: 3", | ||
| "License :: OSI Approved :: MIT License", | ||
| "Operating System :: OS Independent", | ||
| "Topic :: Security", | ||
| ] | ||
|
|
||
| [project.urls] | ||
| Homepage = "https://github.com/noderaven/breach-web-scraper" | ||
| Repository = "https://github.com/noderaven/breach-web-scraper" | ||
|
|
||
| [project.scripts] | ||
| breach-scraper = "breach_scraper.wa_atg_scraper:main" | ||
|
|
||
| [project.optional-dependencies] | ||
| dev = ["ruff>=0.5", "mypy>=1.10", "bandit>=1.7"] | ||
|
|
||
| [tool.hatch.build.targets.wheel] | ||
| packages = ["breach_scraper"] | ||
|
|
||
| [tool.ruff] | ||
| line-length = 100 | ||
| target-version = "py310" | ||
|
|
||
| [tool.ruff.lint] | ||
| select = ["E", "F", "I", "UP", "B", "SIM", "C4"] | ||
|
|
||
| [tool.mypy] | ||
| python_version = "3.10" | ||
| strict = true | ||
| files = ["breach_scraper"] |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Import
HTTPExceptionfromhttp.clientto allow catching protocol-level exceptions (such asIncompleteReadorBadStatusLine) that can occur during HTTP requests.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in 10ed280. Imported HTTPException from http.client.