import ipaddress
import requests
from dotenv import load_dotenv
import os
import sys
import io
if isinstance(sys.stdout, io.TextIOWrapper):
sys.stdout.reconfigure(encoding="utf-8")
load_dotenv()
# pip install python-dotenv requests
# Прокси назначаются аккаунтам по кругу — если прокси меньше чем аккаунтов, они переиспользуются.
# Если файл proxies.txt отсутствует, все запросы идут без прокси. Каждый аккаунт использует отдельную requests.Session, что изолирует соединения.
BASE_URL = "https://api.timeweb.cloud/api/v1"
AVAILABILITY_ZONE = os.getenv("AVAILABILITY_ZONE", "spb-3")
IS_DDOS_GUARD = os.getenv("IS_DDOS_GUARD", "false").lower() == "true"
MAX_ATTEMPTS = int(os.getenv("MAX_ATTEMPTS", "10"))
ACCOUNTS_FILE = os.getenv("ACCOUNTS_FILE", "accounts.txt")
PROXIES_FILE = os.getenv("PROXIES_FILE", "proxies.txt")
TG_BOT_TOKEN = os.getenv("TG_BOT_TOKEN", "")
TG_CHAT_ID = os.getenv("TG_CHAT_ID", "")
DESIRED_SUBNETS = [
"81.200.148.0/24",
"81.200.149.0/24",
"81.200.150.0/24",
"81.200.151.0/24",
"94.228.117.0/24",
"185.200.242.0/24",
]
def send_telegram(text: str):
if not TG_BOT_TOKEN or not TG_CHAT_ID:
return
try:
requests.post(
f"https://api.telegram.org/bot{TG_BOT_TOKEN}/sendMessage",
json={"chat_id": TG_CHAT_ID, "text": text, "parse_mode": "HTML"},
timeout=10,
)
except Exception as e:
print(f" [TG] Не удалось отправить сообщение: {e}")
def load_lines(filepath: str) -> list[str]:
with open(filepath, "r", encoding="utf-8") as f:
return [line.strip() for line in f if line.strip()]
def ip_in_desired_subnets(ip: str) -> bool:
addr = ipaddress.ip_address(ip)
return any(addr in ipaddress.ip_network(subnet) for subnet in DESIRED_SUBNETS)
def make_session(proxy: str | None) -> requests.Session:
session = requests.Session()
if proxy:
session.proxies = {"http": proxy, "https": proxy}
return session
def create_floating_ip(session: requests.Session, headers: dict) -> dict:
payload = {
"availability_zone": AVAILABILITY_ZONE,
"is_ddos_guard": IS_DDOS_GUARD,
}
response = session.post(f"{BASE_URL}/floating-ips", headers=headers, json=payload)
if not response.ok:
print(f" Ошибка {response.status_code}: {response.text}")
response.raise_for_status()
return response.json()["ip"]
def delete_floating_ip(session: requests.Session, headers: dict, floating_ip_id: str):
response = session.delete(
f"{BASE_URL}/floating-ips/{floating_ip_id}", headers=headers
)
if not response.ok:
print(
f" Не удалось удалить IP {floating_ip_id}: {response.status_code} {response.text}"
)
def get_ip_from_desired_range(
session: requests.Session, headers: dict, account_label: str
) -> dict | None:
for attempt in range(1, MAX_ATTEMPTS + 1):
ip_data = create_floating_ip(session, headers)
ip_addr = ip_data["ip"]
print(f" [{account_label}] Попытка {attempt}: получен IP {ip_addr}")
if ip_in_desired_subnets(ip_addr):
print(f" [{account_label}] ✅ IP {ip_addr} входит в нужный диапазон!")
return ip_data
else:
print(f" [{account_label}] ❌ IP {ip_addr} не подходит, удаляем...")
delete_floating_ip(session, headers, ip_data["id"])
print(f" [{account_label}] Не удалось получить IP за {MAX_ATTEMPTS} попыток.")
return None
if __name__ == "__main__":
tokens = load_lines(ACCOUNTS_FILE)
proxies = load_lines(PROXIES_FILE) if os.path.exists(PROXIES_FILE) else []
print(f"Загружено аккаунтов: {len(tokens)}, прокси: {len(proxies)}\n")
send_telegram(
f"🚀 tw.py запущен\n"
f"Аккаунтов: {len(tokens)}, прокси: {len(proxies)}\n"
f"Зона: {AVAILABILITY_ZONE}, DDoS-Guard: {IS_DDOS_GUARD}, попыток: {MAX_ATTEMPTS}"
)
found = []
failed = []
for i, token in enumerate(tokens):
proxy = proxies[i % len(proxies)] if proxies else None
label = f"аккаунт {i + 1}"
print(f"▶ Обработка {label} | прокси: {proxy or 'нет'}")
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
}
session = make_session(proxy)
try:
result = get_ip_from_desired_range(session, headers, label)
if result:
print(f" Итоговый IP: {result['ip']}, ID: {result['id']}\n")
found.append((label, result["ip"], result["id"]))
send_telegram(
f"✅ {label}: получен IP {result['ip']}\n"
f"ID: {result['id']}"
)
else:
failed.append(label)
send_telegram(
f"❌ {label}: не удалось получить подходящий IP "
f"за {MAX_ATTEMPTS} попыток"
)
except Exception as e:
print(f" Критическая ошибка для {label}: {e}\n")
failed.append(label)
send_telegram(f"💥 {label}: критическая ошибка — {e}")
summary_lines = [f"📊 Итог: найдено {len(found)}, не найдено {len(failed)}"]
if found:
summary_lines.append("\nУспешные:")
for lbl, ip, fid in found:
summary_lines.append(f" • {lbl}: {ip}")
if failed:
summary_lines.append("\nНеудачные:")
for lbl in failed:
summary_lines.append(f" • {lbl}")
send_telegram("\n".join(summary_lines))