90 lines
4.4 KiB
Python
90 lines
4.4 KiB
Python
import asyncio
|
||
import random
|
||
import time
|
||
import html
|
||
from aiogram import Bot
|
||
from database import Database
|
||
from kwork import get_kwork_projects, get_project_details
|
||
from ai import filter_vacancies_with_ai
|
||
|
||
class VacancyScanner:
|
||
def __init__(self, bot: Bot, db: Database):
|
||
self.bot = bot
|
||
self.db = db
|
||
self.current_page = 1
|
||
self.last_reset_time = time.time()
|
||
|
||
async def start_scanning(self):
|
||
while True:
|
||
try:
|
||
current_time = time.time()
|
||
if current_time - self.last_reset_time >= 3600:
|
||
print("--- Прошел час: возврат на 1 страницу ---")
|
||
self.current_page = 1
|
||
self.last_reset_time = current_time
|
||
|
||
print(f"--- Сканирую страницу {self.current_page} ---")
|
||
summary_vacancies = await get_kwork_projects(start_page=self.current_page, end_page=self.current_page)
|
||
|
||
if not summary_vacancies:
|
||
print(f"Страница {self.current_page} пуста. Сброс на 1 стр.")
|
||
self.current_page = 1
|
||
else:
|
||
print(f"Найдено {len(summary_vacancies)} вакансий на странице.")
|
||
users = await self.db.get_all()
|
||
|
||
for user in users:
|
||
user_id = user[1]
|
||
if not user[2] or not user[3]:
|
||
print(f"Пропуск пользователя {user_id}: профиль не заполнен.")
|
||
continue
|
||
|
||
# Отбираем новые вакансии
|
||
new_for_user = []
|
||
for v in summary_vacancies:
|
||
if not await self.db.is_vacancy_sent(user_id, v['url']):
|
||
new_for_user.append(v)
|
||
|
||
if not new_for_user:
|
||
print(f"Для пользователя {user_id} новых вакансий нет.")
|
||
continue
|
||
|
||
print(f"Отправка {len(new_for_user)} вакансий на анализ AI для юзера {user_id}...")
|
||
user_prefs = f"Сфера: {user[2]}, Стек: {user[3]}, Доп: {user[4]}"
|
||
|
||
filtered_vacancies = await filter_vacancies_with_ai(new_for_user, user_prefs)
|
||
print(f"AI отобрал {len(filtered_vacancies)} релевантных вакансий.")
|
||
|
||
for vac in filtered_vacancies:
|
||
# Получаем детали
|
||
full_info = await get_project_details(vac['url'])
|
||
description = full_info['description'] if full_info else vac.get('description', 'Нет описания')
|
||
|
||
title = html.escape(vac.get('title', 'Без названия'))
|
||
price = html.escape(vac.get('price', 'По договоренности'))
|
||
|
||
text = (
|
||
f"🎯 <b>Подходящий проект!</b>\n\n"
|
||
f"💼 <b>{title}</b>\n"
|
||
f"💰 <b>Бюджет:</b> {price}\n\n"
|
||
f"📝 <b>Описание:</b>\n{html.escape(description)}\n\n"
|
||
f"🔗 <a href='{vac['url']}'>Открыть на Kwork</a>"
|
||
)
|
||
|
||
try:
|
||
await self.bot.send_message(user_id, text, disable_web_page_preview=True)
|
||
await self.db.mark_vacancy_as_sent(user_id, vac['url'])
|
||
await asyncio.sleep(1)
|
||
except Exception as e:
|
||
print(f"Ошибка отправки сообщения: {e}")
|
||
|
||
self.current_page += 1
|
||
|
||
except Exception as e:
|
||
print(f"Критическая ошибка сканера: {e}")
|
||
await asyncio.sleep(60)
|
||
|
||
wait_time = random.uniform(150, 240)
|
||
print(f"Цикл завершен. Ожидание {wait_time/60:.2f} мин...")
|
||
await asyncio.sleep(wait_time)
|