sitewalker
Crawl a website and create a structured map of its pages.
Requirements
- Python 3.11 or later
Installation
pipx install sitewalker
Usage
# Map all pages on a site (single-level crawl)
sitewalker example.com
# Recursive crawl of all internal pages
sitewalker example.com -r
# Collect external links
sitewalker example.com -e
# Collect external links and check their HTTP status
sitewalker example.com -e --check-external
# Recursive crawl with external link collection
sitewalker example.com -r -e
# Include images, stylesheets, and scripts in the inventory
sitewalker example.com -r -a
# Hunt broken links: non-200s summarized on stdout, with the page to fix
sitewalker example.com -r --broken-only
# Only crawl web pages (skip images, PDFs, etc.)
sitewalker example.com -r -p
# Crawl an HTTP-only site (e.g., LAN staging server)
sitewalker http://staging.lan --allow-private
# Verbose output for debugging
sitewalker example.com -r -v
The target accepts a bare domain (example.com) or a full URL (http://example.com). Bare domains default to HTTPS — if the connection fails, sitewalker exits with a message to provide the full URL.
Options
| Flag | Description | Default |
|---|---|---|
| Crawl scope | ||
-r, --recursive |
Recursively crawl internal links | Off |
-a, --assets |
Also discover img/script/link/source assets (recorded via HEAD, never parsed) |
Off |
-p, --pages |
Only crawl web pages (HTML, PHP, etc.) | Off |
--max-pages |
Maximum number of pages to crawl | 1000 |
--max-depth |
Maximum link distance from start URL (BFS) | 10 |
| External links | ||
-e, --external-links |
Collect external links | Off |
--check-external |
Check HTTP status of external links (requires -e) |
Off |
--max-external-links |
Maximum external links to check with --check-external |
500 |
--domain-delay |
Minimum seconds between requests to the same external domain | 5.0 |
| Output | ||
--output-dir DIR |
Directory for CSV output (created if missing) | Current directory |
--output-filename NAME |
Base name for output files (bare name, no path) | {domain}_{timestamp} |
--broken-only |
Print a summary of non-200 URLs to stdout after the crawl | Off |
| Requests | ||
-t, --timeout |
Request timeout in seconds | 30 |
--delay |
Delay between requests in seconds (use 0 for local) | 1.0 |
| Configuration | ||
--config PATH |
Config file to load | ~/.config/sitewalker/config.toml |
--no-config |
Ignore any config file | Off |
| Safety overrides | ||
--allow-private |
Allow crawling domains that resolve to private IPs | Off |
--ignore-robots |
Ignore robots.txt rules | Off |
| Other | ||
-v, --verbose |
Enable verbose/debug output | Off |
Configuration
Settings that rarely change can live in a TOML config file at ~/.config/sitewalker/config.toml (or $XDG_CONFIG_HOME/sitewalker/config.toml; override the location with --config, skip it entirely with --no-config). CLI flags always win over config values.
# Where CSVs are written when --output-dir isn't given
output_dir = "~/crawls"
# Replaces the built-in extension set used by -p/--pages.
# Include "" to keep treating extension-less URLs and directories as pages.
page_extensions = ["", "html", "htm", "php", "story"]
Recognized keys: output_dir, page_extensions. Unknown keys are an error, so typos fail loudly instead of being ignored.
Output
Results are saved to a CSV file named {domain}_{timestamp}.csv in the current directory. Use --output-dir to write elsewhere (the directory is created if needed) and --output-filename to replace the generated name:
sitewalker example.com -r -e --output-dir ~/crawls --output-filename acme-audit
# → ~/crawls/acme-audit.csv and ~/crawls/acme-audit_external_links.csv
--output-filename must be a bare name — the directory always comes from --output-dir. Columns:
- URL — the page URL
- Title — the page's
<title>tag content - Status Code — HTTP response status
- Found On — the page where this URL was first discovered (empty for the start URL). For a broken link, this is the page to fix.
- Kind —
page(fetched and parsed for links) orasset(recorded only, when-ais used).
URLs discovered beyond --max-depth are included as rows with title skipped: max_depth and an empty status code, so nothing the crawler saw is invisible in the output. Use --broken-only to print a summary of every non-200 URL (with its Found On page) to stdout at the end of the run.
When using -e, external links are additionally saved to {domain}_{timestamp}_external_links.csv. The internal pages CSV is always generated. With --check-external, the external links CSV includes a Status Code column.
Security
- SSRF protection: Domains that resolve to private/reserved IP addresses are blocked by default. Use
--allow-privateto override for legitimate internal use. - robots.txt: Respected by default. Use
--ignore-robotsto override. - CSV injection: Output values are sanitized to prevent spreadsheet formula injection.
- Crawl limits: Recursive crawls are bounded by
--max-pagesand--max-depthto prevent resource exhaustion.
Roadmap
--format json— JSON output format--check-alt— alt text auditing for the image inventory (-acovers the inventory itself)
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sitewalker-0.4.0.tar.gz.
File metadata
- Download URL: sitewalker-0.4.0.tar.gz
- Upload date:
- Size: 15.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b2235ad21ae0e26831adf8dbcfbff5987d6fae2963e2bda0c2a2030e3143259c
|
|
| MD5 |
acd82d5011a40db3ac146a86c75b9c65
|
|
| BLAKE2b-256 |
92151663eb3246d88d383654d1612816b45a85c55c18e530454db23154953d70
|
Provenance
The following attestation bundles were made for sitewalker-0.4.0.tar.gz:
Publisher:
publish.yml on cadentdev/sitewalker
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sitewalker-0.4.0.tar.gz -
Subject digest:
b2235ad21ae0e26831adf8dbcfbff5987d6fae2963e2bda0c2a2030e3143259c - Sigstore transparency entry: 2664504054
- Sigstore integration time:
-
Permalink:
cadentdev/sitewalker@44d04c147cfc70724cf62b1cf552b906cb0d3e28 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/cadentdev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@44d04c147cfc70724cf62b1cf552b906cb0d3e28 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file sitewalker-0.4.0-py3-none-any.whl.
File metadata
- Download URL: sitewalker-0.4.0-py3-none-any.whl
- Upload date:
- Size: 15.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7ebf4ce34269d12160f46dc7e32e52f42d99c3955b58dc7807d79827884552c7
|
|
| MD5 |
fa7749029dcf5672b3151ff1f9e7bbf0
|
|
| BLAKE2b-256 |
587734a01333f9bcd68eb1ec9d56f73be910601e8b1801a667e147871bd62745
|
Provenance
The following attestation bundles were made for sitewalker-0.4.0-py3-none-any.whl:
Publisher:
publish.yml on cadentdev/sitewalker
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sitewalker-0.4.0-py3-none-any.whl -
Subject digest:
7ebf4ce34269d12160f46dc7e32e52f42d99c3955b58dc7807d79827884552c7 - Sigstore transparency entry: 2664504106
- Sigstore integration time:
-
Permalink:
cadentdev/sitewalker@44d04c147cfc70724cf62b1cf552b906cb0d3e28 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/cadentdev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@44d04c147cfc70724cf62b1cf552b906cb0d3e28 -
Trigger Event:
workflow_dispatch
-
Statement type: