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