
Библиотека Python для программного управления экземплярами Tor с поддержкой SOCKS5-прокси, смены идентификаторов, изоляции потоков, скрытых служб, управления цепями и асинхронных HTTP-клиентов.
Python-библиотека для программного управления экземплярами Tor.
Linux (Debian/Ubuntu):
sudo apt-get install tor obfs4proxy
Windows:
Скачайте Tor Expert Bundle с torproject.org.
pip install xtor
# или
uv add xtor
from xtor import Tor
with Tor.start(port=9052, control_port=9053, host="127.0.0.1") as tor:
print(f"Connected through IP: {tor.ip}")
resp = tor.client.get("https://api.ipify.org")
print(resp.text)
from xtor import Tor
from xtor.exceptions import TorNotFoundError, PortInUseError
try:
with Tor.start(port=9052, control_port=9053, host="127.0.0.1", password="mypass") as tor:
print(tor.ip)
resp = tor.client.get("https://api.ipify.org")
print(resp.text)
except TorNotFoundError:
print("Tor не найден в PATH")
except PortInUseError as e:
print(f"Порт занят: {e}")
Примечание:
Tor.startTor()доступен как псевдоним дляTor.start()для обратной совместимости.
with Tor(password="mypass", port=9050, control_port=9051) as tor:
print(tor.ip)
with Tor.start(port=9052, control_port=9053, host="127.0.0.1") as tor:
print(tor.ip)
tor.new_identity(wait=True, timeout=30)
print(tor.ip) # Новый IP
import asyncio
from xtor import Tor
async def main():
with Tor.start(port=9052, control_port=9053, host="127.0.0.1") as tor:
async with tor.async_client as client:
resp = await client.get("https://api.ipify.org")
print(resp.text)
asyncio.run(main())
with Tor.start(port=9052, control_port=9053, host="127.0.0.1") as tor:
# Каждый ключ получает свою цепь
client_a = tor.isolated_client("session-a")
client_b = tor.isolated_client("session-b")
# Запросы через client_a и client_b используют разные цепи
with Tor.start(port=9052, control_port=9053, host="127.0.0.1") as tor:
circuits = tor.get_circuits()
for c in circuits:
print(f"Цепь {c.id}: {c.status}, путь: {c.path}")
# Закрыть конкретную цепь
tor.close_circuit(circuits[0].id)
with Tor.start(port=9052, control_port=9053, host="127.0.0.1") as tor:
info = tor.exit_node
if info:
print(f"Выходной узел: {info.nickname} ({info.country})")
print(f"Флаги: {info.flags}")
with Tor.start(port=9052, control_port=9053, host="127.0.0.1") as tor:
service = tor.create_hidden_service({80: 8080})
print(f"Сервис: {service.onion_address}")
# Удалить, когда закончите
tor.remove_hidden_service(service)
with Tor.start(port=9052, control_port=9053, host="127.0.0.1") as tor:
def on_bandwidth(event):
print(f"Прочитано: {event.read}, Записано: {event.written}")
tor.add_event_listener("BW", on_bandwidth)
# ... выполняем работу ...
tor.remove_event_listener(on_bandwidth)
from xtor import TorPool
with TorPool(size=3, base_port=9100, password="secret") as pool:
# Циклический перебор
tor = pool.next()
print(tor.client.get("https://api.ipify.org").text)
# Сменить все идентичности
pool.rotate_all()
# Случайный выбор
tor = pool.random()
from xtor import Tor
# Запустить именованный экземпляр
tor = Tor.start(port=9052, control_port=9053, host="127.0.0.1", name="my-tor")
# Позже переподключиться по имени
tor = Tor.from_name("my-tor")
with tor:
print(tor.ip)
CLI xtor управляет именованными экземплярами Tor как фоновыми процессами.
# Запустить именованный экземпляр
xtor start my-tor --port 9052 --control-port 9053
# Список экземпляров
xtor list
# Детали подключения
xtor connect my-tor
# Остановить экземпляр
xtor stop my-tor
# Удалить экземпляр и данные
xtor remove my-tor
XtorError (base)
├── TorNotFoundError
├── PortInUseError
├── IdentityChangeTimeout
├── ConnectionError
└── AuthenticationError
Шаблон для перехвата всех ошибок:
from xtor.exceptions import XtorError
try:
with Tor.start(port=9052, control_port=9053, host="127.0.0.1") as tor:
...
except XtorError as e:
print(f"Ошибка xtor: {e}")