import os import time import random # !!! Добавлен импорт модуля random !!! import datetime # !!! Добавлен импорт модуля datetime !!! from selenium import webdriver from selenium.webdriver.chrome.service import Service as ChromeService from selenium.webdriver.chrome.options import Options as ChromeOptions from webdriver_manager.chrome import ChromeDriverManager from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # from pyvirtualdisplay import Display # !!! Удален импорт Display !!! import pandas as pd import csv # !!! Добавлен импорт модуля csv !!! # --- Инициализация перед циклом --- # # Start virtual display # !!! Удалены строки, связанные с виртуальным дисплеем !!! # print("Запуск виртуального дисплея...") # display = Display(visible=0, size=(1920, 1080)) # display.start() # print("Виртуальный дисплей запущен. ") # Настройка и инициализация WebDriver print("Инициализация WebDriver...") chrome_options = ChromeOptions() chrome_options.add_argument('--headless') # !!! Убеждаемся, что headless режим включен !!! chrome_options.add_argument('--no-sandbox') chrome_options.add_argument('--disable-dev-shm-usage') chrome_options.add_argument('--disable-gpu') chrome_options.add_argument('--window-size=1920,1080') chrome_options.binary_location = '/usr/bin/google-chrome' service = ChromeService(ChromeDriverManager().install()) driver = webdriver.Chrome(service=service, options=chrome_options) print("WebDriver инициализирован. ") # !!! alice_interface.html используется ask_alice_via_interface для внутреннего отображения ответов Алисы. # !!! Его удаление или изменение без существенной переработки функции ask_alice_via_interface # !!! приведет к нарушению ее работы. # Создание HTML-интерфейса (один раз) html_content = """ Alice Interface

Talk to Alice

Alice's response will appear here.
""" file_name = 'alice_interface.html' with open(file_name, 'w') as f: f.write(html_content) print(f"HTML interface '{file_name}' создана успешно. ") html_file_path = os.path.abspath(file_name) # Определение функции для взаимодействия с Алисой (один раз) def ask_alice_via_interface(question_text): global driver, html_file_path # Доступ к глобальным driver и html_file_path print(f"Запрос Алисе: '{question_text}'") time.sleep(random.uniform(2, 5)) # !!! Добавлена случайная задержка перед переходом на сайт Алисы !!! # 1. Переходим на сайт Алисы driver.get('https://alice.yandex.ru') print("Переход на сайт Алисы.") # 2. Находим поле ввода на сайте Алисы try: input_field = WebDriverWait(driver, 15).until( EC.presence_of_element_located((By.CSS_SELECTOR, 'textarea')) ) except Exception: input_field = WebDriverWait(driver, 15).until( EC.presence_of_element_located((By.CSS_SELECTOR, 'input[type="text"]')) ) print("Поле ввода Алисы найдено.") # 3. Перед отправкой сообщения получаем общее количество сообщений в чате initial_total_messages_count = len(driver.find_elements(By.CSS_SELECTOR, 'div.Message')) time.sleep(random.uniform(1, 3)) # !!! Добавлена случайная задержка перед отправкой вопроса !!! # 4. Отправляем вопрос Алисе input_field.send_keys(question_text) input_field.send_keys(Keys.ENTER) print("Вопрос отправлен Алисе. Ожидание ответа...") # 5. Механизм ожидания и извлечения ответа Алисы alice_response = "" try: # 5.1. Ждем, пока общее количество сообщений в чате увеличится (ваш вопрос + ответ Алисы) WebDriverWait(driver, 60).until( lambda d: len(d.find_elements(By.CSS_SELECTOR, 'div.Message')) > initial_total_messages_count + 1 ) # 5.2. После того как общее количество сообщений увеличилось, находим элемент с z-index: 2 # Это должен быть самый свежий ответ Алисы, как было указано пользователем. alice_response_element = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CSS_SELECTOR, 'div.Message[style*="z-index: 2"]')) ) # 5.3. Ждем, пока текст в этом элементе станет достаточно длинным и стабильным def message_has_stable_text(driver_instance, element): current_text = element.text.strip() word_count = len(current_text.split()) # Подсчет слов if current_text and len(current_text) > 30: # Проверка на наличие существенного текста if word_count <= 200: # !!! Добавлена проверка на количество слов !!! time.sleep(random.uniform(0.5, 1.5)) # Случайная короткая задержка для проверки стабильности stable_text = element.text.strip() if stable_text == current_text: # Возвращаем текст, если он стабилен return stable_text else: print(f"Предупреждение: Ответ Алисы слишком длинный ({word_count} слов). Максимум 200 слов. ") return False alice_response = WebDriverWait(driver, 30).until( lambda d: message_has_stable_text(d, alice_response_element) ) if not alice_response: # Если alice_response пустой после ожидания (из-за слишком длинного ответа) alice_response = "Ошибка: Ответ Алисы превысил допустимую длину (более 200 слов)." print(f"Сырой ответ Алисы: {alice_response}") time.sleep(random.uniform(3, 7)) # !!! Добавлена случайная задержка после получения ответа Алисы !!! except Exception as e: print(f"Не удалось дождаться или извлечь ответ Алисы: {e}") alice_response = "Ошибка: Не удалось получить ответ от Алисы." # 6. Возвращаемся к локальному HTML-интерфейсу driver.get(f'file://{html_file_path}') print("Возврат к локальному HTML-интерфейсу.") # 7. Обновляем область отображения ответа Алисы в HTML # Очищаем ответ для вставки в JavaScript (экранируем кавычки) sanitized_response = alice_response.replace("'", "'").replace(' ', '
') script = f"document.getElementById('alice_response').innerHTML = '{sanitized_response}';" driver.execute_script(script) print("Ответ Алисы отображен в HTML-интерфейсе.") return alice_response print("Функция 'ask_alice_via_interface' определена. ") # --- Бесконечный цикл для повторной проверки каждые полчаса --- while True: print(f" --- Начинаем проверку и обработку в {time.ctime()} ---") bd_file_name = 'bd.csv' # 5. Load news articles from bd.csv df_bd = pd.DataFrame() try: # Check if bd.csv exists; if not, create a dummy one with proper columns if not os.path.exists(bd_file_name): print(f"'{bd_file_name}' not found. Creating a dummy file with 'published' and 'short_text' columns.") today = datetime.date.today() yesterday = today - datetime.timedelta(days=1) dummy_data_bd = { 'link': ['http://example.com/dummy_news_1', 'http://example.com/dummy_news_2', 'http://example.com/old_news'], 'full_text': [ 'Это первая фейковая новость о прорыве в технологиях. Она достаточно длинная для суммаризации.', 'Это вторая фейковая новость об экономических тенденциях и прогнозах.', 'Это старая новость о чем-то неактуальном, которая не должна быть суммаризирована.' ], 'published': [today.isoformat(), yesterday.isoformat(), (today - datetime.timedelta(days=7)).isoformat()], 'short_text': ['', '', ''] # Initially empty } dummy_df_bd = pd.DataFrame(dummy_data_bd) dummy_df_bd.to_csv(bd_file_name, index=False, sep=';', encoding='utf-8-sig', quoting=csv.QUOTE_ALL) print(f"Dummy '{bd_file_name}' created.") # Try multiple encodings and the new delimiter for bd.csv encodings_to_try = ['utf-8-sig', 'windows-1251', 'utf-8'] df_bd_loaded = False for enc in encodings_to_try: try: df_bd = pd.read_csv(bd_file_name, encoding=enc, sep=';') df_bd_loaded = True print(f"'{bd_file_name}' успешно загружен с кодировкой '{enc}' (sep=';'). Всего статей: {len(df_bd)})") break except (UnicodeDecodeError, pd.errors.ParserError) as read_e: print(f"Попытка загрузки '{bd_file_name}' с кодировкой '{enc}' (sep=';') не удалась: {read_e}.") continue if not df_bd_loaded: raise Exception("Не удалось загрузить bd.csv ни с одной из предложенных кодировок (sep=';').") # Ensure 'published' column is datetime and 'short_text' is string for filtering df_bd['published'] = pd.to_datetime(df_bd['published'], errors='coerce').dt.date df_bd['short_text'] = df_bd['short_text'].fillna('') # Fill NaN with empty string for consistent comparison except Exception as e: print(f"Ошибка загрузки или обработки '{bd_file_name}': {e}. Инициализация пустого DataFrame.") df_bd = pd.DataFrame(columns=['link', 'full_text', 'published', 'short_text']) # Ensure all columns are present # 6. Filtering for new articles to summarize # Articles published today or yesterday AND with empty short_text current_date = datetime.date.today() yesterday_date = current_date - datetime.timedelta(days=1) articles_to_summarize = df_bd[ ((df_bd['published'] == current_date) | (df_bd['published'] == yesterday_date)) & (df_bd['full_text'].notna()) & (df_bd['short_text'] == '') ].copy() if articles_to_summarize.empty: print("В этом цикле нет новых статей для суммаризации (опубликованы сегодня/вчера и без резюме).") else: print(f"Найдено {len(articles_to_summarize)} новых статей для суммаризации.") # 8. Summarize each new article with Alice and update df_bd for index, row in articles_to_summarize.iterrows(): original_link = row['link'] full_news_text = row['full_text'] # Construct the question for Alice with specific phrasing question_for_alice = f'Алиса, суммаризируй новость до 3 небольших предложений (раздельно) {full_news_text}' alice_summary = "" try: print(f" Summarizing: {original_link}") alice_summary = ask_alice_via_interface(question_for_alice) print(f" Summary received for {os.path.basename(original_link)}: {alice_summary[:100]}...") # Print first 100 chars # Add random delay after summarization before next article time.sleep(random.uniform(5, 10)) except Exception as e: print(f" Error processing {original_link}: {e}") alice_summary = "Ошибка: Не удалось получить резюме от Алисы." # Update the original df_bd DataFrame with the new summary df_bd.loc[index, 'short_text'] = alice_summary # 9. Save the updated df_bd to bd.csv after processing all new articles df_bd.to_csv(bd_file_name, index=False, sep=';', encoding='utf-8-sig', quoting=csv.QUOTE_ALL) print(f"Успешно суммаризированы и обновлены статьи в '{bd_file_name}'.") # 10. Pause before the next iteration print(f" Пауза на 30 минут до следующего цикла... (Следующий запуск в {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time() + 1800))})") time.sleep(random.uniform(1700, 1900)) # Random delay around 30 minutes print("Цикл суммаризации остановлен.") # --- Окончательная очистка (выполняется при прерывании цикла) --- print(" ## Инструкции по очистке: Закрытие WebDriver ") # !!! Убрана ссылка на виртуальный дисплей !!! print('Для освобождения ресурсов и правильного завершения работы Selenium WebDriver, пожалуйста, запустите следующие команды в новой ячейке кода, когда закончите все взаимодействия: ') # !!! Убрана ссылка на виртуальный дисплей !!! print('```python driver.quit() print("Selenium WebDriver закрыт.") ``` ') # !!! Убрана ссылка на виртуальный дисплей и его остановка !!! driver.quit() print("Selenium WebDriver закрыт.") # display.stop() # !!! Удалена остановка виртуального дисплея !!!