Загрузка данных


import re
from pathlib import Path
from urllib.parse import urlparse, parse_qs, unquote, urlencode, urlunparse
from playwright.sync_api import sync_playwright

FOLDER_URL = "https://disk.yandex.ru/client/disk/%D1%81%D0%B2%D0%B0%D0%B4%D1%8C%D0%B1%D0%B0%208.09.18%20(%D1%80%D0%BE%D0%B4%D0%B8%D1%82%D0%B5%D0%BB%D1%8C%D1%81%D0%BA%D0%B0%D1%8F%20%D0%BF%D0%B0%D0%BF%D0%BA%D0%B0)"   # ссылка на папку
OUT_DIR = Path("photos_best_0_1")
PROFILE_DIR = "browser_profile"
WAIT_SEC = 8                 # сколько ждать смены фото после стрелки
MAX_FAILS = 4                # сколько пропусков подряд считать концом папки
TRY_BIGGER = True            # пробовать запросить превью покрупнее
OUT_DIR.mkdir(exist_ok=True)

FIND_IMG = """
() => {
  let best = null, bestArea = 0;
  for (const img of document.images) {
    const r = img.getBoundingClientRect();
    const area = r.width * r.height;
    if (r.width > 300 && r.height > 300 && img.complete && img.naturalWidth > 300
        && area > bestArea && img.currentSrc.startsWith('http')) {
      best = img; bestArea = area;
    }
  }
  return best ? best.currentSrc : null;
}
"""


def ext_of(ct):
    ct = (ct or "").lower()
    if "png" in ct:
        return ".png"
    if "webp" in ct:
        return ".webp"
    if "gif" in ct:
        return ".gif"
    return ".jpg"


def bigger_url(url):
    u = urlparse(url)
    q = parse_qs(u.query)
    if "size" not in q:
        return None
    q["size"] = ["4000x4000"]
    return urlunparse(u._replace(query=urlencode(q, doseq=True)))


def fetch(ctx, url):
    try:
        r = ctx.request.get(url)
        if r.ok and r.headers.get("content-type", "").startswith("image/"):
            return r
    except Exception as e:
        print(f"   ошибка запроса: {e}")
    return None


def save(ctx, src, n):
    resp = None
    if TRY_BIGGER:
        big = bigger_url(src)
        if big:
            resp = fetch(ctx, big)
    if resp is None:
        resp = fetch(ctx, src)
    if resp is None:
        print(f"[{n}] ОШИБКА скачивания: {src[:120]}")
        return False

    u = urlparse(src)
    q = parse_qs(u.query)
    name = unquote(q["filename"][0]) if "filename" in q else unquote(Path(u.path).name)
    name = re.sub(r'[\\/:*?"<>|]', "_", name) or "photo"
    if not Path(name).suffix:
        name += ext_of(resp.headers.get("content-type"))

    body = resp.body()
    (OUT_DIR / f"{n:04d}_{name}").write_bytes(body)
    print(f"[{n}] {name}  {len(body) / 1e6:.2f} МБ")
    return True


with sync_playwright() as p:
    ctx = p.chromium.launch_persistent_context(
        PROFILE_DIR,
        headless=False,
        viewport={"width": 1800, "height": 850},
        device_scale_factor=2,
    )
    page = ctx.pages[0] if ctx.pages else ctx.new_page()
    page.goto(FOLDER_URL)

    input("Откройте ПЕРВОЕ фото, дождитесь загрузки и нажмите Enter... ")
    page.bring_to_front()

    seen = set()
    n = 0
    skipped = 0
    fails = 0

    last = page.evaluate(FIND_IMG)
    if last:
        seen.add(last)
        n += 1
        save(ctx, last, n)

    while True:
        page.keyboard.press("ArrowRight")

        new = None
        for _ in range(WAIT_SEC * 4):
            page.wait_for_timeout(250)
            s = page.evaluate(FIND_IMG)
            if s and s != last:
                page.wait_for_timeout(400)          # догрузка качественной версии
                new = page.evaluate(FIND_IMG) or s
                break

        if new and new not in seen:
            seen.add(new)
            last = new
            n += 1
            save(ctx, new, n)
            fails = 0
        else:
            fails += 1