parser_version7
/
osnovaTG.py
236 строк · 11.2 Кб
1import asyncio2from aiogram import Bot, Dispatcher, types3from aiogram.types import Message4from aiogram.fsm.storage.memory import MemoryStorage5from aiogram.fsm.context import FSMContext6from aiogram.filters import Command7from aiogram.fsm.state import StatesGroup, State8from datetime import date, timedelta9from test2 import parse_and_save10import mysql.connector11import hashlib12
13# Замените на ваш токен и ID группы
14TOKEN = "7032031280:AAEjXQh-WNlqfY2el6a7cj0PtUvJNh-vLM0"15GROUP_ID = "-1002448868558" # Для теста16
17# Ключевые слова для поиска
18keywords = [19"обыски", "задержан", "досудебное расследование", "уголовный процесс", "уголовное дело", "обвинение",20"привлечение к уголовной ответственности", "экономическое преступление", "корпоративное мошенничество",21"уклонение от уплаты налогов", "легализация доходов", "отмывание доходов", "хищение", "вымогательство",22"судебное рассмотрение", "подача апелляции", "кассационная жалоба", "арест имущества", "налоговый аудит",23"налоговая проверка", "налоговое правонарушение", "налоговый спор", "отмывание доходов",24"открытие дела о банкротстве", "заявление о несостоятельности", "признаки неплатежеспособности",25"реструктуризация долгов", "ликвидация компании", "арбитражное разбирательство", "введение конкурсного производства",26"требования кредиторов", "мировое соглашение", "корпоративный спор"27]
28
29# Инициализация бота и диспетчера
30bot = Bot(token=TOKEN, timeout=60)31storage = MemoryStorage()32dp = Dispatcher(storage=storage)33
34# Конфигурация базы данных
35config = {36'user': 'root',37'password': 'Uz94deco!',38'host': '127.0.0.1',39'database': 'parser'40}
41
42# Класс для состояний FSM
43class DaysForm(StatesGroup):44waiting_for_days = State()45
46# Функция для нормализации текста сообщения
47def normalize_text(text):48return ' '.join(text.strip().split()).lower() # Убираем лишние пробелы и приводим текст к нижнему регистру49
50# Функция для вычисления хеша текста сообщения
51def get_text_hash(text):52normalized_text = normalize_text(text)53return hashlib.sha256(normalized_text.encode('utf-8')).hexdigest()54
55# Функция для получения истории сообщений группы (до 1000 сообщений)
56async def get_group_messages(limit=1000):57all_messages = []58all_hashes = []59try:60offset_message_id = None # ID последнего полученного сообщения для смещения61
62while len(all_messages) < limit:63# Получаем 100 сообщений с возможным смещением64messages = await bot.get_chat_history(chat_id=GROUP_ID, limit=100, offset_message_id=offset_message_id)65
66if not messages:67break # Если сообщений больше нет, выходим из цикла68
69for message in messages:70if message.text:71normalized_message = normalize_text(message.text)72all_messages.append(normalized_message)73all_hashes.append(get_text_hash(normalized_message))74
75# Устанавливаем ID последнего сообщения для следующего смещения76offset_message_id = messages[-1].message_id77
78# Ограничиваем общее количество сообщений до запрашиваемого лимита79return all_messages[:limit], all_hashes[:limit]80
81except Exception as e:82print(f"Ошибка при получении истории сообщений группы: {e}")83return [], []84
85# Проверка наличия дубликатов по хешам сообщений в группе или базе данных
86async def is_duplicate(post_text, group_messages_hashes, conn):87post_text_hash = get_text_hash(post_text)88
89# Проверка на дубликат в истории сообщений группы90if post_text_hash in group_messages_hashes:91return True92
93# Проверка на дубликат в базе данных94cursor = conn.cursor()95cursor.execute("SELECT COUNT(*) FROM sent_posts WHERE post_hash = %s", (post_text_hash,))96count = cursor.fetchone()[0]97cursor.close()98
99return count > 0100
101# Ограничиваем скорость запросов, чтобы избежать лимитов
102async def send_message_with_delay(text, conn):103try:104await bot.send_message(GROUP_ID, text)105
106# Сохраняем хеш отправленного сообщения в базе данных107post_text_hash = get_text_hash(text)108cursor = conn.cursor()109cursor.execute("INSERT INTO sent_posts (post_hash) VALUES (%s)", (post_text_hash,))110conn.commit()111cursor.close()112
113await asyncio.sleep(5) # Задержка между запросами, чтобы избежать лимита114except Exception as e:115print(f"Ошибка при отправке сообщения: {e}")116
117# Функция отправки уникальных постов
118async def send_unique_posts():119try:120conn = mysql.connector.connect(**config)121cursor = conn.cursor(dictionary=True)122cursor.execute("SELECT post_text, time, channel_name FROM posts") # Добавили post_date и channel_name123posts = cursor.fetchall()124
125# Получаем до 1000 сообщений из группы и их хеши126group_messages, group_messages_hashes = await get_group_messages(1000)127
128for post in posts:129post_text = post['post_text']130time = post['time'].strftime('%d-%m-%Y')131channel_name = post['channel_name']132
133# Перебираем все ключевые слова134for keyword in keywords:135if keyword.lower() in post_text.lower():136formatted_message = f"Канал: {channel_name}\nДата: {time}\nКлючевое слово: {keyword}\n\n{post_text}"137
138is_dup = await is_duplicate(formatted_message, group_messages_hashes, conn)139
140if not is_dup:141await send_message_with_delay(formatted_message, conn)142print(f"Отправлен уникальный пост: {formatted_message}")143else:144print(f"Пост пропущен (дубликат): {formatted_message}")145
146except Exception as e:147print(f"Ошибка при отправке уникальных постов: {e}")148finally:149cursor.close()150conn.close()151
152# Загрузка ссылок и ключевых слов из файлов
153def load_links_and_keywords():154try:155with open('Links.txt', 'r', encoding='utf-8') as f:156links = [line.strip() for line in f.readlines()]157with open('keywords.txt', 'r', encoding='utf-8') as f:158keywords = [line.strip() for line in f.readlines()]159return links, keywords160except Exception as e:161print(f"Ошибка при загрузке ссылок или ключевых слов: {e}")162return [], []163
164# Загрузка количества дней из файла
165def load_days():166try:167with open('days.txt', 'r') as f:168return int(f.read().strip())169except Exception as e:170print(f"Ошибка при загрузке дней: {e}")171return 7 # Значение по умолчанию172
173# Сохранение количества дней в файл
174def save_days(days):175try:176with open('days.txt', 'w') as f:177f.write(str(days))178except Exception as e:179print(f"Ошибка при сохранении дней: {e}")180
181# Фоновая задача для парсинга каждые 15 минут
182async def scheduled_parsing():183while True:184try:185days = load_days() # Загружаем количество дней из файла186links, keywords = load_links_and_keywords()187nazvanie = ["Бойлерная", "Кремлёвский безБашенник", "Силовики", "НЕЗЫГАРЬ", "ОПЕР Слил", "SHOT", "Mash", "Baza", "ВЧК-ОГПУ", "КОНТЕКСТ"] # Названия каналов188
189start_date = date.today() - timedelta(days=days)190
191# Асинхронный запуск парсинга192await asyncio.to_thread(parse_and_save, links, nazvanie, keywords, start_date)193
194# Отправка уникальных постов195await send_unique_posts()196
197except Exception as e:198print(f"Ошибка в фоновом парсинге: {e}")199
200await asyncio.sleep(900) # Повтор каждые 15 минут201
202# Команда /start
203@dp.message(Command("start"))204async def start_command(message: Message, state: FSMContext):205await message.answer("""Здравствуйте, вас привествует бот по Парсеру данных из разных каналов.206Основные команды в боте:
207
208/start - запуск бота.
209/change_days - изменить время для парсера данных.""")210await message.answer("Сколько дней вы хотите парсить данные?")211await state.set_state(DaysForm.waiting_for_days)212
213# Команда для изменения количества дней
214@dp.message(Command("change_days"))215async def change_days(message: Message, state: FSMContext):216await message.answer("Введите количество дней для парсинга:")217await state.set_state(DaysForm.waiting_for_days)218
219# Обработка ответа на вопрос о днях
220@dp.message(DaysForm.waiting_for_days)221async def process_days(message: Message, state: FSMContext):222try:223days = int(message.text)224save_days(days) # Сохраняем количество дней в файл225await message.answer(f"Количество дней успешно изменено на {days}.")226except ValueError:227await message.answer("Пожалуйста, введите число.")228await state.clear()229
230# Запуск фона
231async def on_startup():232asyncio.create_task(scheduled_parsing())233
234if __name__ == "__main__":235dp.startup.register(on_startup)236dp.run_polling(bot)237