Adauga comenzi Telegram pentru solduri si repara get_telegram_chat_id

- Adauga /scrape_solduri - scraping rapid doar solduri (fara CSV tranzactii)
- Adauga /solduri - afisare instant solduri din cache (fara 2FA)
- Redenumeste comenzi pentru consistenta
- Adauga suport BALANCES_ONLY in scraper (skip download tranzactii)
- Repara get_telegram_chat_id.py - elimina input() interactiv
- Imbunatateste output get_telegram_chat_id.py cu info bot si formatare

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-11 01:03:02 +02:00
parent 7e8dadcbdc
commit e2ec15939c
3 changed files with 163 additions and 62 deletions

View File

@@ -93,8 +93,14 @@ class BTGoScraper:
def run(self): def run(self):
"""Entry point principal - orchestreaza tot flow-ul""" """Entry point principal - orchestreaza tot flow-ul"""
try: try:
# Check dacă rulăm în mod balances_only
balances_only = os.getenv('BALANCES_ONLY', 'false').lower() == 'true'
logging.info("=" * 60) logging.info("=" * 60)
logging.info("Start BTGO Scraper") if balances_only:
logging.info("Start BTGO Scraper (DOAR SOLDURI)")
else:
logging.info("Start BTGO Scraper")
logging.info("=" * 60) logging.info("=" * 60)
with sync_playwright() as p: with sync_playwright() as p:
@@ -115,9 +121,11 @@ class BTGoScraper:
accounts = self.read_accounts() accounts = self.read_accounts()
csv_path, json_path = self.save_results(accounts) csv_path, json_path = self.save_results(accounts)
# Descarcă tranzacții pentru toate conturile (optional) # Descarcă tranzacții pentru toate conturile (doar dacă nu e balances_only)
downloaded_files = [] downloaded_files = []
if self.config.DOWNLOAD_TRANSACTIONS: if balances_only:
logging.info("Mod DOAR SOLDURI - skip download tranzactii")
elif self.config.DOWNLOAD_TRANSACTIONS:
downloaded_files = self.download_transactions(accounts) downloaded_files = self.download_transactions(accounts)
else: else:
logging.info("Download tranzacții dezactivat (DOWNLOAD_TRANSACTIONS=false)") logging.info("Download tranzacții dezactivat (DOWNLOAD_TRANSACTIONS=false)")

View File

@@ -4,6 +4,7 @@ Helper script pentru obținerea Chat ID Telegram (pentru DM și grupuri)
""" """
import os import os
import sys
import requests import requests
from dotenv import load_dotenv from dotenv import load_dotenv
@@ -13,11 +14,20 @@ load_dotenv()
BOT_TOKEN = os.getenv('TELEGRAM_BOT_TOKEN') BOT_TOKEN = os.getenv('TELEGRAM_BOT_TOKEN')
if not BOT_TOKEN: if not BOT_TOKEN:
print("❌ TELEGRAM_BOT_TOKEN nu este setat în .env!") print("=" * 60)
print("EROARE: TELEGRAM_BOT_TOKEN nu este setat în .env")
print("=" * 60)
print("\nAdaugă în .env:") print("\nAdaugă în .env:")
print("TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrs") print("TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrs")
print("=" * 60)
exit(1) exit(1)
def get_bot_info():
"""Preia informații despre bot"""
url = f"https://api.telegram.org/bot{BOT_TOKEN}/getMe"
response = requests.get(url)
return response.json()
def get_updates(): def get_updates():
"""Preia ultimele update-uri de la bot""" """Preia ultimele update-uri de la bot"""
url = f"https://api.telegram.org/bot{BOT_TOKEN}/getUpdates" url = f"https://api.telegram.org/bot{BOT_TOKEN}/getUpdates"
@@ -28,96 +38,102 @@ def main():
print("=" * 60) print("=" * 60)
print(" Telegram Chat ID Helper") print(" Telegram Chat ID Helper")
print("=" * 60) print("=" * 60)
print()
print("📱 Instrucțiuni:")
print("1. Trimite /start către bot (DM)")
print(" SAU")
print("2. Trimite /start în grupul unde ai bot-ul")
print()
print("Apasă Enter după ce ai trimis mesajul...")
input()
print("\n🔍 Căutare mesaje...") # Verifică info bot
bot_data = get_bot_info()
if bot_data.get('ok'):
bot = bot_data['result']
print(f"\nBot: @{bot.get('username')} ({bot.get('first_name')})")
print(f"Bot ID: {bot.get('id')}")
print(f"Status: ACTIV")
else:
print(f"\nERORE: Token invalid - {bot_data}")
exit(1)
print("\n" + "=" * 60)
print("Căutare mesaje...")
print("=" * 60)
data = get_updates() data = get_updates()
if not data.get('ok'): if not data.get('ok'):
print(f"❌ Eroare API: {data}") print(f"\nERORE API: {data}")
return return
results = data.get('result', []) results = data.get('result', [])
if not results: if not results:
print("❌ Niciun mesaj găsit!") print("\nNU S-AU GĂSIT MESAJE!")
print("\nAsigură-te că:") print("\n" + "=" * 60)
print("• Ai trimis /start către bot SAU în grup") print("INSTRUCȚIUNI:")
print("• Bot-ul este adăugat în grup (dacă folosești grup)") print("=" * 60)
print("• Token-ul este corect") print("1. Deschide Telegram")
print(f"2. Caută @{bot.get('username')} SAU deschide grupul cu bot-ul")
print("3. Trimite un mesaj (ex: /start sau /info)")
print("4. Rulează din nou acest script")
print("=" * 60)
return return
print(f"\nGăsit {len(results)} mesaje!\n") print(f"\nGăsit {len(results)} mesaje în total")
# Procesează ultimele mesaje (ultimele 20)
seen_chats = {}
user_ids = set()
print("\n" + "=" * 60)
print("CHAT IDs DETECTATE:")
print("=" * 60) print("=" * 60)
# Procesează ultimele mesaje for update in results[-20:]: # Ultimele 20 mesaje
seen_chats = {}
for update in results:
if 'message' in update: if 'message' in update:
msg = update['message'] msg = update['message']
chat = msg['chat'] chat = msg['chat']
chat_id = chat['id'] chat_id = chat['id']
chat_type = chat['type'] chat_type = chat['type']
user = msg['from']
user_ids.add(user['id'])
text = msg.get('text', '(no text)')
# Evită duplicate # Evită duplicate
if chat_id in seen_chats: if chat_id in seen_chats:
continue continue
seen_chats[chat_id] = True seen_chats[chat_id] = chat
# Detalii chat # Detalii chat
if chat_type == 'private': if chat_type == 'private':
# DM # DM
user = msg['from'] print(f"\n[DM] {user.get('first_name', '')} {user.get('last_name', '')}")
print(f"📱 DM cu {user.get('first_name', 'Unknown')}") print(f" Username: @{user.get('username', 'N/A')}")
print(f" User ID: {user['id']}") print(f" User ID: {user['id']}")
print(f" Username: @{user.get('username', 'N/A')}") print(f" Chat ID: {chat_id}")
print(f" Chat ID: {chat_id}")
elif chat_type in ['group', 'supergroup']: elif chat_type in ['group', 'supergroup']:
# Grup # Grup
print(f"👥 Grup: {chat.get('title', 'Unknown')}") print(f"\n[GRUP] {chat.get('title', 'Unknown')}")
print(f" Chat ID: {chat_id} ⚠️ NEGATIV pentru grupuri!") print(f" Chat ID: {chat_id}")
print(f" Tip: {chat_type}") print(f" Tip: {chat_type}")
# User care a trimis mesajul print(f" User: @{user.get('username', 'Unknown')} (ID: {user['id']})")
user = msg['from']
print(f" Mesaj de la: @{user.get('username', 'Unknown')} (ID: {user['id']})")
print() print(f" Mesaj: \"{text[:60]}\"")
print("\n" + "=" * 60)
print("CONFIGURARE .env:")
print("=" * 60) print("=" * 60)
print("\n💡 Pentru configurare .env:")
print()
# Recomandări # Recomandări
for chat_id, chat_data in seen_chats.items(): for chat_id, chat in seen_chats.items():
if chat_id < 0: # Grup if chat_id < 0: # Grup
print(f"# Pentru grup (notificări + comenzi):") print(f"\n# Grup: {chat.get('title', 'Unknown')}")
print(f"TELEGRAM_CHAT_ID={chat_id}") print(f"TELEGRAM_CHAT_ID={chat_id}")
else: # DM else: # DM
print(f"# Pentru DM:") print(f"\n# DM")
print(f"TELEGRAM_CHAT_ID={chat_id}") print(f"TELEGRAM_CHAT_ID={chat_id}")
print() if user_ids:
print("# User IDs autorizați (pot rula /scrape):") user_ids_str = ",".join(str(uid) for uid in sorted(user_ids))
print("TELEGRAM_ALLOWED_USER_IDS=", end="") print(f"\n# User IDs autorizați")
print(f"TELEGRAM_ALLOWED_USER_IDS={user_ids_str}")
# Colectează user IDs unice print("\n" + "=" * 60)
user_ids = set()
for update in results:
if 'message' in update:
user_id = update['message']['from']['id']
user_ids.add(user_id)
print(",".join(str(uid) for uid in sorted(user_ids)))
print()
print("=" * 60)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@@ -9,6 +9,7 @@ import io
import subprocess import subprocess
import logging import logging
import json import json
import csv
import zipfile import zipfile
from pathlib import Path from pathlib import Path
from datetime import datetime from datetime import datetime
@@ -65,6 +66,8 @@ class TelegramTriggerBot:
commands = [ commands = [
{"command": "scrape", "description": "Rulează scraper-ul BTGO"}, {"command": "scrape", "description": "Rulează scraper-ul BTGO"},
{"command": "scrape_zip", "description": "Rulează scraper + trimite ZIP"}, {"command": "scrape_zip", "description": "Rulează scraper + trimite ZIP"},
{"command": "scrape_solduri", "description": "Extrage doar soldurile (fără CSV)"},
{"command": "solduri", "description": "Afișează ultimul fișier solduri"},
{"command": "zip", "description": "Trimite ultimele fișiere ca ZIP"}, {"command": "zip", "description": "Trimite ultimele fișiere ca ZIP"},
{"command": "status", "description": "Status sistem"}, {"command": "status", "description": "Status sistem"},
{"command": "help", "description": "Ajutor comenzi"} {"command": "help", "description": "Ajutor comenzi"}
@@ -108,11 +111,12 @@ class TelegramTriggerBot:
return True return True
return user_id in self.allowed_users return user_id in self.allowed_users
def run_scraper(self, chat_id, reply_to_message_id=None, send_as_zip=False): def run_scraper(self, chat_id, reply_to_message_id=None, send_as_zip=False, balances_only=False):
"""Execută scraper-ul""" """Execută scraper-ul"""
# Trimite mesaj inițial și salvează message_id pentru editare ulterioară # Trimite mesaj inițial și salvează message_id pentru editare ulterioară
zip_msg = " (arhiva ZIP)" if send_as_zip else "" zip_msg = " (arhiva ZIP)" if send_as_zip else ""
response = self.send_message(chat_id, f"*BTGO Scraper pornit{zip_msg}*\n\nAsteapta 2FA pe telefon.", reply_to_message_id) balances_msg = " - DOAR SOLDURI" if balances_only else ""
response = self.send_message(chat_id, f"*BTGO Scraper pornit{zip_msg}{balances_msg}*\n\nAsteapta 2FA pe telefon.", reply_to_message_id)
message_id = None message_id = None
try: try:
message_id = response.json()['result']['message_id'] message_id = response.json()['result']['message_id']
@@ -122,7 +126,7 @@ class TelegramTriggerBot:
try: try:
# Rulează scraper-ul # Rulează scraper-ul
logging.info(f"Pornire scraper (send_as_zip={send_as_zip})...") logging.info(f"Pornire scraper (send_as_zip={send_as_zip}, balances_only={balances_only})...")
# Prepare environment with global playwright path + Telegram progress info # Prepare environment with global playwright path + Telegram progress info
env = os.environ.copy() env = os.environ.copy()
@@ -138,6 +142,11 @@ class TelegramTriggerBot:
if send_as_zip: if send_as_zip:
env['SEND_AS_ZIP'] = 'true' env['SEND_AS_ZIP'] = 'true'
logging.info("Mod ZIP activat - va trimite arhivă ZIP") logging.info("Mod ZIP activat - va trimite arhivă ZIP")
# Dacă balances_only, comunică să nu descarce tranzacții
if balances_only:
env['BALANCES_ONLY'] = 'true'
logging.info("Mod DOAR SOLDURI activat - nu va descărca tranzacții")
else: else:
logging.warning("No message_id available for progress updates") logging.warning("No message_id available for progress updates")
@@ -172,6 +181,59 @@ class TelegramTriggerBot:
logging.error(f"Eroare execuție: {e}") logging.error(f"Eroare execuție: {e}")
self.send_message(chat_id, f"*EROARE EXECUTIE*\n\n```\n{str(e)}\n```", reply_to_message_id) self.send_message(chat_id, f"*EROARE EXECUTIE*\n\n```\n{str(e)}\n```", reply_to_message_id)
def show_cached_balances(self, chat_id, reply_to_message_id=None):
"""Afișează soldurile din cel mai recent fișier solduri.csv"""
try:
data_dir = Path('data')
if not data_dir.exists():
self.send_message(chat_id, "*EROARE*\n\nDirectorul 'data' nu există!", reply_to_message_id)
return
# Găsește ultimul fișier solduri
solduri_files = sorted(data_dir.glob('solduri_*.csv'), key=lambda x: x.stat().st_mtime, reverse=True)
if not solduri_files:
self.send_message(chat_id, "*EROARE*\n\nNu s-au găsit fișiere solduri!", reply_to_message_id)
return
latest_solduri = solduri_files[0]
solduri_time = latest_solduri.stat().st_mtime
file_datetime = datetime.fromtimestamp(solduri_time).strftime('%Y-%m-%d %H:%M:%S')
# Citește fișierul CSV
accounts = []
with open(latest_solduri, 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
accounts.append({
'nume_cont': row['nume_cont'],
'sold': float(row['sold']),
'moneda': row['moneda']
})
# Construiește mesaj cu solduri
total_ron = sum(acc['sold'] for acc in accounts if acc.get('moneda') == 'RON')
message = f"*SOLDURI BANCARE*\n\n"
message += f"Data: {file_datetime}\n"
message += f"Conturi: {len(accounts)}\n\n"
for acc in accounts:
nume = acc['nume_cont']
sold = acc['sold']
moneda = acc['moneda']
message += f"{nume}: {sold:,.2f} {moneda}\n"
message += f"\n*TOTAL: {total_ron:,.2f} RON*"
self.send_message(chat_id, message, reply_to_message_id)
logging.info(f"Afișat solduri cached din {latest_solduri.name}")
except Exception as e:
logging.error(f"Eroare show_cached_balances: {e}", exc_info=True)
self.send_message(chat_id, f"*EROARE*\n\n```\n{str(e)}\n```", reply_to_message_id)
def send_zip_files(self, chat_id, reply_to_message_id=None): def send_zip_files(self, chat_id, reply_to_message_id=None):
"""Trimite ultimele fișiere ca arhivă ZIP""" """Trimite ultimele fișiere ca arhivă ZIP"""
try: try:
@@ -332,8 +394,10 @@ class TelegramTriggerBot:
welcome_msg += f"Bot activ in grupul *{chat_title}*\n\n" welcome_msg += f"Bot activ in grupul *{chat_title}*\n\n"
welcome_msg += ( welcome_msg += (
"Comenzi disponibile:\n" "Comenzi disponibile:\n"
"`/scrape` - Ruleaza scraper-ul\n" "`/scrape` - Ruleaza scraper-ul complet\n"
"`/scrape_zip` - Ruleaza scraper + trimite ZIP\n" "`/scrape_zip` - Ruleaza scraper + trimite ZIP\n"
"`/scrape_solduri` - Extrage doar soldurile (rapid)\n"
"`/solduri` - Afiseaza ultimul fisier solduri\n"
"`/zip` - Trimite ultimele fisiere ca ZIP\n" "`/zip` - Trimite ultimele fisiere ca ZIP\n"
"`/status` - Status sistem\n" "`/status` - Status sistem\n"
"`/help` - Ajutor" "`/help` - Ajutor"
@@ -348,6 +412,14 @@ class TelegramTriggerBot:
logging.info(f"Comandă /scrape_zip primită în {context}") logging.info(f"Comandă /scrape_zip primită în {context}")
self.run_scraper(chat_id, message_id, send_as_zip=True) self.run_scraper(chat_id, message_id, send_as_zip=True)
elif text == '/scrape_solduri':
logging.info(f"Comandă /scrape_solduri primită în {context}")
self.run_scraper(chat_id, message_id, balances_only=True)
elif text == '/solduri':
logging.info(f"Comandă /solduri primită în {context}")
self.show_cached_balances(chat_id, message_id)
elif text == '/zip': elif text == '/zip':
logging.info(f"Comandă /zip primită în {context}") logging.info(f"Comandă /zip primită în {context}")
self.send_zip_files(chat_id, message_id) self.send_zip_files(chat_id, message_id)
@@ -381,20 +453,25 @@ class TelegramTriggerBot:
"*COMENZI:*\n" "*COMENZI:*\n"
"`/scrape` - Ruleaza scraper + trimite fisiere individuale\n" "`/scrape` - Ruleaza scraper + trimite fisiere individuale\n"
"`/scrape_zip` - Ruleaza scraper + trimite arhiva ZIP\n" "`/scrape_zip` - Ruleaza scraper + trimite arhiva ZIP\n"
"`/scrape_solduri` - Extrage doar soldurile (fara CSV tranzactii)\n"
"`/solduri` - Afiseaza ultimul fisier solduri (instant)\n"
"`/zip` - Trimite ultimele fisiere ca arhiva ZIP (fara scraping)\n" "`/zip` - Trimite ultimele fisiere ca arhiva ZIP (fara scraping)\n"
"`/status` - Informatii sistem\n" "`/status` - Informatii sistem\n"
"`/help` - Acest mesaj\n\n" "`/help` - Acest mesaj\n\n"
"*GHID SCRAPER:*\n" "*GHID SCRAPER:*\n"
"1. Trimite `/scrape` sau `/scrape_zip`\n" "1. Trimite `/scrape`, `/scrape_zip` sau `/scrape_solduri`\n"
"2. Asteapta notificarea de 2FA pe telefon\n" "2. Asteapta notificarea de 2FA pe telefon\n"
"3. Aproba in aplicatia George\n" "3. Aproba in aplicatia George\n"
"4. Primesti fisierele automat\n\n" "4. Primesti fisierele automat\n\n"
"*DIFERENTE:*\n" "*DIFERENTE:*\n"
"• `/scrape` - Fisiere individuale (CSV + JSON)\n" "• `/scrape` - Fisiere individuale (CSV + JSON)\n"
"• `/scrape_zip` - Un singur ZIP cu toate fisierele\n" "• `/scrape_zip` - Un singur ZIP cu toate fisierele\n"
"• `/zip` - Rapid, foloseste datele existente\n\n" "• `/scrape_solduri` - Doar solduri (RAPID - fara CSV tranzactii)\n"
"• `/solduri` - Vizualizare rapida (fara 2FA)\n"
"• `/zip` - Fisiere existente (fara scraping)\n\n"
"*NOTE:*\n" "*NOTE:*\n"
"- Scraper-ul ruleaza ~2-3 minute\n" "- Scraper complet: ~2-3 minute\n"
"- Scraper solduri: ~30-40 secunde\n"
"- VM-ul trebuie sa aiba browser vizibil" "- VM-ul trebuie sa aiba browser vizibil"
) )
self.send_message(chat_id, help_msg, message_id) self.send_message(chat_id, help_msg, message_id)