парсинг страницы происходит, ошибка при отправке запроса на нейронку, нужно разбираться, возможно из за величины текста или частые запросы
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2026-04-09 15:56:09 +10:00
parent f4791491ef
commit 5d724a7a8d
2 changed files with 91 additions and 45 deletions

113
main.py
View File

@@ -9,7 +9,6 @@ from datetime import datetime, timedelta
import random
import zipfile
# from rarfile import RarFile
import tempfile
# Сторонние библиотеки (third-party)
@@ -17,17 +16,18 @@ from apscheduler.schedulers.asyncio import AsyncIOScheduler
from bs4 import BeautifulSoup
from contextlib import asynccontextmanager
from docx import Document
from newspaper import Article
from fastapi import BackgroundTasks, FastAPI, Query, Request, Depends
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse
from pydantic import BaseModel
from urllib.parse import urljoin
from pydantic import BaseModel, HttpUrl
from urllib.parse import urljoin, urlparse, urldefrag
import uvicorn
import requests
# Локальные импорты
import settings_work as sw
# import settings_work as sw
import work_parser as wp
DOCUMENTS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "documents")
@@ -206,21 +206,9 @@ def extract_text_from_url(url, timeout=10, verify=True):
return "\n".join(content_text), time_t
# Общий запрос на GPT
def gpt_response_message(content, ist_number=1):
def gpt_response_message(content: str, name_promt: str):
# Promts = sw.read_settings().sources
# if ist_number == 1:
# contentGPT = Promts[0].prompt.replace('{content}', content)
# else:
# contentGPT = Promts[1].prompt.replace('{content}', content)
if ist_number == 1:
url_ist = "http://epaper.hljnews.cn/hljrb/pc/layout"
else:
url_ist = "https://def.ltn.com.tw/breakingnewslist"
contentGPT = wp.get_promt(url_ist).replace('{content}', content)
contentGPT = wp.get_promt(name_promt).replace('{content}', content)
url = 'http://45.129.78.228:8484' #10.8.0.14:5500
params = {'text': contentGPT}
@@ -242,15 +230,6 @@ def gpt_response_message(content, ist_number=1):
logger.info(f"Привышен лимит запросов {max_retries}")
return ""
# перезапуск сервиса GPT при неудачных попытках запроса
# def restart_service(service_name):
# try:
# subprocess.run(['sudo', 'systemctl', 'restart', service_name], check=True)
# time.sleep(30)
# print(f"Сервис {service_name} успешно перезапущен")
# except subprocess.CalledProcessError:
# print(f"Не удалось перезапустить сервес {service_name}")
# Общие функции проверки ссылок
def check_url(url):
print(url)
@@ -342,7 +321,6 @@ def start_pars_one_istochnik(data_init=""):
for page_number in range(1, 9):
url = f'http://epaper.hljnews.cn/hljrb/pc/layout/{current_year}{current_month}/{current_day}/node_0{page_number}.html'
wp.update_task(task_id, status='in_progress', source_url=url, started_at=datetime.utcnow())
print(f"Сбор href из: {url}")
@@ -358,7 +336,7 @@ def start_pars_one_istochnik(data_init=""):
print(f"Страница {page_number} [{i}/{len(hrefs)}] parsing {link}")
text = extract_text_from_url_one(link)
if len(text) >= 100:
response_text = gpt_response_message(text, ist_number=2)
response_text = gpt_response_message(text, url_ist = "http://epaper.hljnews.cn/hljrb/pc/layout")
print(response_text)
if response_text:
update_bd_and_create_document(response_text=response_text, article_date=f"{current_year}/{current_month}/{current_day}", url=link, parsed_at=str(dt.now()), original_text=text, other=url)
@@ -386,7 +364,7 @@ def start_pars_two_istochnik():
try:
text, time_text = extract_text_from_url(hrefs)
if len(text) >= 100:
response_text = gpt_response_message(text)
response_text = gpt_response_message(text, url_ist = "https://def.ltn.com.tw/breakingnewslist")
print(response_text)
if response_text:
update_bd_and_create_document(response_text=response_text, article_date=time_text, url=hrefs, parsed_at=str(dt.now()), original_text=text, other=url)
@@ -395,6 +373,64 @@ def start_pars_two_istochnik():
wp.update_task(task_id, status='completed', finished_at=datetime.utcnow())
#Функции start любого источника
def start_pars_all_istochnik(url:str, promt:str):
task_id = wp.insert_task(status='queued', source_url=url)
try:
response = requests.get(url)
response.raise_for_status()
except requests.RequestException:
return set()
soup = BeautifulSoup(response.text, 'html.parser')
base_domain = urlparse(url).netloc
# links = set()
for a_tag in soup.find_all('a', href=True):
href = a_tag['href'].strip()
if not href or href.startswith('mailto:') or href.startswith('javascript:'):
continue
# Приведение к абсолютному URL и удаление якорей (#...)
abs_url = urljoin(url, href)
abs_url, _ = urldefrag(abs_url)
parsed = urlparse(abs_url)
# Фильтр: ссылка должна быть на тот же домен
if parsed.netloc != base_domain:
continue
# Фильтрация по ключевым словам (пример для новостных сайтов)
# path_lower = parsed.path.lower()
# if any(keyword in path_lower for keyword in ['/news/', 'article', '2023', '2024', '/blog/', '/post/']):
print(f"Парсинг {abs_url}")
try:
article = Article(abs_url)
article.download()
article.parse()
if len(article.text) > 200 and article.publish_date:
time_text = article.publish_date.strftime("%Y/%m/%d %H:%M:%S")
print("URL:", abs_url)
print("Заголовок:", article.title)
print("Дата публикации:", time_text)
print("Текст статьи:", article.text)
response_text = gpt_response_message(str(article.text), promt)
print(response_text)
if response_text:
update_bd_and_create_document(response_text=response_text, article_date=time_text, url=abs_url, parsed_at=str(dt.now()), original_text=article.text, other=url)
except Exception as e:
print(f"Ошибка при обработке статьи {abs_url}: {e}")
logger.info(f"Ошибка при обработке статьи {abs_url}: {e}")
continue # Продолжаем со следующей статьей
wp.update_task(task_id, status='completed', finished_at=datetime.utcnow())
# start_pars_all_istochnik("https://www.asahi.com", "japan")
# Функции для автоматического запуска
def scheduled_parser_1():
start_pars_one_istochnik()
@@ -406,16 +442,25 @@ class ParserOneRequest(BaseModel):
time: str
@app.post("/parser_1", summary="Запуск процесса парсинга первого источника")
async def process_data(data: ParserOneRequest, background_tasks: BackgroundTasks):
async def process_parser_one_ist(data: ParserOneRequest, background_tasks: BackgroundTasks):
istochnik = data.time.split("-")
background_tasks.add_task(start_pars_one_istochnik, istochnik)
background_tasks.add_task(start_pars_one_istochnik(istochnik))
return {"message": "Процесс парсинга 1 источника запущен"}
@app.post("/parser_2" , summary="Запуск процеса парсинга второго источника")
async def process_data_gpt(background_tasks: BackgroundTasks):
async def process_parser_two_ist(background_tasks: BackgroundTasks):
background_tasks.add_task(start_pars_two_istochnik)
return {"message": "Процесс парсинга 2 источника запущен"}
class Parserall(BaseModel):
url: HttpUrl
promt: str
@app.post("/parser_all" , summary="Запуск процеса парсинга любого источника")
async def process_parser_all_ist(url: Parserall, background_tasks: BackgroundTasks):
background_tasks.add_task(start_pars_all_istochnik(str(url.url), url.promt))
return {"message": "Процесс парсинга любого источника запущен"}
# GET метод для получения
@app.get("/get_tasks_offset", summary="Метод получения задач парсинга")
def get_tasks_offset(limit: int = Query(10, gt=0), offset: int = Query(0, ge=0)):
@@ -536,7 +581,7 @@ async def download_all(dates: DownloadRange, background_tasks: BackgroundTasks):
return response
@app.get("/logs")
@app.get("/logs", summary="Показать логи")
def get_logs():
with open("app.log", "r") as file:
lines = file.readlines()[-10:] # последние 10 строк

View File

@@ -1,6 +1,6 @@
import psycopg2
from psycopg2.extras import RealDictCursor
from pydantic import BaseModel, HttpUrl
from pydantic import BaseModel
# Подключение к БД (укажи свои параметры)
conn = psycopg2.connect(
@@ -90,7 +90,7 @@ def create_table_config_gpt():
print("Таблица config_gpt создана или уже существует")
class Source (BaseModel):
url: HttpUrl
url: str
name: str
promt: str
@@ -105,12 +105,12 @@ def update_promt(data: Source):
ON CONFLICT (url) DO UPDATE SET
name = EXCLUDED.name,
promt = EXCLUDED.promt
""", (str(data.url), data.name, data.promt))
""", (data.url, data.name, data.promt))
conn.commit()
def get_promt(url):
def get_promt(promt_name_url):
with conn.cursor(cursor_factory=RealDictCursor) as cur:
cur.execute("SELECT promt FROM config_gpt WHERE url = %s", (url,))
cur.execute("SELECT promt FROM config_gpt WHERE url = %s", (promt_name_url,))
promt = cur.fetchone()
return promt['promt']
@@ -126,9 +126,10 @@ def get_all_promt():
# Пример использования
# if __name__ == "__main__":
# create_table_config_gpt() # <-- раскомментировать эту строку
# update_promt({
# "url": "http://epaper.hljnews.cn/hljrb/pc/layout",
# "name": "source1",
# "promt": "Задача: Перевод на русский язык и тематическая фильтрация новостных статей из китайской прессы. \n Необходимо переводить текст статьи и определять, относится ли она к КНР по указанным темам: \n 1. Перевод\n Переведи предоставленный китайский текст на русский язык, сохранив оригинальный смысл, стиль и структуру.\n Текст:\n {content}\n -------------------------------------\n 2. Отбирай исключительно новости, прямо относящиеся к Китаю, его безопасности, соседним странам и территориям, влияющим на интересы Китая.\n Если не относится к Китаю — считаем, что статья НЕ подходит, и отдаем пустой JSON:\n {\"text\": \"\", \"pereskas\": \"\", \"title\": \"\", \"topics\": []}\n Если привязка есть — переходи к шагу 3. \n -------------------------------------\n 3. Тематическая классификация\n Определи, относится ли статья к одной или нескольким темам из списка:\n 1) Военные новости — конфликты, учения, мобилизация, закупки вооружений. \n 2) Пограничная деятельность — охрана границы, пограничные учения, строительство или модернизация пограничной инфраструктуры, техника для пограничников. \n 3) Пункты пропуска на границе с РФ — изменения режима работы, строительство, реконструкция, оборудование, логистика. \n 4) Пограничные реки — состояние рек, экология, инфраструктурные проекты, мониторинг. \n 5) Чрезвычайные ситуации — природные и техногенные происшествия, особенно затрагивающие пограничные реки и прилегающие земли. \n 6) Санитарно-эпидемиологическая обстановка — эпидемии, эпизоотии, эпифитотии, угрозы и меры предотвращения. \n 7) Индустриальные проекты (арктическое/антарктическое направление). \n 8) Индустриальные проекты в приграничных районах — заводы, производства, технопарки, новые технологии. \n 9) Инфраструктурные проекты в приграничных районах — дороги, мосты, транспорт, логистика. \n 10) Культура малочисленных народностей (нанайцы, монголы, уйгуры, нанайцы и хэчжэ) — политика, традиции, бытовая жизнь нанайцев, монголов, уйгуров, и хэчжэ (малочисленных народов).\n\n Отметь только те темы, которым статья действительно соответствует.\n\n -------------------------------------\n 4. Формат ответа \n Вернуть строго JSON без пояснений и дополнительных слов:\n {\n \"translation_text\": \"<перевод текста статьи на русский язык (дословный, точный и без сокращений ) >\",\n \"short_text\": \"<пересказ переведённого текста>\",\n \"title\": \"<краткая суть новости (12 предложения)>\",\n \"category\": \"<названий категорий, которым соответствует статья>\"\n }\n Если статья не относится ни к одной теме или не привязана к нужным регионам — вернуть:\n {\"translation_text\": \"\", \"short_text\": \"\", \"title\": \"\", \"category\": \"\"}"
# })
# # create_table_config_gpt() # <-- раскомментировать эту строку
# update_promt({
# "url": "http://korei",
# "name": "Корея",
# "promt": "Задача: Перевод на русский язык и тематическая фильтрация новостных статей из китайской прессы. \n Необходимо переводить текст статьи и определять, относится ли она к КНР по указанным темам: \n 1. Перевод\n Переведи предоставленный китайский текст на русский язык, сохранив оригинальный смысл, стиль и структуру.\n Текст:\n {content}\n -------------------------------------\n 2. Отбирай исключительно новости, прямо относящиеся к Китаю, его безопасности, соседним странам и территориям, влияющим на интересы Китая.\n Если не относится к Китаю — считаем, что статья НЕ подходит, и отдаем пустой JSON:\n {\"text\": \"\", \"pereskas\": \"\", \"title\": \"\", \"topics\": []}\n Если привязка есть — переходи к шагу 3. \n -------------------------------------\n 3. Тематическая классификация\n Определи, относится ли статья к одной или нескольким темам из списка:\n 1) Военные новости — конфликты, учения, мобилизация, закупки вооружений. \n 2) Пограничная деятельность — охрана границы, пограничные учения, строительство или модернизация пограничной инфраструктуры, техника для пограничников. \n 3) Пункты пропуска на границе с РФ — изменения режима работы, строительство, реконструкция, оборудование, логистика. \n 4) Пограничные реки — состояние рек, экология, инфраструктурные проекты, мониторинг. \n 5) Чрезвычайные ситуации — природные и техногенные происшествия, особенно затрагивающие пограничные реки и прилегающие земли. \n 6) Санитарно-эпидемиологическая обстановка — эпидемии, эпизоотии, эпифитотии, угрозы и меры предотвращения. \n 7) Индустриальные проекты (арктическое/антарктическое направление). \n 8) Индустриальные проекты в приграничных районах — заводы, производства, технопарки, новые технологии. \n 9) Инфраструктурные проекты в приграничных районах — дороги, мосты, транспорт, логистика. \n 10) Культура малочисленных народностей (нанайцы, монголы, уйгуры, нанайцы и хэчжэ) — политика, традиции, бытовая жизнь нанайцев, монголов, уйгуров, и хэчжэ (малочисленных народов).\n\n Отметь только те темы, которым статья действительно соответствует.\n\n -------------------------------------\n 4. Формат ответа \n Вернуть строго JSON без пояснений и дополнительных слов:\n {\n \"translation_text\": \"<перевод текста статьи на русский язык (дословный, точный и без сокращений ) >\",\n \"short_text\": \"<пересказ переведённого текста>\",\n \"title\": \"<краткая суть новости (12 предложения)>\",\n \"category\": \"<названий категорий, которым соответствует статья>\"\n }\n Если статья не относится ни к одной теме или не привязана к нужным регионам — вернуть:\n {\"translation_text\": \"\", \"short_text\": \"\", \"title\": \"\", \"category\": \"\"}"
# })
# print(get_promt("japan"))