Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
240f4e7
Bump urllib3 from 2.5.0 to 2.6.3
dependabot[bot] Jan 8, 2026
cfd6d79
Improve CLI handling and crawler link resolution
KingAkeem Jul 16, 2026
dec920f
Simplify local install and CLI entry path
KingAkeem Jul 16, 2026
a738e92
Merge pull request #385 from DedSecInside/dependabot/pip/urllib3-2.6.3
KingAkeem Jul 16, 2026
e1b3ac4
bump urllib3 from 2.6.3 to 2.7.0
dependabot[bot] Jul 16, 2026
445f834
bump soupsieve from 2.3.2.post1 to 2.8.4
dependabot[bot] Jul 16, 2026
2ead0ab
bump idna from 3.7 to 3.15
dependabot[bot] Jul 16, 2026
d4251be
flake8
KingAkeem Jul 16, 2026
f779b98
Merge pull request #391 from DedSecInside/dependabot/pip/idna-3.15
KingAkeem Jul 16, 2026
61d00b0
Merge pull request #389 from DedSecInside/dependabot/pip/urllib3-2.7.0
KingAkeem Jul 16, 2026
9d24b97
Merge pull request #390 from DedSecInside/dependabot/pip/soupsieve-2.8.4
KingAkeem Jul 16, 2026
870bac6
bump python-dotenv from 0.20.0 to 1.2.2
dependabot[bot] Jul 16, 2026
f8ccec1
Merge pull request #394 from DedSecInside/dependabot/pip/python-doten…
KingAkeem Jul 16, 2026
d6b5e46
Resolve pyproject merge conflict
KingAkeem Jul 16, 2026
eddee14
Restore strict child URL filtering in linktree
KingAkeem Jul 16, 2026
e67747e
Merge pull request #388 from DedSecInside/patch-crawler-cli-fixes
KingAkeem Jul 16, 2026
f51f4e9
bump scikit-learn from 1.4.2 to 1.5.0
dependabot[bot] Jul 16, 2026
9575faa
bump pytest from 8.1.1 to 9.0.3
dependabot[bot] Jul 16, 2026
632cc7c
Merge pull request #393 from DedSecInside/dependabot/pip/pytest-9.0.3
KingAkeem Jul 16, 2026
d4f0094
Merge pull request #392 from DedSecInside/dependabot/pip/scikit-learn…
KingAkeem Jul 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
[flake8]
max-line-length = 119
exclude = .venv,build,dist
58 changes: 33 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,44 +39,49 @@
8. Built-in Updater
9. Build a visual tree of link relationships that can be quickly viewed or saved to a file

### Recent improvements
- The CLI now allows `--version` and `--update` to run without requiring a URL.
- The crawler now resolves relative links against the current page and skips unsupported or malformed hrefs more gracefully.

...(will be updated)

### Dependencies
- Tor (Optional)
- Python ^3.9
- Poetry (Optional)

### Python Dependencies
- Python 3.9+
- pip

(see pyproject.toml or requirements.txt for more details)
## Quick start

## Installation

### TorBot
### Local setup
```sh
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
python -m pip install -e .
```

#### Using `venv`
* If using Python ^3.4,
### Run the CLI
```sh
python -m venv torbot_venv
source torbot_venv/bin/activate
pip install -r requirements.txt
pip install -e .
./main.py --help
python main.py --help
python main.py --version
python main.py -u https://example.com --depth 2 --visualize table
```

#### Using `docker`
### Common examples
```sh
docker build -t {image_name} .
# Gather basic site information
python main.py -u https://example.com --info

# Running without Tor
docker run {image_name} poetry run python torbot -u https://example.com --depth 2 --visualize tree --save json --disable-socks5
# Save the crawl tree as JSON
python main.py -u https://example.com --depth 2 --save json

# Running with Tor
docker run --network="host" {image_name} poetry run python torbot -u https://example.com --depth 2 --visualize tree --save json --disable-socks5
# Disable SOCKS5 if you are not using Tor locally
python main.py -u https://example.com --disable-socks5 --visualize tree
```

### Options
<pre>
```text
usage: Gather and analyze data from Tor sites.

optional arguments:
Expand All @@ -92,11 +97,14 @@ optional arguments:
--save FORMAT Save results in a file. (tree, JSON)
--visualize FORMAT Visualizes tree of data gathered. (tree, JSON, table)
-i, --info Info displays basic info of the scanned site
--disable-socks5 Executes HTTP requests without using SOCKS5 proxy</pre>
--disable-socks5 Executes HTTP requests without using SOCKS5 proxy
```

> `-u/--url` is required for crawl-related commands such as `--info`, `--save`, and `--visualize`.

* NOTE: -u is a mandatory for crawling
If you are using Tor locally, keep the SOCKS5 proxy enabled. If you are not using Tor, add `--disable-socks5` to avoid proxy connection errors.

Read more about torrc here : [Torrc](https://github.com/DedSecInside/TorBoT/blob/master/Tor.md)
Read more about torrc here: [Torrc](https://github.com/DedSecInside/TorBoT/blob/master/Tor.md)

## Curated Features
- [x] Visualization Module Revamp
Expand Down
6 changes: 6 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
--------------------
All notable changes to this project will be documented in this file.

## 4.1.1

### Fixed
- Adjusted the CLI so `--version` and `--update` can run without requiring a URL.
- Improved crawler link parsing so relative links are resolved against the current page while unsupported hrefs are skipped cleanly.

## 2.1.0

### Added
Expand Down
16 changes: 10 additions & 6 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,6 @@ def run(arg_parser: argparse.ArgumentParser, version: str) -> None:
logging_lvl = logging.DEBUG if args.v else logging.INFO
logging.basicConfig(level=logging_lvl, format=logging_fmt, datefmt=date_fmt)

# URL is a required argument
if not args.url:
arg_parser.print_help()
sys.exit()

# Print verison then exit
if args.version:
print(f"TorBot Version: {version}")
Expand All @@ -76,6 +71,11 @@ def run(arg_parser: argparse.ArgumentParser, version: str) -> None:
check_version()
sys.exit()

# URL is required for crawl-related actions
if not args.url:
arg_parser.print_help()
sys.exit()

socks5_host = args.host
socks5_port = str(args.port)
socks5_proxy = f"socks5://{socks5_host}:{socks5_port}"
Expand Down Expand Up @@ -123,7 +123,11 @@ def set_arguments() -> argparse.ArgumentParser:
prog="TorBot", usage="Gather and analayze data from Tor sites."
)
parser.add_argument(
"-u", "--url", type=str, required=True, help="Specifiy a website link to crawl"
"-u",
"--url",
type=str,
default=None,
help="Specifiy a website link to crawl",
)
parser.add_argument(
"--depth", type=int, help="Specifiy max depth of crawler (default 1)", default=1
Expand Down
78 changes: 42 additions & 36 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,51 +4,57 @@ build-backend = "hatchling.build"

[project]
name = "torbot"
version = "4.1.0"
version = "4.1.1"
authors = [
{ name="Akeem King", email="akeemtlking@gmail.com" },
{ name="PS Narayanan", email="thepsnarayanan@gmail.com" },
]
description = "TorBot is an OSINT tool for the dark web."
readme = "README.md"
requires-python = ">=3.7"
requires-python = ">=3.9"
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Operating System :: OS Independent",
]
dependencies = [
"altgraph==0.17.2",
"beautifulsoup4==4.11.1",
"certifi==2024.7.4",
"charset-normalizer==2.0.12",
"decorator==5.1.1",
"idna==3.7",
"igraph==0.10.6",
"joblib==1.2.0",
"macholib==1.16",
"progress==1.6",
"pyinstaller==6.0.0",
"pyinstaller-hooks-contrib==2022.7",
"PySocks==1.7.1",
"python-dotenv==0.20.0",
"scikit-learn==1.3.0",
"scipy==1.10.0",
"six==1.16.0",
"sklearn==0.0",
"soupsieve==2.3.2.post1",
"termcolor==1.1.0",
"texttable==1.6.4",
"threadpoolctl==3.1.0",
"urllib3==2.5.0",
"validators==0.20.0",
"treelib==1.6.1",
"numpy==1.24.4",
"unipath==1.1",
"httpx[socks]==0.25.0",
"tabulate==0.9.0",
"phonenumbers==8.13.22",
"pytest==7.4.2",
"yattag==1.15.1",
"toml==0.10.2",
"altgraph>=0.17.4",
"beautifulsoup4>=4.12.3",
"certifi>=2024.7.4",
"charset-normalizer>=3.3.2",
"decorator>=5.1.1",
"idna>=3.15",
"igraph>=0.11.4",
"joblib>=1.4.2",
"macholib>=1.16.3",
"progress>=1.6",
"pyinstaller>=6.8.0",
"pyinstaller-hooks-contrib>=2024.6",
"PySocks>=1.7.1",
"python-dotenv>=1.2.2",
"scikit-learn>=1.5.0",
"scipy>=1.13.0",
"six>=1.16.0",
"sklearn>=0.0",
"soupsieve>=2.8.4",
"termcolor>=2.4.0",
"texttable>=1.7.0",
"threadpoolctl>=3.5.0",
"urllib3>=2.7.0",
"validators>=0.22.0",
"treelib>=1.7.1",
"numpy>=1.26.4",
"unipath>=1.1",
"httpx[socks]>=0.27.0",
"tabulate>=0.9.0",
"phonenumbers>=8.13.37",
"pytest>=9.0.3",
"yattag>=1.15.2",
"toml>=0.10.2",
]

[project.scripts]
torbot = "torbot.cli:main"
12 changes: 6 additions & 6 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ decorator==5.1.1
h11==0.14.0
httpcore==1.0.5
httpx[socks]==0.27.0
idna==3.7
idna==3.15
igraph==0.11.4
iniconfig==2.0.0
joblib==1.4.2
Expand All @@ -22,17 +22,17 @@ progress==1.6
pyinstaller-hooks-contrib==2024.6
pyinstaller==6.8.0
pysocks==1.7.1
pytest==8.1.1
python-dotenv==1.0.1
pytest==9.0.3
python-dotenv==1.2.2
pywin32-ctypes==0.2.2 ; sys_platform == "win32"
scikit-learn==1.4.2
scikit-learn==1.5.0
scipy==1.13.0
setuptools==78.1.1
six==1.16.0
sklearn==0.0
sniffio==1.3.1
socksio==1.0.0
soupsieve==2.5
soupsieve==2.8.4
tabulate==0.9.0
termcolor==2.4.0
texttable==1.7.0
Expand All @@ -41,6 +41,6 @@ toml==0.10.2
tomli==2.0.1
treelib==1.7.1
unipath==1.1
urllib3==2.5.0
urllib3==2.7.0
validators==0.22.0
yattag==1.15.2
7 changes: 7 additions & 0 deletions scripts/publish.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail

python3 -m build
python3 -m twine check dist/*
echo "Publishing is ready. Run the following when you have your PyPI token:"
echo "python3 -m twine upload dist/*"
28 changes: 28 additions & 0 deletions src/torbot/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import os
import sys

import toml

REPO_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
if REPO_ROOT not in sys.path:
sys.path.insert(0, REPO_ROOT)

from main import run as run_cli, set_arguments # noqa: E402


def main() -> None:
"""Run the TorBot CLI from an installed entry point."""
arg_parser = set_arguments()
config_file_path = os.path.join(REPO_ROOT, "pyproject.toml")
try:
with open(config_file_path, "r", encoding="utf-8") as handle:
data = toml.load(handle)
version = data["project"]["version"]
except Exception as exc:
raise RuntimeError("unable to find version from pyproject.toml.") from exc

run_cli(arg_parser, version)


if __name__ == "__main__":
main()
Loading
Loading