Skip to content

Commit ef105e7

Browse files
committed
Update manager.py
1 parent fff5f82 commit ef105e7

1 file changed

Lines changed: 40 additions & 1 deletion

File tree

pyaterochka_api/manager.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from camoufox.async_api import AsyncCamoufox
99
from human_requests import HumanBrowser, HumanContext, HumanPage
1010
from human_requests.abstraction import FetchResponse, HttpMethod, Proxy
11+
from human_requests.network_analyzer.anomaly_sniffer import HeaderAnomalySniffer, WaitSource, WaitHeader
1112

1213
from .endpoints.advertising import ClassAdvertising
1314
from .endpoints.catalog import ClassCatalog
@@ -48,6 +49,9 @@ class PyaterochkaAPI:
4849
"""Внутренний контекст сессии браузера"""
4950
page: HumanPage = field(init=False, repr=False)
5051
"""Внутренний страница сессии браузера"""
52+
53+
unstandard_headers: dict[str, str] = {}
54+
"""Список нестандартных заголовков пойманных при инициализации"""
5155

5256
Geolocation: ClassGeolocation = field(init=False)
5357
"""API для работы с геолокацией."""
@@ -83,10 +87,38 @@ async def _warmup(self) -> None:
8387
self.ctx = await self.session.new_context()
8488
self.page = await self.ctx.new_page()
8589

90+
sniffer = HeaderAnomalySniffer(
91+
# доп. вайтлист, если нужно
92+
extra_request_allow=["x-forwarded-for", "x-real-ip"],
93+
extra_response_allow=[],
94+
# нормализуем URL: без фрагмента, но с query
95+
#url_normalizer=lambda u: u.split("#", 1)[0],
96+
include_subresources=True, # или False, если интересны только документы
97+
url_filter=lambda u: u.startswith("https://5d.5ka.ru/")
98+
)
99+
await sniffer.start(self.ctx)
100+
86101
await self.page.goto("https://5ka.ru", wait_until="load")
87102
await self.page.wait_for_selector(selector="next-route-announcer", state="attached")
88103
await self.page.wait_for_load_state('networkidle')
89104

105+
await sniffer.wait(
106+
tasks=[
107+
WaitHeader(
108+
source=WaitSource.REQUEST,
109+
headers=[
110+
"x-app-version",
111+
"x-device-id",
112+
"x-platform"
113+
]
114+
)
115+
],
116+
timeout_ms=self.timeout_ms
117+
)
118+
119+
result = await sniffer.complete()
120+
self.unstandard_headers = result.get("https://5d.5ka.ru")
121+
90122
async def __aexit__(self, *exc):
91123
"""Выход из контекстного менеджера с закрытием сессии."""
92124
await self.close()
@@ -99,12 +131,18 @@ async def delivery_panel_store(self) -> dict:
99131
"""Текущий адрес доставке (при инициализации проставляется автоматически)"""
100132
return json.loads((await self.page.local_storage()).get("DeliveryPanelStore"))
101133

134+
async def device_id(self) -> str:
135+
"""Анонимный (так как в библиотеке нет возможности авторизации) индефекатор пользователя,
136+
который отправляется на сервер почти с каждым запросом (изменить нельзя)."""
137+
return str((await self.page.local_storage()).get("deviceId"))
138+
102139
async def _request(
103140
self,
104141
method: HttpMethod,
105142
url: str,
106143
*,
107144
json_body: Any | None = None,
145+
add_unstandard_headers: bool = True
108146
) -> FetchResponse:
109147
"""Выполнить HTTP-запрос через внутреннюю сессию.
110148
@@ -116,6 +154,7 @@ async def _request(
116154
json_body: Тело запроса в формате JSON (опционально)
117155
"""
118156
# Единая точка входа в чужую библиотеку для удобства
157+
# TODO: пройтись по библиотеке и проверить где add_unstandard_headers должен быть false
119158
print(url)
120159
resp: FetchResponse = await self.page.fetch(
121160
url=url,
@@ -124,7 +163,7 @@ async def _request(
124163
mode="cors",
125164
timeout_ms=self.timeout_ms,
126165
referrer=self.MAIN_SITE_URL,
127-
headers={"Accept": "application/json, text/plain, */*"},
166+
headers={"Accept": "application/json, text/plain, */*"}.update(self.unstandard_headers if add_unstandard_headers else {}),
128167
)
129168

130169
return resp

0 commit comments

Comments
 (0)