#!/usr/bin/env python3 # ikea_collect_product_links.py – POST-вариант, полный лог import json, re, sys, time, pathlib, requests, pandas as pd, datetime from urllib.parse import urljoin # ── настройки ───────────────────────────────────────────────────── BASE_DIR = pathlib.Path(__file__).resolve().parent CAT_FILE = BASE_DIR / "leaf_categories.txt" OUT_TXT = BASE_DIR / "product_links.txt" OUT_XLSX = BASE_DIR / "product_links.xlsx" LOG_FILE = BASE_DIR / "log_all_CatProd.txt" LOCALE_PREFIX = "/pl/pl/" # поменяйте, если другая страна BASE_DOMAIN = "https://www.ikea.com" SEARCH_URL = "https://sik.search.blue.cdtapps.com/pl/pl/search?c=listaf&v=20250507" HEADERS = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36", "Content-Type": "application/json", "session-id":"99c25720-5826-4c57-87b2-d6e29397b584", "Accept":"*/*", } SIZE = 24 # столько же использует фронт PAUSE = 0.6 # задержка между offset-запросами # ────────────────────────────────────────────────────────────────── def log(text: str): ts = datetime.datetime.now().strftime("[%Y-%m-%d %H:%M:%S] ") with LOG_FILE.open("a", encoding="utf-8") as f: f.write(ts + text + "\n") LOG_FILE.write_text("", encoding="utf-8") # обнуляем файл (без append) def fetch_chunk(category_id: str, offset: int) -> dict: payload = { "searchParameters": {"input": category_id, "type": "CATEGORY"}, "zip": "05-090", "store": "188", "isUserLoggedIn": False, "optimizely": { "listing_3547_filter_hnf_sticky": None, "listing_3332_collapsed_filter_bar": None, "discount_percentage": None, "listing_3790_simplify_rating_stars": None }, "optimizelyAttributes": { "market": "pl", "device": "desktop", "deviceVendor": "Apple", "deviceType": "desktop", "isLoggedIn": False, "environment": "prod", "browser": "Chrome", "os": "Mac OS", "language": "pl", "feedMarket": "pl-PL", "locale": "pl-PL", "customerType": "guest", "isEntranceVisit": False, "pip_to_pip_src": "" }, "components": [ { "component": "PRIMARY_AREA", "columns": 4, "types": { "main": "PRODUCT", "breakouts": ["PLANNER", "LOGIN_REMINDER", "MATTRESS_WARRANTY"] }, "filterConfig": {"max-num-filters": 6}, "window": {"size": 1000, "offset": 0}, "forceFilterCalculation": True } ] } log(f"POST offset={offset} payload: {json.dumps(payload, ensure_ascii=False)}") r = requests.post(SEARCH_URL, headers=HEADERS, data=json.dumps(payload), timeout=15) log(f"→ status {r.status_code}") try: data = r.json() log("response: " + json.dumps(data, ensure_ascii=False)) except ValueError: log("response: ") data = {} r.raise_for_status() return data def collect_pipurls(node, out:set): """Рекурсивно находит все значения ключа 'pipUrl'.""" if isinstance(node, dict): for k, v in node.items(): if k == "pipUrl" and isinstance(v, str): out.add(urljoin(BASE_DOMAIN, v)) else: collect_pipurls(v, out) elif isinstance(node, list): for item in node: collect_pipurls(item, out) def product_links_from_category(cat_url: str) -> list[str]: m = re.search(r'-([0-9]+)/?$', cat_url.rstrip("/")) if not m: print(" ⚠️ categoryId not found") return [] cid = m.group(1) offset = 0 links = [] while True: data = fetch_chunk(cid, offset) # ← ваша существующая функция pip_set = set() collect_pipurls(data, pip_set) # ★ собираем все pipUrl links.extend(pip_set) # без deduplicate по просьбе print(f" +{len(pip_set)} pipUrl") # если вернулось меньше стандартного окна — выходим if len(data.get("products", [])) < SIZE: break offset += SIZE #time.sleep(PAUSE_SEC) return links def main(): LOG_FILE.write_text("", encoding="utf-8") # очищаем лог if not CAT_FILE.exists(): sys.exit("leaf_categories.txt не найден") categories = [l.strip() for l in CAT_FILE.read_text(encoding="utf-8").splitlines() if l.strip()] all_links = [] for idx, cat in enumerate(categories, 1): print(f"[{idx}/{len(categories)}] {cat}") try: links = product_links_from_category(cat) print(f" Σ {len(links)} ссылок") all_links.extend(links) # дубликаты сохраняем except Exception as e: print(" ⚠️", e) log(f"ERROR on {cat}: {e}") OUT_TXT.write_text("\n".join(all_links), encoding="utf-8") print("🔗 product_links.txt создан") try: pd.DataFrame(all_links, columns=["url"]).to_excel(OUT_XLSX, index=False) print("📊 product_links.xlsx создан") except Exception as e: print("⚠️ Excel не записан:", e) if __name__ == "__main__": main()