93 lines
3.8 KiB
Python
93 lines
3.8 KiB
Python
#!/usr/bin/env python3
|
||
# ikea_leaf_categories.py • собирает «листовые» категории каталога
|
||
|
||
import json, requests, pathlib, pandas as pd, time, sys
|
||
|
||
# ── настройки ────────────────────────────────────────────────────
|
||
BASE_DIR = pathlib.Path(__file__).resolve().parent
|
||
|
||
|
||
LOCALE_PATH = "/pl/pl/" # ← поменяйте на /de/de/, /fr/fr/ … при нужде
|
||
JSON_URL = (f"https://www.ikea.com{LOCALE_PATH}"
|
||
"meta-data/navigation/catalog-products-slim.json")
|
||
HEADERS = {"User-Agent": "Mozilla/5.0", "Accept": "application/json"}
|
||
|
||
TXT_OUT = BASE_DIR / "leaf_categories.txt"
|
||
XLSX_OUT = BASE_DIR / "leaf_categories.xlsx"
|
||
|
||
EXCLUDE_NAMES = {"Wyprzedaż"} # можно расширять
|
||
EXCLUDE_URL_SNIPPETS = {"/last-chance/"} # подстроки url, которые нужно отсечь
|
||
|
||
# ── загрузка JSON ────────────────────────────────────────────────
|
||
def fetch_json():
|
||
r = requests.get(JSON_URL, headers=HEADERS, timeout=10)
|
||
r.raise_for_status()
|
||
return r.json()
|
||
|
||
# ── рекурсивный обход ────────────────────────────────────────────
|
||
def walk(node: dict, acc: list):
|
||
# ── NEW: фильтр «Wyprzedaż / last-chance» ─────────────────────
|
||
nm = node.get("name", "")
|
||
url = node.get("url", "")
|
||
if nm in EXCLUDE_NAMES or any(sn in url for sn in EXCLUDE_URL_SNIPPETS):
|
||
return # просто не лезем в эту ветку
|
||
# ─────────────────────────────────────────────────────────────
|
||
|
||
subs = node.get("subs") or []
|
||
if not subs: # лист
|
||
acc.append({
|
||
"id": node.get("id"),
|
||
"name": nm,
|
||
"url": "https://www.ikea.com" + url
|
||
})
|
||
else:
|
||
for s in subs:
|
||
walk(s, acc)
|
||
|
||
|
||
def collect_leaves(tree):
|
||
"""
|
||
tree – либо dict с ключом 'subs', либо list из таких dict-ов.
|
||
Возвращает список «листовых» категорий.
|
||
"""
|
||
leaves = []
|
||
|
||
# если пришёл список – обходим каждый элемент
|
||
if isinstance(tree, list):
|
||
for node in tree:
|
||
walk(node, leaves)
|
||
return leaves
|
||
|
||
# если dict – работаем по старой схеме
|
||
if isinstance(tree, dict):
|
||
for top in tree.get("subs", []):
|
||
walk(top, leaves)
|
||
return leaves
|
||
|
||
|
||
# ── main ─────────────────────────────────────────────────────────
|
||
def main():
|
||
try:
|
||
data = fetch_json()
|
||
except Exception as e:
|
||
sys.exit(f"❌ Не удалось скачать JSON: {e}")
|
||
|
||
leaves = collect_leaves(data)
|
||
print("Найдено категорий-листов:", len(leaves))
|
||
|
||
# txt
|
||
with open(TXT_OUT, "w", encoding="utf-8") as f:
|
||
f.write("\n".join(cat["url"] for cat in leaves))
|
||
print("Ссылки сохранены:", TXT_OUT)
|
||
|
||
# xlsx (для удобства)
|
||
try:
|
||
pd.DataFrame(leaves, columns=["id", "name", "url"]).to_excel(
|
||
XLSX_OUT, index=False)
|
||
print("Таблица сохранена:", XLSX_OUT)
|
||
except Exception as e:
|
||
print("⚠️ Excel не записан:", e)
|
||
|
||
if __name__ == "__main__":
|
||
main()
|