Compare commits

..
55 Commits
Author SHA1 Message Date
qananasikq cccf6b3916 initial openlane project 2026-04-21 23:01:33 +03:00
qananasikq 55203d33ea chore: cleanup ad-hoc debug scripts + sitemap test downloads 2026-04-18 16:35:07 +03:00
qananasikq 5999c2e42d checkpoint: pipeline + 27k/h baseline before sitemap discovery 2026-04-18 16:34:09 +03:00
qananasikq a8c5f8aa41 Replace page-level checkpoint with segment-level resume 2026-04-17 17:51:23 +03:00
qananasikq 05d1ffb5ac Stabilize worker sync flow 2026-04-17 17:30:28 +03:00
qananasikq 3c3aea8eb3 tune vps config and update tests 2026-04-15 21:58:10 +03:00
qananasikq 37d01c4ba1 clean mapper comments 2026-04-15 21:58:03 +03:00
qananasikq 6165c65159 add segmented listing sync 2026-04-15 21:57:40 +03:00
qananasikq acbb045b6e Add checkpoint logic and tests 2026-04-15 11:10:32 +03:00
qananasikq d9111be2d2 fix worker lock 2026-04-14 19:32:45 +03:00
qananasikq cac68bda4c add full scan mode 2026-04-14 19:32:34 +03:00
qananasikq 0add3913eb fix listing parsing 2026-04-14 19:31:57 +03:00
qananasikq 6a334d3c64 tune docker config 2026-04-14 14:03:26 +03:00
qananasikq d51216ddb7 improve listing sync 2026-04-14 14:03:16 +03:00
qananasikq 9337344182 stabilize worker 2026-04-14 14:03:08 +03:00
qananasikq c729f971e3 fix worker recovery and docker logs 2026-04-13 20:49:25 +03:00
qananasikq eaafbd5816 Удалить .env 2026-04-13 19:46:28 +02:00
qananasikq a4c93a1df1 fix docker scraping
improve batch sync

add postgres upsert

fix sync locking

improve listing sync

speed up scraper

clean up project

prepare for github

update docker setup
2026-04-13 16:35:08 +03:00
qananasikq b9557922ed fix parser_id format: car- + 22 alphanum chars, origin_id: iaai:{lot} 2026-04-10 20:31:48 +03:00
qananasikq 85b4ff8502 remove xvfb, use headless with cookie auth 2026-04-10 20:01:53 +03:00
qananasikq 6134b10fd0 add iaai auto-login with session persistence 2026-04-10 19:59:03 +03:00
qananasikq 05b83b5518 add cookie session persistence 2026-04-10 19:55:38 +03:00
qananasikq b1aeb966ac add sqlite check command to readme 2026-04-10 19:51:38 +03:00
qananasikq 1acfafe665 remove github workflow 2026-04-10 19:49:24 +03:00
qananasikq 2cbefbde93 update local run setup 2026-04-10 19:47:20 +03:00
qananasikq db2fa5ec17 add antibot unit tests 2026-04-10 15:18:57 +03:00
qananasikq 18dab6d48d docker non-root and healthcheck fix 2026-04-10 15:18:57 +03:00
qananasikq 3870cf4d94 add task status endpoint 2026-04-10 15:18:57 +03:00
qananasikq 62aafae793 add Redis lock for sync_listing 2026-04-10 15:18:57 +03:00
qananasikq acf30fcc20 add antibot guard and retry 2026-04-10 15:18:57 +03:00
qananasikq 7b1501008e fix limit after only_new filter 2026-04-10 15:18:57 +03:00
qananasikq 6d1702faae Обновить README.md 2026-04-10 10:08:33 +02:00
qananasikq 2931eee0a7 fix readme 2026-04-09 20:35:41 +03:00
qananasikq f6d7c8ea60 cleanup and fix runtime bugs 2026-04-09 20:35:25 +03:00
qananasikq eb9fb48ea0 improve docker compose setup 2026-04-09 20:34:34 +03:00
qananasikq 042ffdcfbb move deps to pyproject 2026-04-09 20:34:20 +03:00
qananasikq 437aedad45 update celery schedule and readme 2026-04-08 23:46:13 +03:00
qananasikq 9f703696d8 fix readme 2026-04-08 23:43:21 +03:00
qananasikq 3992067a94 rewrite readme 2026-04-08 22:55:00 +03:00
qananasikq e5700f9623 postgres redis docker compose setup 2026-04-08 22:54:51 +03:00
qananasikq f4b9d20191 add fastapi rest api and celery workers 2026-04-08 22:54:33 +03:00
qananasikq 6e97991c68 cleanup and fix runtime bugs 2026-04-08 22:54:16 +03:00
qananasikq 90bd4756b3 update readme and env 2026-04-08 18:33:56 +03:00
qananasikq 64b7c760d9 update tests for sync 2026-04-08 18:32:45 +03:00
qananasikq f161071e07 harden price normalization 2026-04-08 18:30:39 +03:00
qananasikq 3b218534ec sync only new cars 2026-04-08 18:30:02 +03:00
qananasikq 54fea100dc add docker proxy bridge 2026-04-08 18:29:06 +03:00
qananasikq 447a88feed persist raw attributes and tighten sync assertions 2026-04-08 14:30:57 +03:00
qananasikq b2d3902bcc stabilize daemon sync and docker startup 2026-04-08 14:30:44 +03:00
qananasikq d1844ba625 document docker runtime and tune env defaults 2026-04-08 14:30:27 +03:00
qananasikq ff2a1c7ac8 Обновить README.md 2026-04-08 12:38:15 +02:00
qananasikq 0010abdf08 fix parsing db and tests 2026-04-08 13:31:02 +03:00
qananasikq f96e5ca5f8 improve scraper runtime 2026-04-08 13:30:45 +03:00
qananasikq 21bdf17f35 update readme and env 2026-04-08 13:30:17 +03:00
qananasikq 78b52b265f IAAI scraper 2026-04-07 23:51:41 +03:00
3 changed files with 5 additions and 49 deletions
-1
View File
@@ -2,7 +2,6 @@
OPENLANE_HEADLESS=true OPENLANE_HEADLESS=true
OPENLANE_LOG_LEVEL=INFO OPENLANE_LOG_LEVEL=INFO
OPENLANE_TIMEOUT_MS=45000 OPENLANE_TIMEOUT_MS=45000
OPENLANE_RUNTIME_CONFIG_FILE=runtime_config.json
# --- OpenLane Auth & API --- # --- OpenLane Auth & API ---
OPENLANE_USERNAME= OPENLANE_USERNAME=
+1 -1
View File
@@ -181,7 +181,7 @@ class Settings:
log_level: str = _env_str("OPENLANE_LOG_LEVEL", "INFO") log_level: str = _env_str("OPENLANE_LOG_LEVEL", "INFO")
log_file: str | None = _env_optional_str("OPENLANE_LOG_FILE") log_file: str | None = _env_optional_str("OPENLANE_LOG_FILE")
enable_trace_id_logs: bool = _env_bool("OPENLANE_ENABLE_TRACE_ID_LOGS", True) enable_trace_id_logs: bool = _env_bool("OPENLANE_ENABLE_TRACE_ID_LOGS", True)
runtime_config_file: str | None = _env_path_str("OPENLANE_RUNTIME_CONFIG_FILE") or "runtime_config.json" runtime_config_file: str | None = _env_path_str("OPENLANE_RUNTIME_CONFIG_FILE")
fingerprint: FingerprintConfig = field(default_factory=FingerprintConfig) fingerprint: FingerprintConfig = field(default_factory=FingerprintConfig)
openlane: OpenLaneConfig = field(default_factory=OpenLaneConfig) openlane: OpenLaneConfig = field(default_factory=OpenLaneConfig)
database: DatabaseConfig = field(default_factory=DatabaseConfig) database: DatabaseConfig = field(default_factory=DatabaseConfig)
+4 -47
View File
@@ -321,9 +321,7 @@ class OpenLaneAuthenticator:
"https://app.openlane.com/api/_next/time", "https://app.openlane.com/api/_next/time",
wait_until="domcontentloaded", wait_until="domcontentloaded",
) )
if self._is_api_authenticated(page): return page
return page
logger.warning("Access token cookie exists but API returned unauthorized, will re-authenticate")
# Пробуем прямой refresh access_token без навигации. # Пробуем прямой refresh access_token без навигации.
refresh_token = self._extract_refresh_token_from_cookies(context) or self.config.refresh_token refresh_token = self._extract_refresh_token_from_cookies(context) or self.config.refresh_token
@@ -339,10 +337,8 @@ class OpenLaneAuthenticator:
"https://app.openlane.com/api/_next/time", "https://app.openlane.com/api/_next/time",
wait_until="domcontentloaded", wait_until="domcontentloaded",
) )
if self._is_api_authenticated(page): logger.info("OpenLane session restored via direct Okta refresh")
logger.info("OpenLane session restored via direct Okta refresh") return page
return page
logger.warning("Direct Okta refresh produced token but API still unauthorized")
logger.warning("Direct refresh failed, trying sign_in fallback") logger.warning("Direct refresh failed, trying sign_in fallback")
# Если refresh_token был только в env, добавляем cookie вручную. # Если refresh_token был только в env, добавляем cookie вручную.
@@ -359,9 +355,7 @@ class OpenLaneAuthenticator:
self._wait_for_authenticated_session(page) self._wait_for_authenticated_session(page)
self._persist_storage_state(context) self._persist_storage_state(context)
self._maybe_rotate_token(context) self._maybe_rotate_token(context)
if self._is_api_authenticated(page): return page
return page
logger.warning("sign_in fallback completed but API is still unauthorized")
except OpenLaneAuthError: except OpenLaneAuthError:
logger.warning("SPA refresh_token exchange failed") logger.warning("SPA refresh_token exchange failed")
page.close() page.close()
@@ -376,43 +370,6 @@ class OpenLaneAuthenticator:
" 2. Set OPENLANE_USERNAME and OPENLANE_PASSWORD in .env" " 2. Set OPENLANE_USERNAME and OPENLANE_PASSWORD in .env"
) )
def _is_api_authenticated(self, page: Page) -> bool:
"""Проверяет, что сессия реально авторизована для OpenLane API.
Нужна для случаев, когда access_token cookie есть (и даже не истёк),
но сервер уже считает сессию невалидной.
"""
try:
status = page.evaluate(
"""async () => {
try {
const resp = await fetch('https://app.openlane.com/api/v4/search?page=1&per_page=1&source_tab=marketplace&sale_types=marketplace', {
method: 'GET',
credentials: 'include',
headers: {
'Accept': 'application/json, application/vnd.backlotcars.v3'
}
});
return resp.status;
} catch (e) {
return 0;
}
}"""
)
except Exception:
logger.warning("Failed to validate OpenLane API auth state", exc_info=True)
return False
try:
code = int(status)
except (TypeError, ValueError):
return False
# 401/403 — точно неавторизованы.
if code in (401, 403, 0):
return False
return True
def login(self, context: BrowserContext) -> Page: def login(self, context: BrowserContext) -> Page:
self.validate_credentials() self.validate_credentials()
page = context.new_page() page = context.new_page()