| |
|
| | import os |
| | import time |
| | import random |
| | import 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 |
| | |
| | import pandas as pd |
| | import csv |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | ") |
| | |
| | # Настройка и инициализация 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 = """ |
| | <!DOCTYPE html> |
| | <html> |
| | <head> |
| | <title>Alice Interface</title> |
| | <style> |
| | body { font-family: Arial, sans-serif; margin: 20px; background-color: |
| | .container { max-width: 800px; margin: auto; background-color: |
| | h1 { color: |
| | |
| | |
| | |
| | |
| | |
| | </style> |
| | </head> |
| | <body> |
| | <div class="container"> |
| | <h1>Talk to Alice</h1> |
| | <div id="input_area"> |
| | <input type="text" id="question_input" placeholder="Ask Alice a question..."> |
| | <button id="ask_button">Ask Alice</button> |
| | </div> |
| | <div id="alice_response">Alice's response will appear here.</div> |
| | </div> |
| | </body> |
| | </html> |
| | """ |
| | |
| | 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(' |
| | ', '<br>') |
| | 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() # !!! Удалена остановка виртуального дисплея !!! |
| | |