Пробую развернуть контрейнер
parent
7e42f59215
commit
b3c7d9e9e9
|
|
@ -0,0 +1,27 @@
|
||||||
|
FROM python:3.11-slim-bookworm
|
||||||
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
RUN apt-get update
|
||||||
|
RUN apt-get -y install wget libaio1 unzip alien
|
||||||
|
|
||||||
|
RUN cd /home && wget -q https://download.oracle.com/otn_software/linux/instantclient/2112000/oracle-instantclient-basic-21.12.0.0.0-1.el8.x86_64.rpm &&\
|
||||||
|
alien -i --scripts /home/oracle-instantclient-basic-21.12.0.0.0-1.el8.x86_64.rpm &&\
|
||||||
|
rm /home/oracle-instantclient-basic-21.12.0.0.0-1.el8.x86_64.rpm &&\
|
||||||
|
export LD_LIBRARY_PATH=/usr/lib/oracle/21.12/client64/lib/${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
|
||||||
|
|
||||||
|
RUN cd /home/ && wget -q https://download.oracle.com/otn_software/linux/instantclient/2112000/oracle-instantclient-sqlplus-21.12.0.0.0-1.el8.x86_64.rpm &&\
|
||||||
|
alien -i --scripts /home/oracle-instantclient-sqlplus-21.12.0.0.0-1.el8.x86_64.rpm &&\
|
||||||
|
rm /home/oracle-instantclient-sqlplus-21.12.0.0.0-1.el8.x86_64.rpm
|
||||||
|
|
||||||
|
RUN cd /home/ && wget -q https://download.oracle.com/otn_software/linux/instantclient/2112000/oracle-instantclient-devel-21.12.0.0.0-1.el8.x86_64.rpm && \
|
||||||
|
alien -i --scripts /home/oracle-instantclient-devel-21.12.0.0.0-1.el8.x86_64.rpm &&\
|
||||||
|
rm /home/oracle-instantclient-devel-21.12.0.0.0-1.el8.x86_64.rpm &&\
|
||||||
|
ldconfig
|
||||||
|
|
||||||
|
CMD ["sqlplus", "-v"]
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
WORKDIR /code/app
|
||||||
|
COPY ./requirements.txt /code/requirements.txt
|
||||||
|
RUN python3.11 -m pip install --upgrade pip
|
||||||
|
RUN echo Y | python3.11 -m pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||||
5
main.py
5
main.py
|
|
@ -1,5 +0,0 @@
|
||||||
import working_database
|
|
||||||
import parse_saby
|
|
||||||
|
|
||||||
working_database.connect_hvac()
|
|
||||||
parse_saby.process_reports_parse()
|
|
||||||
202
parse_saby.py
202
parse_saby.py
|
|
@ -1,202 +0,0 @@
|
||||||
import requests
|
|
||||||
from bs4 import BeautifulSoup
|
|
||||||
import re
|
|
||||||
|
|
||||||
def parse_html(url: str):
|
|
||||||
"""
|
|
||||||
Фунция принимает строку URL, выполняет запрос.
|
|
||||||
Создает и возращает объект BeautifulSoup(HTML).
|
|
||||||
"""
|
|
||||||
# Запрос страницы
|
|
||||||
response = requests.get(url)
|
|
||||||
# Проверка статуса в ответе на запрос
|
|
||||||
if not(200 <= response.status_code <= 299):
|
|
||||||
# Повторный запрос
|
|
||||||
response = requests.get(url)
|
|
||||||
print("Ошибка при запросе: ", response.status_code)
|
|
||||||
return response.status_code
|
|
||||||
# Создание обьекта BeautifulSoup(HTML страница)
|
|
||||||
soup = BeautifulSoup(response.text, 'html.parser')
|
|
||||||
return soup
|
|
||||||
|
|
||||||
def parse_date_report(url: str):
|
|
||||||
"""
|
|
||||||
Функия ожидает list из URL ввида:
|
|
||||||
url = https://formats.saby.ru/report/fns/128513
|
|
||||||
Заходит по URL, запоминает дату.
|
|
||||||
Возвращает две строки ввида:
|
|
||||||
'date = 01.07.22'
|
|
||||||
'id_date = 5.01'
|
|
||||||
"""
|
|
||||||
# HTML report
|
|
||||||
soup = parse_html(url)
|
|
||||||
# Если не удалось отправить запрос, ворзвращаем URL и код ошибки.
|
|
||||||
# Они будут занесы в файл.
|
|
||||||
if soup == int:
|
|
||||||
return url, soup
|
|
||||||
# Поиск в HTML строки ввида: 'Действующий формат (с 10.01.23) 5.01'
|
|
||||||
div_element = soup.find('div', class_='controls-Dropdown__text')
|
|
||||||
# Извлекаем текст из элемента
|
|
||||||
text = div_element.get_text()
|
|
||||||
# Парсим нужные данные
|
|
||||||
# Уловия ловит: text = 'Действующий формат 02-04-2025 _2025_001'
|
|
||||||
if '_' in text:
|
|
||||||
regex = r'\w+\s\w+\s(\S+) (\S+)'
|
|
||||||
date, id_date = re.search(regex, text).groups()
|
|
||||||
return date, id_date
|
|
||||||
# Все остальные
|
|
||||||
else:
|
|
||||||
regex = r'(\d{2}\D\d{2}\D\d{2})(?:(?:.+)?\))? #?(\d+(?:\D\d+)?)'
|
|
||||||
date, id_date = re.search(regex, text).groups()
|
|
||||||
return date, id_date
|
|
||||||
|
|
||||||
def parse_reports(soup=BeautifulSoup, # HTML объект
|
|
||||||
report_title = str, # строка ввида: 'report/fns'
|
|
||||||
url_formats = str, # Строка ввида: 'https://formats.saby.ru'
|
|
||||||
name_title = str): # имя тайтла: 'fns'
|
|
||||||
"""
|
|
||||||
Достаются все необходимые данные, возвращаются в ввиде словаря:
|
|
||||||
{106538: ('fns', 'НД по косвенным налогам', '01.08.23', '5.04')}
|
|
||||||
"""
|
|
||||||
|
|
||||||
result_dict_data = {}
|
|
||||||
# Перебарает все URL, ищутся по тегу 'a'
|
|
||||||
for link in soup.find_all('a'):
|
|
||||||
# Ищет по тегу: href
|
|
||||||
href = link.get('href')
|
|
||||||
if f'{report_title}/' in href:
|
|
||||||
# id report
|
|
||||||
id = href.rstrip('/').split('/')[-1]
|
|
||||||
#URL report
|
|
||||||
url_report = f'{url_formats}{href}'
|
|
||||||
link = soup.find('a', href=href)
|
|
||||||
# Name report
|
|
||||||
span = link.find('span', class_="ProxySbisRu__registry-BrowserItem_typeName")
|
|
||||||
# Данные получены из url после парсинга
|
|
||||||
date, id_date = parse_date_report(url_report)
|
|
||||||
# Добавление всех данных в итоговый словарь
|
|
||||||
result_dict_data.update({id: (name_title, span.text, date, id_date)})
|
|
||||||
|
|
||||||
return result_dict_data
|
|
||||||
|
|
||||||
def write_report_data(filename, dict_name = dict, name_title = str):
|
|
||||||
"""
|
|
||||||
Сохраняем запись, каждая запись с новой строки:
|
|
||||||
'ключ: значение'
|
|
||||||
'ключ: значение'
|
|
||||||
...
|
|
||||||
"""
|
|
||||||
#Блок для красивого офорлмения файла
|
|
||||||
|
|
||||||
# Вычисляем количество подчёркиваний слева и справа
|
|
||||||
def center_text():
|
|
||||||
"""
|
|
||||||
Функия парсит сколько нужно подчеркивания,
|
|
||||||
что бы центролизовать текст в строке с этими подчеркиваниями
|
|
||||||
Возвращает две строки одна для начало блока записей тайтал, вторая конца блока.
|
|
||||||
"""
|
|
||||||
start_str = f'START_{name_title}'
|
|
||||||
end_str = f'END_{name_title}'
|
|
||||||
dash = 100
|
|
||||||
list_result = []
|
|
||||||
# сначал вернеться dash_start, потом end_start.
|
|
||||||
for text in start_str, end_str:
|
|
||||||
remaining_space = dash - len(text)
|
|
||||||
left = remaining_space // 2
|
|
||||||
right = remaining_space - left # Чтобы учесть нечётную разницу
|
|
||||||
list_result.append('_' * left + text + '_' * right)
|
|
||||||
return list_result[:2]
|
|
||||||
dash_start, dash_end = center_text()
|
|
||||||
|
|
||||||
#Конец блока
|
|
||||||
#Запись в файл с красивым офрмление в виде нижнего подчеркивания
|
|
||||||
with open(filename, 'a', encoding='utf-8') as f:
|
|
||||||
f.write(f'\n{dash_start}\n')
|
|
||||||
for key, value in dict_name.items():
|
|
||||||
str_k_v = f'{key}: {value}\n'
|
|
||||||
f.write(str_k_v)
|
|
||||||
f.write(f'{dash_end}\n')
|
|
||||||
|
|
||||||
def search_title():
|
|
||||||
"""
|
|
||||||
Функция ищет все тайтлы на странице formats.saby.ru/report.
|
|
||||||
|
|
||||||
Возвращает:
|
|
||||||
Список URL-путей, например: ['/report/fns', '/report/example', ...]
|
|
||||||
|
|
||||||
Исключения:
|
|
||||||
ValueError: Если запрос к странице завершился с ошибкой (неверный статус).
|
|
||||||
"""
|
|
||||||
# url по которому в котором будет происходить поиск,
|
|
||||||
url_format_report = 'https://formats.saby.ru/report'
|
|
||||||
|
|
||||||
# Получаем HTML-cтраницу
|
|
||||||
html = parse_html(url_format_report)
|
|
||||||
|
|
||||||
# Проверяем, что html не является кодом ошибки (int)
|
|
||||||
if isinstance(html, int):
|
|
||||||
error_message = f'Ошибка при запросе {url_format_report}: {html}'
|
|
||||||
raise Exception(error_message)
|
|
||||||
|
|
||||||
# < в который будут заноситься тайтлы
|
|
||||||
report_urls = set()
|
|
||||||
|
|
||||||
# Ищем все ссылки <a> с href, соответствующие шаблону /report/{title}
|
|
||||||
for link in html.find_all('a', href=True):
|
|
||||||
# Ищем по тегу: href
|
|
||||||
href = link['href']
|
|
||||||
# Проверям что href содержит: /report/{title}
|
|
||||||
if re.search(r'\/report\/(\w+)$', href):
|
|
||||||
report_urls .add(href)
|
|
||||||
return report_urls
|
|
||||||
|
|
||||||
# Имя файла в который будет записан результат кода
|
|
||||||
filename_save = 'ReportData.txt'
|
|
||||||
def clear_report_data_file():
|
|
||||||
"""
|
|
||||||
Удаляем старые записи, что бы записать актульные
|
|
||||||
"""
|
|
||||||
with open(filename_save, 'w') as f:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def process_reports_parse():
|
|
||||||
"""
|
|
||||||
Функция пробегается по каждому тайтлу.
|
|
||||||
Для всех записей(reports) выполняется запрос HTML страницы,
|
|
||||||
которая парситься в объект BeautifulSoup(HTML страница).
|
|
||||||
Из это обьекта достаются не обходимые данные,
|
|
||||||
которые записываются в текстовый файл.
|
|
||||||
"""
|
|
||||||
# Очищаем файл перед записью
|
|
||||||
clear_report_data_file()
|
|
||||||
|
|
||||||
# Лист имеет вид: ['/report/fns', '/report/sfr'...]
|
|
||||||
list_title = search_title()
|
|
||||||
|
|
||||||
for report_title in list_title:
|
|
||||||
try:
|
|
||||||
# используется для создание полных URL
|
|
||||||
url_formats = 'https://formats.saby.ru'
|
|
||||||
# Получаем имя тайтла через парсинг
|
|
||||||
name_title = report_title.rstrip('/').split('/')[-1]
|
|
||||||
|
|
||||||
# URL на конкретный title
|
|
||||||
url_title = f'{url_formats}{report_title}'
|
|
||||||
|
|
||||||
# Объект HTML, конкретного title
|
|
||||||
soup = parse_html(url_title)
|
|
||||||
|
|
||||||
# Словарь с нужными данными
|
|
||||||
dict_result = parse_reports(soup, report_title, url_formats, name_title)
|
|
||||||
|
|
||||||
# Запись данных в текстовый файл
|
|
||||||
write_report_data(filename_save, dict_result, name_title)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Ошибка при обработке отчета {report_title}: {str(e)}")
|
|
||||||
continue
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
process_reports_parse()
|
|
||||||
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue