Python scraper for Oryx equipment loss data, matching the R script approach from scrape_oryx.
This package scrapes equipment loss data directly from the Oryx blog post and generates CSV files in the same format as the oryx_data repository.
- ✅ CSV Output: Generates CSV files matching oryx_data format
- ✅ Type-safe: Full type hints with dataclasses
- ✅ Context Manager: Proper resource cleanup
- ✅ Well-tested: Comprehensive test suite
- ✅ Modern Python: Requires Python 3.10+
pip install oryx-wat-scraperOr using uv:
uv add oryx-wat-scraperOr using poetry:
poetry add oryx-wat-scraperfrom oryx_wat_scraper import OryxScraper
# Initialize the scraper
scraper = OryxScraper()
# Scrape data
data = scraper.scrape()
# Generate CSV files (matching oryx_data format)
scraper.scrape_to_csv('outputfiles')
# Or get JSON
json_data = scraper.scrape_to_json('output.json')
# Close when done
scraper.close()from oryx_wat_scraper import OryxScraper
with OryxScraper() as scraper:
# Scrape specific countries
data = scraper.scrape(countries=['russia', 'ukraine'])
# Generate CSV files
scraper.scrape_to_csv('outputfiles')# Generate CSV files
oryx-scraper --csv
# Save to JSON
oryx-scraper -o output.json
# Scrape specific countries
oryx-scraper --csv --countries russia ukraine
# Custom output directory
oryx-scraper --csv --output-dir my_outputdaily_count.csv (columns: country, equipment_type, destroyed, abandoned, captured, damaged, type_total, date_recorded)
country,equipment_type,destroyed,abandoned,captured,damaged,type_total,date_recorded
russia,T-62M,154,5,34,1,194,2024-01-15
ukraine,T-72,45,2,8,0,55,2024-01-15totals_by_type.csv (columns: country, type, destroyed, abandoned, captured, damaged, total)
country,type,destroyed,abandoned,captured,damaged,total
russia,T-62M,154,5,34,1,194
ukraine,T-72,45,2,8,0,55{
"url": "https://www.oryxspioenkop.com/...",
"date_scraped": "2024-01-15",
"total_entries": 1000,
"daily_count": [...],
"totals_by_type": [...]
}Main scraper class.
scrape(countries: List[str] | None = None) -> Dict: Scrape data for specified countriesscrape_to_csv(output_dir: str = 'outputfiles') -> Dict: Scrape and save to CSV filesscrape_to_json(output_file: str | None = None, indent: int = 2) -> str: Scrape and return/save as JSONclose(): Close the HTTP client
EquipmentEntry: Individual equipment entry with statusSystemEntry: Individual system entry with status
OryxScraperError: Base exceptionOryxScraperNetworkError: Network errorsOryxScraperParseError: HTML parsing errorsOryxScraperValidationError: Data validation errors
# Clone the repository
git clone https://github.com/wat-suite/oryx-wat-scraper.git
cd oryx-wat-scraper
# Install with uv
uv sync --dev
# Install pre-commit hooks
uv run pre-commit install# Run all tests
pytest
# Run with coverage
pytest --cov=oryx_wat_scraper --cov-report=html
# Run specific test file
pytest tests/test_client.pyYou can run the same checks that CI runs locally:
# Run all checks
black --check .
ruff check .
mypy oryx_wat_scraper
pytest# Format code
black .
# Lint code
ruff check .
# Type check
mypy oryx_wat_scrapermake install-dev # Install with dev dependencies
make test # Run tests
make lint # Run linters
make format # Format code
make type-check # Type check
make clean # Clean build artifactsThis project uses GitHub Releases to trigger PyPI publishing. The workflow automatically publishes to PyPI when a final (non-pre-release) GitHub Release is created.
Update the version in pyproject.toml:
[project]
version = "0.2.0" # Update to your new versionFollow Semantic Versioning:
- MAJOR (1.0.0): Breaking changes
- MINOR (0.1.0): New features, backwards compatible
- PATCH (0.0.1): Bug fixes, backwards compatible
Update CHANGELOG.md with the changes for this version.
git add pyproject.toml CHANGELOG.md
git commit -m "chore: bump version to 0.2.0"
git push origin mainCreate a tag matching the version (with or without 'v' prefix):
# Option 1: Tag with 'v' prefix
git tag v0.2.0
# Option 2: Tag without prefix
git tag 0.2.0
# Push the tag
git push origin v0.2.0Important: The tag version must match the version in pyproject.toml exactly (excluding the 'v' prefix if used).
Go to the GitHub Releases page and click "Draft a new release":
For Pre-Release (Testing):
- Tag: Select the tag you just created (e.g.,
v0.2.0) - Release title:
v0.2.0(or your version) - Description: Copy from
CHANGELOG.mdor write release notes - ☑️ Set as a pre-release: Check this box
- Click "Publish release"
Pre-releases are not published to PyPI. Use them for testing before the final release.
For Final Release (Publishing to PyPI):
- Tag: Select the tag you just created (e.g.,
v0.2.0) - Release title:
v0.2.0(or your version) - Description: Copy from
CHANGELOG.mdor write release notes - ☐ Set as a pre-release: Leave this unchecked
- Click "Publish release"
The GitHub Actions workflow will:
- Verify the tag version matches
pyproject.toml - Build the package
- Check the package with
twine - Publish to PyPI (only for final releases, not pre-releases)
1. Update version in pyproject.toml
2. Update CHANGELOG.md
3. Commit and push changes
4. Create and push git tag
5. Create GitHub Release (pre-release or final)
└─> Pre-release: Testing only, not published to PyPI
└─> Final release: Automatically published to PyPI
- Version mismatch error: Ensure the tag version (without 'v' prefix) exactly matches
pyproject.tomlversion - Pre-release published: Pre-releases are intentionally skipped. Create a final release to publish to PyPI
- Workflow not triggered: Ensure the release is "Published" (not "Draft") and the tag exists
This scraper is based on the R script approach from:
- scrape_oryx - R script for scraping Oryx data
- oryx_data - Processed CSV data repository
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests for new functionality
- Ensure all tests pass and code is formatted (
black . && ruff check . && pytest) - Commit your changes (following Conventional Commits)
- Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project follows Conventional Commits. Commit messages should be formatted as:
<type>(<scope>): <subject>
<body>
<footer>
Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting, etc.)refactor: Code refactoringtest: Adding or updating testschore: Maintenance tasks
- This project uses Black for code formatting
- Ruff is used for linting
- mypy is used for type checking
- All code must pass linting and type checking
This project is licensed under the MIT License - see the LICENSE file for details.
If you encounter any issues or have questions, please open an issue on GitHub.
See CHANGELOG.md for a list of changes and version history.
- Oryx for documenting equipment losses
- scarnecchia for the R script and data processing
- All contributors who help improve this library