Simple and powerful Python script to look for keywords or download direct files from AndroidFileHost by imitating their API calls. Supports downloading from multiple pages, direct FID / URL downloads, automatic mirror failover, dry-run inspection, JSON output, and sorting.
AFH is slowly dying, which means a lot of ROMs, kernels, and recoveries will be forever gone if we don't archive them elsewhere. This script makes bulk archiving and single-file retrieval fast and easy.
- Keyword Search & Archiving: Search and download files across multiple pages with popularity or newest sorting.
- Direct Downloads: Download specific files directly by AFH URL or numeric FID (
-u/--url,--fid). - Mirror Failover: Automatic fallback to alternate mirrors if the preferred mirror (USA/Germany) fails or is unreachable.
- Dry Run & Inspection: Preview search matches or target file metadata without downloading (
--list/--dry-run). - Structured JSON Output: Machine-readable JSON output mode (
--json) for scripting and pipelines. - Async HTTP/2 Engine: High-throughput concurrent downloads with real-time transfer speed and progress tracking.
- Integrity Validation: Automatic SHA-256 and MD5 hash verification with
.partatomic file staging. - Safe Path Resolution: Default archive directory (
afh_archive) is placed in the current working directory, preventingsite-packagespollution when installed via pip.
Install dependencies:
pip install httpx h2 beautifulsoup4You can also check the releases page to download precompiled standalone executables for Windows, Linux, and macOS without installing Python.
Alternatively, install globally via PyPI:
pip install AndroidFileHostScraperYou can then run it from anywhere using either androidfilehostscraper or afhscraper.
Simply run the tool without arguments:
python AFHscraper.pyYou will be prompted to choose between searching for keywords or entering direct file URLs/FIDs, followed by mirror and concurrency preferences.
AFHScraper provides a command-line interface for automation and scripting:
options:
-h, --help show this help message and exit
-s, --search SEARCH Search terms (comma-separated)
-u, --url URL Direct download by AFH URL or FID (comma-separated for multiple)
--fid FID Direct download by FID (comma-separated for multiple)
--sort {newest,popular}
Sort order (newest or popular)
-n, --files FILES Maximum files to download per search term
-m, --mirror {usa,germany}
Preferred mirror location
-t, --threads THREADS
Number of concurrent downloads (default: 1)
-o, --output OUTPUT Download directory
--list, --dry-run Search and display matching files without downloading
--json Output results in JSON format
-l, --log-level {DEBUG,INFO,WARNING,ERROR}
Logging level (default: INFO)
-
Search and download files:
python AFHscraper.py -s "twrp,lineage" --sort popular -n 20 -t 5 -m usa -
Direct download by URL or FID:
python AFHscraper.py -u "https://androidfilehost.com/?fid=1234567890" python AFHscraper.py --fid 1234567890,9876543210 -t 2 -o ./downloads -
Dry-run / list files without downloading:
python AFHscraper.py -s "lineage" --list python AFHscraper.py --fid 1234567890 --list -
Output in JSON format:
python AFHscraper.py -s "lineage" --list --json python AFHscraper.py --fid 1234567890 --json
By default, files are downloaded into an afh_archive directory inside your current working directory (or adjacent to the executable if running a frozen binary). This ensures that running afhscraper when installed in global Python environments never writes downloaded files into site-packages. Use -o / --output to set a custom destination directory.
AFHScraper first attempts to download from your selected mirror region (usa or germany). If that mirror fails, responds with an HTTP error, or returns an invalid stream, AFHScraper automatically falls back to remaining available mirrors until the download succeeds or all options are exhausted.
Unit tests are written using Python's built-in unittest framework and require no external test runner:
python -m unittest discover -s tests
# or simply
python -m unittestEnjoy my work? Please consider a small donation!