Merhabalar hocalarım bir rezervasyon botum rezervasyonu tespiti çok hızlı ama kabul aşamasında çok geç kalıyor yardımcı olabilecek varmı acaba, Chatgpt ve gemini ile sağlıklı cevaplar alamadım ,
import asyncio
import time
import json
import certifi
import cloudscraper
import random
from fake_useragent import UserAgent
import os
from datetime import datetime
NUM_POLLING_WORKERS = 7
STATUS_UPDATE_INTERVAL = 0.5
ACCEPT_RETRY_DELAY = 1.5
MAX_ACCEPT_RETRIES = 2
ACCEPT_TIMEOUT = 20
BOOKING_URL = "api1"
ACCEPT_URL = "api2"
LOGIN_HASH = "hash1"
ACCEPT_LOGIN_HASH = "hash2"
VEHICLE_ID = "36979"
TELEGRAM_BOT_TOKEN = "token"
TELEGRAM_CHAT_ID = "id"
PROXY_FILE = "proxy.txt"
previous_hashes = set()
lock = asyncio.Lock()
success_count = 0
ua = UserAgent()
loaded_proxies = []
try:
accept_scraper = cloudscraper.create_scraper(
browser={"browser": "chrome", "platform": "windows", "mobile": False}
)
print("\n✅ Kabul istekleri için Cloudscraper başarıyla başlatıldı.")
except Exception as e:
print(f"\n❌ Kabul istekleri için Cloudscraper başlatılamadı: {e}")
accept_scraper = None # Hata durumunda None olarak ayarla
# ---------------------------------------------
# ===================================
# FONKSİYONLAR
# ===================================
def get_current_time_ms():
return datetime.now().strftime('%H:%M:%S.%f')[:-3]
def load_proxies_from_file(filename=PROXY_FILE):
"""proxy.txt dosyasından ip:port:user:pass formatındaki proxy'leri okur."""
proxies = []
if not os.path.exists(filename):
print(f"\n❌ HATA: Proxy dosyası bulunamadı: {filename}")
return []
try:
with open(filename, 'r') as f:
for line_num, line in enumerate(f):
line = line.strip()
if not line or line.startswith('#'):
continue
parts = line.split(':')
if len(parts) == 4:
ip, port, username, password = parts
# IPv6 adresleri için köşeli parantez kontrolü
if ':' in ip and not (ip.startswith('[') and ip.endswith(']')):
ip = f"[{ip}]" # Köşeli parantez ekle
proxy_url = f"http://{username}:{password}@{ip}:{port}"
proxy_dict = {"http": proxy_url, "https": proxy_url}
proxies.append(proxy_dict)
else:
print(f"\n⚠️ Uyarı: {filename} dosyasındaki {line_num+1}. satır geçersiz formatta: '{line}'. Format ip:port:user:pass olmalı.")
except Exception as e:
print(f"\n❌ HATA: Proxy dosyası okunurken hata oluştu ({filename}): {e}")
return []
if not proxies:
print(f"\n❌ HATA: {filename} dosyasından geçerli proxy yüklenemedi.")
else:
print(f"\n✅ {len(proxies)} adet proxy başarıyla yüklendi: {filename}")
return proxies
def get_random_headers():
"""Rastgele User-Agent ile HTTP başlıkları oluşturur."""
return {
"Content-Type": "application/json",
"User-Agent": ua.random
}
# ==========================================================
# === send_telegram_message (SSL Hatası için Düzeltildi) ===
# ==========================================================
async def send_telegram_message(message):
"""Telegram'a asenkron olarak bildirim gönderir (SSL doğrulaması ile)."""
if not TELEGRAM_BOT_TOKEN or not TELEGRAM_CHAT_ID:
# print("\nℹ️ Telegram token veya chat ID ayarlanmadığı için bildirim gönderilmedi.")
return
url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
payload = {"chat_id": TELEGRAM_CHAT_ID, "text": message, "parse_mode": "Markdown"}
sender_scraper = None
try:
# Telegram için ayrı, basit bir scraper kullan
sender_scraper = cloudscraper.create_scraper()
# Cloudscraper doğrudan async context manager desteklemez, to_thread kullanmak daha güvenli
response = await asyncio.to_thread(
sender_scraper.post,
url,
json=payload,
timeout=15,
verify=certifi.where()
)
if response.status_code != 200:
response_text = response.text
print(f"\n[{get_current_time_ms()}] ❌ Telegram Hatası: {response.status_code} - {response_text[:200]}")
except asyncio.TimeoutError:
print(f"\n[{get_current_time_ms()}] ⚠️ Telegram Bağlantı Hatası: Zaman aşımı (Timeout)")
except Exception as e:
print(f"\n[{get_current_time_ms()}] ⚠️ Telegram Bağlantı Hatası: {type(e).__name__} - {e}")
finally:
if sender_scraper:
pass
# ==========================================================
# === /send_telegram_message ===
# ==========================================================
async def accept_booking(booking_hash):
"""Bir rezervasyonu PROXYSİZ olarak kabul etmeye çalışır (Geliştirilmiş Loglama ile)."""
global previous_hashes
global lock
global accept_scraper # Global scraper'ı kullan
start_time_accept = get_current_time_ms()
if accept_scraper is None:
print(f"\n[{start_time_accept}] 🚫 Kabul Scraper başlatılamadığı için kabul işlemi yapılamıyor: {booking_hash}")
return False
# --- Hash Kontrolü (Kilitle) ---
async with lock:
if booking_hash in previous_hashes:
# print(f"\n[{start_time_accept}] ℹ️ Zaten işleniyor/işlendi: {booking_hash}") # Çok sık log olmaması için yorumda
return False # Zaten işleniyorsa veya işlendiyse çık
previous_hashes.add(booking_hash)
# -----------------------------
print(f"\n[{start_time_accept}] 🚀 Kabul işlemi başlatıldı (PROXYSİZ): {booking_hash}")
accept_payload = {
"login_hash": ACCEPT_LOGIN_HASH,
"booking_hash": booking_hash,
"vehicle_id": VEHICLE_ID,
"refuse": "accept"
}
headers = get_random_headers()
for attempt in range(MAX_ACCEPT_RETRIES):
current_time_attempt = get_current_time_ms()
print(f" [{current_time_attempt}] ➡️ Kabul Denemesi {attempt + 1}/{MAX_ACCEPT_RETRIES} gönderiliyor: {booking_hash}")
try:
accept_response = await asyncio.to_thread(
accept_scraper.post, # Global scraper'ı kullan
ACCEPT_URL,
headers=headers,
json=accept_payload,
verify=certifi.where(), # Burada zaten vardı
timeout=ACCEPT_TIMEOUT # Ayarlanan timeout
)
current_time_response = get_current_time_ms()
response_text_snippet = accept_response.text[:200] if accept_response.text else "Yanıt yok" # Hata mesajını kısalt
if accept_response.status_code == 200:
print(f" [{current_time_response}] ✅ BAŞARILI KABUL! (PROXYSİZ) - Deneme {attempt + 1}: {booking_hash}")
message = f"✅ Rezervasyon Kabul Edildi!\n\nHash: `{booking_hash}`\nZaman: {current_time_response}\n\n🔗 [Detay](https://site.com/{booking_hash})"
asyncio.create_task(send_telegram_message(message)) # Telegram'a gönder
return True # Başarılı, fonksiyondan çık
else:
# --- Detaylı Hata Loglaması ---
print(f" [{current_time_response}] ❌ KABUL HATASI (PROXYSİZ) - Durum Kodu: {accept_response.status_code} - Deneme {attempt + 1}/{MAX_ACCEPT_RETRIES}")
print(f" Yanıt Başlangıcı: {response_text_snippet}...")
print(f" Hash: {booking_hash}")
# ------------------------------
if 400 <= accept_response.status_code < 500:
print(f" [{current_time_response}] 🛑 4xx hatası alındı, tekrar denenmeyecek: {booking_hash}")
return False # Tekrar deneme
if attempt + 1 < MAX_ACCEPT_RETRIES:
wait_time = ACCEPT_RETRY_DELAY * (2 ** attempt) # Exponential backoff
print(f" [{current_time_response}] ⏳ {wait_time:.1f} sn bekleniyor...")
await asyncio.sleep(wait_time)
except Exception as e:
current_time_exception = get_current_time_ms()
# --- Detaylı İstisna Loglaması ---
print(f" [{current_time_exception}] ⚠️ KABUL BAĞLANTI/İSTİSNA HATASI (PROXYSİZ) - Deneme {attempt + 1}/{MAX_ACCEPT_RETRIES}")
print(f" Hata: {type(e).__name__} - {e}")
print(f" Hash: {booking_hash}")
# ------------------------------
if attempt + 1 < MAX_ACCEPT_RETRIES:
wait_time = ACCEPT_RETRY_DELAY * (2 ** attempt) # Exponential backoff
print(f" [{current_time_exception}] ⏳ {wait_time:.1f} sn bekleniyor...")
await asyncio.sleep(wait_time)
final_fail_time = get_current_time_ms()
print(f"\n[{final_fail_time}] 🚫 KABUL BAŞARISIZ (PROXYSİZ) (Tüm denemeler bitti): {booking_hash}")
return False
# =============================================
# === check_new_bookings FONKSİYONU (await ile güncellendi) ===
# =============================================
async def check_new_bookings(response_text):
"""
API yanıtını kontrol eder ve yeni rezervasyonları kabul için İŞLEME ALIR.
(await kullanıldığı için, bu fonksiyon içinde rezervasyonlar sırayla işlenir)
"""
try:
data = json.loads(response_text)
# Anahtar varlık kontrollerini artır
if not isinstance(data, dict): return
api_data = data.get("data")
if not isinstance(api_data, dict): return
current_bookings = api_data.get("bookings")
if not isinstance(current_bookings, list): return
except json.JSONDecodeError as e:
# print(f"\n[{get_current_time_ms()}] ⚠️ JSON Decode Hatası: {e} - Yanıt: {response_text[:100]}...") # Gürültülü olabilir
return
except Exception as e:
print(f"\n[{get_current_time_ms()}] ❌ Beklenmedik Hata (check_new_bookings): {type(e).__name__} - {e}")
return
if current_bookings:
current_time_check = get_current_time_ms()
print(f"\n[{current_time_check}] Yeni rezervasyon(lar) bulundu ({len(current_bookings)} adet). Sırayla işleniyor...")
for booking in current_bookings:
if isinstance(booking, dict) and "booking_hash_link" in booking:
booking_hash = booking["booking_hash_link"]
# Log mesajını güncelle (bekleme olduğunu belirtmek için)
print(f" -> [{get_current_time_ms()}] ✨ REZERVASYON: {booking_hash} -> Kabul işlemi başlatılıyor ve bekleniyor (await)...")
try:
# === DEĞİŞİKLİK BURADA (Önceki adımda yapıldı) ===
# accept_booking fonksiyonunu çağır ve tamamlanmasını bekle.
success = await accept_booking(booking_hash)
# ============================================
if success:
pass
else:
pass
except Exception as e:
print(f" -> [{get_current_time_ms()}] ❌ KRİTİK HATA (check_new_bookings içinde await sırasında): {booking_hash} - {e}")
else:
print(f" -> [{get_current_time_ms()}] ⚠️ Geçersiz rezervasyon verisi formatı atlandı: {booking}")
print(f"--- [{get_current_time_ms()}] Bulunan rezervasyonların işlenmesi tamamlandı (check_new_bookings). ---")
# =============================================
# === /check_new_bookings FONKSİYONU ===
# =============================================
async def poll_worker(worker_id):
global success_count
global lock
global loaded_proxies
# Her worker için ayrı scraper instance
worker_scraper = None # Başlangıçta None
try:
worker_scraper = cloudscraper.create_scraper(
browser={"browser": "chrome", "platform": "windows", "mobile": False}
)
except Exception as e:
print(f"[{get_current_time_ms()}] [Worker {worker_id}] ❌ Başlatılamadı: Scraper oluşturma hatası: {e}")
return # Scraper oluşturulamazsa worker çalışamaz
polling_interval = 0 # Başlangıçta bekleme yok
MAX_POLL_RETRIES = 1 # Sorgu için tekrar deneme sayısı
POLL_RETRY_DELAY = 1 # Sorgu tekrar deneme gecikmesi
while True:
await asyncio.sleep(polling_interval) # Döngüler arası (varsa) bekleme
if not loaded_proxies:
await asyncio.sleep(10)
continue
# --- Proxy Seçimi ve İstek Hazırlığı ---
try:
proxies = random.choice(loaded_proxies)
except IndexError:
await asyncio.sleep(5)
continue
headers = get_random_headers()
response = None
# ------------------------------------
for attempt in range(MAX_POLL_RETRIES):
try:
payload = {"login_hash": LOGIN_HASH}
response = await asyncio.to_thread(
worker_scraper.post,
BOOKING_URL,
headers=headers,
json=payload,
verify=certifi.where(), # Sorgulama için de SSL doğrulama ekleyelim
proxies=proxies,
timeout=15 # Sorgu timeout'u
)
if response.status_code == 200:
async with lock:
success_count += 1
response_text = response.text
asyncio.create_task(check_new_bookings(response_text))
polling_interval = 0 # Başarılı ise hemen tekrar dene
break # Başarılı, deneme döngüsünden çık
else:
if 400 <= response.status_code < 500:
polling_interval = 0.5
break #
if attempt + 1 < MAX_POLL_RETRIES:
await asyncio.sleep(POLL_RETRY_DELAY * (2 ** attempt))
else:
polling_interval = 0.5 #
except Exception as e:
polling_interval = 0.5
if attempt + 1 < MAX_POLL_RETRIES:
await asyncio.sleep(POLL_RETRY_DELAY * (2 ** attempt))
async def status_updater():
global success_count
global lock
last_print_time = time.monotonic()
while True:
await asyncio.sleep(max(0, STATUS_UPDATE_INTERVAL - (time.monotonic() - last_print_time)))
last_print_time = time.monotonic()
async with lock:
current_count = success_count
current_time_str = get_current_time_ms()
print(f"\r🔄 Toplam Başarılı Sorgu: {current_count} | Zaman: {current_time_str} ", end="")
# ===================================
# ANA PROGRAM YÖNETİMİ
# ===================================
async def main():
"""Worker ve status task'larını başlatır ve çalışmasını bekler."""
global loaded_proxies
global accept_scraper
if accept_scraper is None:
print("\n🛑 Kabul Scraper başlatılamadığı için program sonlandırılıyor.")
return
loaded_proxies = load_proxies_from_file(PROXY_FILE)
if not loaded_proxies:
print("\n🛑 Proxy yüklenemediği için worker'lar başlatılamıyor.")
return
print(f"\n🚀 {NUM_POLLING_WORKERS} adet sorgulama worker'ı ve durum güncelleyici başlatılıyor...")
tasks = []
for i in range(NUM_POLLING_WORKERS):
task = asyncio.create_task(poll_worker(i))
tasks.append(task)
status_task = asyncio.create_task(status_updater())
tasks.append(status_task)
print(f"\n✅ {len(tasks)} görev (worker + status) başarıyla oluşturuldu ve çalışıyor.")
print("-" * 35)
try:
await asyncio.gather(*tasks)
except asyncio.CancelledError:
print("\nℹ️ Görevler iptal edildi.")
except Exception as e:
print(f"\n❌ Ana görevde beklenmedik hata: {type(e).__name__} - {e}")
finally:
print("\n🛑 Program sonlandırılıyor.")
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
print("\nCTRL+C algılandı. Program kapatılıyor...")
except Exception as e:
print(f"\n❌ Program başlangıcında kritik hata: {e}")