Добавил асинхронную версию getStaticPage

This commit is contained in:
Ilia Miheev
2026-05-02 11:20:43 +03:00
parent d1b1fd8e0b
commit 1ae870da3a
3 changed files with 85 additions and 32 deletions
+1
View File
@@ -7,3 +7,4 @@ __pycache__
ideas.md ideas.md
*copy* *copy*
venv/ venv/
.idea/
+82 -31
View File
@@ -6,6 +6,8 @@ from bs4 import BeautifulSoup
from pprint import pprint from pprint import pprint
from time import sleep from time import sleep
from typing import Any, Optional from typing import Any, Optional
import asyncio
import aiohttp
import requests import requests
from os import mkdir, listdir from os import mkdir, listdir
from os.path import exists from os.path import exists
@@ -69,7 +71,6 @@ class Pars:
self.__validation(schema, expected) self.__validation(schema, expected)
# Открываем файл и возвращаем объяект bs4 на его основе
with open(pathToFile, encoding=encoding) as file: with open(pathToFile, encoding=encoding) as file:
src = file.read() src = file.read()
soup = BeautifulSoup(src, parser) soup = BeautifulSoup(src, parser)
@@ -95,7 +96,6 @@ class Pars:
for item in arr: for item in arr:
data = item.text data = item.text
# Удаляем пробелы в начале и конце строки, табуляцию, переносы строки
if needFix: if needFix:
data = data.strip() data = data.strip()
data = data.replace('\t', '') data = data.replace('\t', '')
@@ -151,27 +151,8 @@ class Pars:
writeMethod: метод записи данных в файл. "w" записывает текст, "wb" — байты writeMethod: метод записи данных в файл. "w" записывает текст, "wb" — байты
headers: заголовки запроса к серверу''' headers: заголовки запроса к серверу'''
# Устанавливаем случайный user-agent если пользователь не указал свой
if headers is None: if headers is None:
software_names = [ headers = self.__makeHeaders()
SoftwareName.FIREFOX.value,
SoftwareName.CHROME.value,
SoftwareName.EDGE.value,
SoftwareName.SAFARI.value,
SoftwareName.YANDEX.value,
]
operating_systems = [
OperatingSystem.WINDOWS.value,
OperatingSystem.LINUX.value,
OperatingSystem.IOS.value,
OperatingSystem.MACOS.value,
]
user_agent_rotator = UserAgent(software_names=software_names, operating_systems=operating_systems, limit=10)
user_agent = user_agent_rotator.get_random_user_agent()
headers = {
"Accept": "*/*",
"User-Agent": user_agent
}
schema = { schema = {
@@ -185,11 +166,9 @@ class Pars:
try: try:
# Отправляем запрос
req = requests.get(url, headers=headers) req = requests.get(url, headers=headers)
req.raise_for_status() req.raise_for_status()
# Записываем данные
if writeMethod == 'w': if writeMethod == 'w':
src = req.text src = req.text
with open(pathToSaveFile, 'w', encoding='utf-8') as file: with open(pathToSaveFile, 'w', encoding='utf-8') as file:
@@ -202,7 +181,7 @@ class Pars:
else: else:
raise ValueError(f"Неподдерживаемый метод записи: {writeMethod}") raise ValueError(f"Неподдерживаемый метод записи: {writeMethod}")
return req.status_code # Возвращаем статус ответа от сервера return req.status_code
except requests.exceptions.HTTPError as httpErr: except requests.exceptions.HTTPError as httpErr:
raise RuntimeError(f"HTTP ошибка: {httpErr}") from httpErr raise RuntimeError(f"HTTP ошибка: {httpErr}") from httpErr
@@ -211,14 +190,11 @@ class Pars:
def __scrollAndSave(self, driver: webdriver.Chrome, timeSleep: int, pathToSaveFile: str) -> None: def __scrollAndSave(self, driver: webdriver.Chrome, timeSleep: int, pathToSaveFile: str) -> None:
# Прокручиваем страницу до самого низа '''Прокручиваем страницу до самого низа'''
lastHeight = driver.execute_script("return document.body.scrollHeight") lastHeight = driver.execute_script("return document.body.scrollHeight")
while True: while True:
# Прокручиваем до низа страницы
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
# Ждем загрузки страницы
sleep(timeSleep) sleep(timeSleep)
# Вычисляем новую высоту страницы
newHeight = driver.execute_script("return document.body.scrollHeight") newHeight = driver.execute_script("return document.body.scrollHeight")
if newHeight == lastHeight: if newHeight == lastHeight:
break break
@@ -247,12 +223,10 @@ class Pars:
self.__validation(schema, expected) self.__validation(schema, expected)
# Ставим настройку на запуск баузера в фоновом режиме, если closeWindow = True
options = Options() options = Options()
if closeWindow: if closeWindow:
options.add_argument('--headless') options.add_argument('--headless')
# открываем браузер
with webdriver.Chrome(options=options) as driver: with webdriver.Chrome(options=options) as driver:
driver.get(url) driver.get(url)
self.__scrollAndSave(driver, timeSleep, pathToSaveFile) self.__scrollAndSave(driver, timeSleep, pathToSaveFile)
@@ -280,3 +254,80 @@ class Pars:
driver.get(url) driver.get(url)
a = input('Нажми ENTER когда окажешься на нужной тебе странице') a = input('Нажми ENTER когда окажешься на нужной тебе странице')
self.__scrollAndSave(driver, timeSleep, pathToSaveFile) self.__scrollAndSave(driver, timeSleep, pathToSaveFile)
def __makeHeaders(self) -> dict:
'''Генерирует случайный User-Agent для запроса'''
software_names = [
SoftwareName.FIREFOX.value,
SoftwareName.CHROME.value,
SoftwareName.EDGE.value,
SoftwareName.SAFARI.value,
SoftwareName.YANDEX.value,
]
operating_systems = [
OperatingSystem.WINDOWS.value,
OperatingSystem.LINUX.value,
OperatingSystem.IOS.value,
OperatingSystem.MACOS.value,
]
user_agent_rotator = UserAgent(software_names=software_names, operating_systems=operating_systems, limit=10)
return {
'Accept': '*/*',
'User-Agent': user_agent_rotator.get_random_user_agent()
}
async def getStaticPageAsync(
self,
pathToSaveFile: str,
url: str,
writeMethod: str = 'w',
headers: Optional[dict] = None,
session: Optional[aiohttp.ClientSession] = None,
) -> int:
'''Асинхронно сохраняет статическую страницу и возвращает статус ответа
pathToSaveFile: путь, куда сохранится полученный файл
url: ссылка на данные
writeMethod: метод записи. "w" — текст, "wb" — байты (для картинок)
headers: заголовки запроса. Если None — подставится случайный User-Agent
session: aiohttp.ClientSession для переиспользования соединений'''
if headers is None:
headers = self.__makeHeaders()
schema = {
'pathToSaveFile': {'type': 'string'},
'url': {'type': 'string'},
'writeMethod': {'type': 'string', 'allowed': ['w', 'wb']},
'headers': {'type': 'dict'},
}
self.__validation(schema, {'pathToSaveFile': pathToSaveFile, 'url': url, 'writeMethod': writeMethod, 'headers': headers})
close_session = session is None
if close_session:
session = aiohttp.ClientSession()
try:
async with session.get(url, headers=headers) as response:
response.raise_for_status()
if writeMethod == 'w':
text = await response.text(encoding='utf-8')
with open(pathToSaveFile, 'w', encoding='utf-8') as file:
file.write(text)
elif writeMethod == 'wb':
content = await response.read()
with open(pathToSaveFile, 'wb') as file:
file.write(content)
return response.status
except aiohttp.ClientResponseError as httpErr:
raise RuntimeError(f'HTTP ошибка: {httpErr}') from httpErr
except Exception as e:
raise RuntimeError(e) from e
finally:
if close_session:
await session.close()
+1
View File
@@ -13,6 +13,7 @@ setup(
url='https://iliamiheev.github.io/ipars-doc/#/./home', url='https://iliamiheev.github.io/ipars-doc/#/./home',
install_requires=[ install_requires=[
'requests', 'requests',
'aiohttp',
'selenium', 'selenium',
'lxml', 'lxml',
'bs4', 'bs4',