#!/usr/bin/env python3 import re import logging import html2text import urllib.parse from bs4 import BeautifulSoup class ContentProcessor: def __init__(self): self.logger = logging.getLogger(__name__) def make_soup(self, response): self.logger.debug("Создаем объект BeautifulSoup") return BeautifulSoup(response.text, 'html.parser') def html_to_text(self, html_content): self.logger.debug(f"Конвертируем HTML в текст") self.logger.debug(f"HTML на входе: {html_content}") h = html2text.HTML2Text() h.ignore_links = False h.ignore_images = True h.bypass_tables = True h.reference_links = True markdown_text = h.handle(html_content) self.logger.debug(f"Текст до обработки регулярными выражениями: {markdown_text}") # Удаление переносов строк из-за - markdown_text = re.sub(r'-\s*\n\s*', '-', markdown_text, flags=re.DOTALL) markdown_text = re.sub(r'-\s*\n*', '-', markdown_text, flags=re.DOTALL) # Убираем переносы строк внутри круглых скобок () markdown_text = re.sub(r'\((.*?)\)', lambda x: '(' + x.group(1).replace('\n', ' ') + ')', markdown_text, flags=re.DOTALL) # Убираем переносы строк внутри квадратных скобок [] markdown_text = re.sub(r'\[(.*?)\]', lambda x: '[' + x.group(1).replace('\n', ' ') + ']', markdown_text, flags=re.DOTALL) # Удаление строк, содержащих '* * *' markdown_text = re.sub(r'^.*\* \* \*.*$', '', markdown_text, flags=re.MULTILINE) # Преобразование всех ссылок с параметрами URL markdown_text = self.convert_links(markdown_text) # Работа с # patterns_to_remove = [ r'###', r'##', r'#', r'\[scripts\]\(\/tag\/scripts\) version \d+ ', r'##\[scripts\]\(\) version \d+ ', r'\d{4}×\d{3} \d+ KB' ] for pattern in patterns_to_remove: markdown_text = re.sub(pattern, '', markdown_text) # Удаление избыточных пустых строк после удаления строк markdown_text = re.sub(r'\n\s*\n', '\n', markdown_text) # Замена текстов типа "image1280×474 99.7 KB", "807×454 64.1 KB" на "." markdown_text = re.sub(r'image\d+×\d+\s+\d+(\.\d+)?\s+KB', '.', markdown_text) markdown_text = re.sub(r'\d+×\d+\s+\d+(\.\d+)?\s+KB', '.', markdown_text) # Изменение ссылок без описания markdown_text = re.sub(r'\[\]\((https:\/\/[^\)]+)\)', r'[.](\1)', markdown_text) markdown_text = re.sub(r'\[\s]\((https:\/\/[^\)]+)\)', r'[.](\1)', markdown_text) # Удаление дублирующихся ссылок markdown_text = self.remove_duplicate_links(markdown_text) # Удаление лишних отступов для строк, начинающихся с '*' markdown_text = re.sub(r' \*', r'*', markdown_text) # Перемещение ссылки на изображение в конец последней строки image_link = "[.](https://linux-gaming.ru/uploads/default/original/1X/5cfa59077a5275971401fab0114e56f3ffdd0ec4.png)" if image_link in markdown_text: markdown_text = markdown_text.replace(image_link, '') markdown_text = markdown_text + image_link self.logger.debug(f"Текст после обработки: {markdown_text}") return markdown_text def convert_links(self, text): self.logger.debug("Конвертируем ссылки") url_pattern = re.compile(r'https?://[^\s\)]+') url_pattern = url_pattern.sub(lambda match: self.decode_url_params(match.group(0)), text) self.logger.debug(f"Результат конвертации ссылок: {url_pattern}") return url_pattern def decode_url_params(self, url): self.logger.debug(f"Декодируем URL параметры: {url}") parsed_url = urllib.parse.urlparse(url) query_params = urllib.parse.parse_qs(parsed_url.query) for key, values in query_params.items(): if key.lower() == 'to' and values: return urllib.parse.unquote(values[0]) self.logger.debug(f"Возвращаем URL: {url}") return url def remove_empty_lines(self, text_data): self.logger.debug("Удаляем пустые строки") lines = text_data.splitlines() non_empty_lines = [line for line in lines if line.strip()] non_empty_lines = '\n'.join(non_empty_lines) self.logger.debug(f"Результат удаления пустых строк: {non_empty_lines}") return non_empty_lines def remove_markdown_links(self, markdown_text): self.logger.debug("Удаляем markdown ссылки") markdown_text = re.sub(r'\[.*?\]\((https?://.*?)\)', r'\1', markdown_text) self.logger.debug(f"Результат удаления markdown ссылок: {markdown_text}") return markdown_text def remove_duplicate_links(self, text): self.logger.debug("Удаляем дубликаты ссылок") seen_links = set() def replace_link(match): link = match.group(2) if link in seen_links: return '' seen_links.add(link) return match.group(0) link_pattern = re.compile(r'(\[.*?\]\((https:\/\/.*?)\))') text = re.sub(link_pattern, replace_link, text) self.logger.debug(f"Результат удаления дубликатов ссылок: {text}") return text def extract_links(self, text): self.logger.debug("Извлекаем ссылки из текста") # Улучшенное регулярное выражение, исключающее конечные знаки препинания url_pattern = re.compile(r'https?://[^\s\)\]\}\>,;]+') links = url_pattern.findall(text) # Дополнительная очистка: убираем точки и запятые в конце cleaned_links = [] for link in links: link = link.rstrip('.,!?') cleaned_links.append(link) self.logger.debug(f"Найденные ссылки: {cleaned_links}") return cleaned_links def format_for_vk(self, content): """Форматирование контента для VK""" self.logger.debug("Форматируем контент для VK") # Замена маркеров списка content = re.sub(r'\* ', '•', content) content = re.sub(r' •', '➜', content) content = re.sub(r' •', '➜', content) # Удаление markdown ссылок content = self.remove_markdown_links(content) # Замена изображения content = re.sub( r'https://linux-gaming.ru/uploads/default/original/1X/5cfa59077a5275971401fab0114e56f3ffdd0ec4.png', '\n', content, flags=re.DOTALL ) return content def format_for_telegram(self, content): """Форматирование контента для Telegram""" self.logger.debug("Форматируем контент для Telegram") return content # Telegram поддерживает markdown def create_script_content(self, script_ver, next_version, response): """Создание контента для обновления скрипта""" self.logger.debug(f"Создаем контент для версии скрипта {script_ver}") soup = self.make_soup(response) page_text = str(soup) page_text = page_text.replace("Вы можете помочь развитию проекта: https://linux-gaming.ru/donate/", '') last_text = f"###Scripts version {next_version}### / stable" index_last_text = page_text.find(last_text) if index_last_text != -1: changelog_text_last = page_text[:index_last_text] prev_text = f"###Scripts version {script_ver}### / stable" index_script_ver = changelog_text_last.find(prev_text) changelog_text = changelog_text_last[index_script_ver:] changelog_text = re.sub( r'###Scripts version (\d+)### / Дата: (\d{2}\.\d{2}\.\d{4}) / Размер скачиваемого обновления: \d+ \S+', r'\1 - \2' + ":", changelog_text ) changelog_text = re.sub( r'###Scripts version (\d+)### / stable / Дата: (\d{2}\.\d{2}\.\d{4}) / Размер скачиваемого обновления: \d+ \S+', r'\1 - \2' + ":", changelog_text ) post_text = "-----------------------------\n" + changelog_text self.logger.debug(f"Возвращаем post_text: {post_text}") return post_text return None