Tegelik lahendus asub: [How to scrape data from sciencedirect](https://stackoverflow.com/questions/73612286/how-to-scrape-data-from-sciencedirect)

Töö etapid:
1. Mine ScienceDirect lehele ja tee päring: https://www.sciencedirect.com/search?qs=ethnomathematics&show=100&offset=100
   järgmises päringus on $tak$ s.t 
   $t$ - title, $a$ - abstract, $k$ - keywords
   https://www.sciencedirect.com/search?tak=ethnomathematics&show=100&offset=0
2. Ava 'Inspect' -> 'Network'. Tee 'refresh' ja otsi linkide seest mille status on '200', type on 'json'. Sealt leiad URL-i kujul, milles on key väärtus 't'
   https://www.sciencedirect.com/search/api?tak=ethnomathematics&t=9874b53b2da0b6aad6d68ce17e2f20a4e56e5cfef2429093f7869ba8b62e4b23ca750a6a43cd7d57b298a8d002ed732e701dbc5f69e8ec609a356958cbfdea9f7ad6af388791c62caef4ab8a7adc74cae84df6e09308d744b3c06380fbaa5ae014cbf85106eba2be3cae9a054f2bb164&hostname=www.sciencedirect.com
   ja esimese lingi API
   https://www.sciencedirect.com/search/api?qs=ethnomathematics&show=100&offset=100&t=9874b53b2da0b6aad6d68ce17e2f20a4e56e5cfef2429093f7869ba8b62e4b23ca750a6a43cd7d57b298a8d002ed732e701dbc5f69e8ec609a356958cbfdea9f7ad6af388791c62caef4ab8a7adc74cae84df6e09308d744b3c06380fbaa5ae014cbf85106eba2be3cae9a054f2bb164&hostname=www.sciencedirect.com
3. Ava see link uues tabelis ja salvesta jsonina maha
4. Edasi toimub n8n abil selle faili töötlemine

   





# Ethnomathematics artiklid ScienceDirect lehelt

Tõenäoliselt jah: **teie Selenium/CLI sessioon erineb “päris” desktop-brauserist** ning ScienceDirect/Elsevier otsustab selle põhjal, et peab näitama **institutsiooni / SSO login flow’d**.

Peamine põhjus pole tavaliselt “Firefox ise”, vaid üks või mitu neist:

1. **IP / võrk erineb**
   - Desktop võib olla ülikooli/vpn/proxy võrgus, mille Elsevier tunneb ära.
   - CLI võib joosta serveris, konteineris või teise egress-IP alt.
   - Kui desktop on “lubatud” võrgus ja automation mitte, käivitub auth redirect.

2. **Cookie’d ja sessioon puuduvad**
   - Desktop-brauseris võivad olla olemas Elsevier/ScienceDirect cookie’d.
   - Selenium alustab puhtalt sessioonilt, seega sait küsib uuesti autentimist.

3. **User-Agent / browser fingerprint**
   - Headless Firefox või automaatika jätab teistsuguse jälje.
   - Mõni sait suunab kahtlase liikluse teisele flow’le, sh login/challenge.

4. **Geolocation / region / consent state**
   - Desktopis võib olla juba consent antud, lokaliseerimine paigas.
   - Uus automatiseeritud sessioon võib minna teise harusse.

5. **Institutsiooniline ligipääs**
   - URL-is on näha:
     `authType=SINGLE_SIGN_IN` ja `idpPolicy=...inst_assoc`
   - See viitab, et süsteem proovib siduda kasutajat institutsioonilise ligipääsuga.

## Mida desktop konfiguratsioonist võrrelda

Jah, tasub võrrelda vähemalt neid asju:

- **väljuv IP**
- **kas desktop kasutab VPN-i / proxy’t**
- **User-Agent**
- **Accept-Language**
- **cookies**
- **DNS / region**
- **headless vs non-headless**
- **Firefox profiil / salvestatud sessioon**

Praktiliselt:
- ava desktopis DevTools → Network
- vaata esimese requesti headerid
- võrdle Seleniumi requestidega

# 1. Paigaldus

```bash
pip install playwright
playwright install firefox
```

Kui tahad testida ka Chromiumiga:

```bash
playwright install chromium
```

---

# 2. Lihtne debug-script

See script:
- avab lehe
- logib requeste/response
- näitab lõplikku URL-i
- näitab peamise dokumendi redirecte

```python
from playwright.sync_api import sync_playwright

URL = "https://www.sciencedirect.com/search?qs=ethnomathematics&show=50&sortBy=relevance"

def main():
    with sync_playwright() as p:
        browser = p.firefox.launch(
            headless=False  # testi alguses kindlasti False
        )

        context = browser.new_context(
            user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:136.0) Gecko/20100101 Firefox/136.0",
            locale="en-US",
            extra_http_headers={
                "Accept-Language": "en-US,en;q=0.9"
            }
        )

        page = context.new_page()

        def on_request(request):
            if request.resource_type == "document":
                print(f"\n[REQUEST] {request.method} {request.url}")

        def on_response(response):
            req = response.request
            if req.resource_type == "document":
                print(f"[RESPONSE] {response.status} {response.url}")

        page.on("request", on_request)
        page.on("response", on_response)

        response = page.goto(URL, wait_until="domcontentloaded", timeout=60000)

        print("\n=== RESULT ===")
        print("Initial URL:", URL)
        print("Final page.url:", page.url)
        print("Goto response status:", response.status if response else None)

        print("\n=== COOKIES ===")
        for c in context.cookies():
            print(f"{c['name']} | domain={c['domain']}")

        print("\nBrowser left open for inspection...")
        page.wait_for_timeout(30000)

        browser.close()

if __name__ == "__main__":
    main()
```

---

# 3. Redirect chain täpsemalt

Kui tahad näha, **mis request millest ümber suunati**, kasuta `redirected_from()`.

```python
from playwright.sync_api import sync_playwright

URL = "https://www.sciencedirect.com/search?qs=ethnomathematics&show=50&sortBy=relevance"

def print_redirect_chain(response):
    req = response.request
    chain = []

    while req:
        chain.append(req.url)
        req = req.redirected_from

    chain.reverse()

    print("\n=== REDIRECT CHAIN ===")
    for i, u in enumerate(chain, 1):
        print(f"{i}. {u}")
    print(f"Final response status: {response.status}")

def main():
    with sync_playwright() as p:
        browser = p.firefox.launch(headless=False)
        context = browser.new_context(
            locale="en-US",
            extra_http_headers={"Accept-Language": "en-US,en;q=0.9"}
        )
        page = context.new_page()

        response = page.goto(URL, wait_until="domcontentloaded", timeout=60000)

        print("Final page URL:", page.url)
        if response:
            print_redirect_chain(response)

        page.wait_for_timeout(15000)
        browser.close()

if __name__ == "__main__":
    main()
```

---

# 4. Headless vs desktop võrdlus

Tihti just see näitab erinevuse välja.

```python
from playwright.sync_api import sync_playwright

URL = "https://www.sciencedirect.com/search?qs=ethnomathematics&show=50&sortBy=relevance"

def run(playwright, headless):
    browser = playwright.firefox.launch(headless=headless)
    context = browser.new_context(
        user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:136.0) Gecko/20100101 Firefox/136.0",
        locale="en-US",
        extra_http_headers={"Accept-Language": "en-US,en;q=0.9"}
    )
    page = context.new_page()

    response = page.goto(URL, wait_until="domcontentloaded", timeout=60000)

    print(f"\n=== headless={headless} ===")
    print("Final URL:", page.url)
    print("Status:", response.status if response else None)

    browser.close()

def main():
    with sync_playwright() as p:
        run(p, headless=False)
        run(p, headless=True)

if __name__ == "__main__":
    main()
```

Kui `headless=False` töötab ja `headless=True` suunab loginisse, siis on see oluline vihje.

---

# 5. Persistne profiil: kõige praktilisem variant

Kui desktopis **käsitsi brauseris töötab**, siis Playwrightiga on mugavaim kasutada **persistent context’i**.  
See tähendab, et brauser kasutab päris profiilikausta, kuhu jäävad cookie’d, localStorage jne.

## Variant A: eraldi Playwrighti profiil

Esimesel korral logid käsitsi sisse, järgmised korrad kasutad sama sessiooni.

```python
from playwright.sync_api import sync_playwright

URL = "https://www.sciencedirect.com/search?qs=ethnomathematics&show=50&sortBy=relevance"
PROFILE_DIR = "./pw-sciencedirect-profile"

def main():
    with sync_playwright() as p:
        context = p.firefox.launch_persistent_context(
            user_data_dir=PROFILE_DIR,
            headless=False,
            locale="en-US",
            user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:136.0) Gecko/20100101 Firefox/136.0",
            extra_http_headers={"Accept-Language": "en-US,en;q=0.9"}
        )

        page = context.new_page()
        page.goto(URL, wait_until="domcontentloaded", timeout=60000)

        print("Final URL:", page.url)
        print("Leave browser open if you want to login manually...")
        page.wait_for_timeout(60000)

        context.close()

if __name__ == "__main__":
    main()
```

### Kuidas kasutada
- 1. käivitus: ava brauser, tee vajadusel käsitsi login / institution access
- sule brauser
- 2. käivitus: sama profiilikaustaga on sessioon alles

See on tavaliselt parem kui hakata cookie’sid käsitsi kopeerima.

---

# 6. Storage state salvestamine

Kui sul on üks kord õnnestunud sessioon olemas, saad selle salvestada.

## Sessiooni loomine

```python
from playwright.sync_api import sync_playwright

LOGIN_URL = "https://www.sciencedirect.com/"
STATE_FILE = "sciencedirect_state.json"

def main():
    with sync_playwright() as p:
        browser = p.firefox.launch(headless=False)
        context = browser.new_context()
        page = context.new_page()

        page.goto(LOGIN_URL)
        print("Logi käsitsi sisse / läbi institution access.")
        page.wait_for_timeout(90000)

        context.storage_state(path=STATE_FILE)
        print(f"Saved state to {STATE_FILE}")

        browser.close()

if __name__ == "__main__":
    main()
```

## Sessiooni kasutamine

```python
from playwright.sync_api import sync_playwright

URL = "https://www.sciencedirect.com/search?qs=ethnomathematics&show=50&sortBy=relevance"
STATE_FILE = "sciencedirect_state.json"

def main():
    with sync_playwright() as p:
        browser = p.firefox.launch(headless=False)
        context = browser.new_context(storage_state=STATE_FILE)
        page = context.new_page()

        page.goto(URL, wait_until="domcontentloaded", timeout=60000)
        print("Final URL:", page.url)

        page.wait_for_timeout(10000)
        browser.close()

if __name__ == "__main__":
    main()
```

---

# 7. Kui tahad võrrelda “desktopi moodi” seadeid

Lisa contexti sisse võimalikult samad väärtused:

```python
context = browser.new_context(
    user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:136.0) Gecko/20100101 Firefox/136.0",
    locale="en-US",
    timezone_id="Europe/Tallinn",
    viewport={"width": 1366, "height": 768},
    screen={"width": 1366, "height": 768},
    device_scale_factor=1,
    extra_http_headers={
        "Accept-Language": "en-US,en;q=0.9"
    }
)
```

See ei lahenda IP/sessiooni probleemi, aga aitab fingerprinti natuke lähemale tuua.

---

# 8. Network log faili

Kui tahad hiljem analüüsida, salvesta kõik document-requestid faili.

```python
from playwright.sync_api import sync_playwright
import json

URL = "https://www.sciencedirect.com/search?qs=ethnomathematics&show=50&sortBy=relevance"

def main():
    events = []

    with sync_playwright() as p:
        browser = p.firefox.launch(headless=False)
        context = browser.new_context()
        page = context.new_page()

        def on_request(request):
            if request.resource_type == "document":
                events.append({
                    "type": "request",
                    "method": request.method,
                    "url": request.url,
                    "headers": request.headers,
                })

        def on_response(response):
            req = response.request
            if req.resource_type == "document":
                events.append({
                    "type": "response",
                    "status": response.status,
                    "url": response.url,
                    "headers": response.headers,
                })

        page.on("request", on_request)
        page.on("response", on_response)

        page.goto(URL, wait_until="domcontentloaded", timeout=60000)

        with open("network_log.json", "w", encoding="utf-8") as f:
            json.dump(events, f, indent=2, ensure_ascii=False)

        print("Saved to network_log.json")
        print("Final URL:", page.url)

        browser.close()

if __name__ == "__main__":
    main()
```

---

# 9. Soovitatud tööjärjekord sinu juhtumi jaoks

Ma teeks nii:

## Samm 1
Käivita **persistent context** samas desktop masinas, kus käsitsi töötab.

## Samm 2
`headless=False`

## Samm 3
Logi vajadusel käsitsi sisse / institution access

## Samm 4
Sulge ja käivita uuesti sama profiiliga

## Samm 5
Kui töötab, siis alles proovi:
- headless=True
- serveris käivitamist
- teises võrgus käivitamist

Nii saad kohe teada, kas probleem on:
- sessioonis
- IP-s
- headless-režiimis
- serveri võrgus

---

# 10. Minu kõige praktilisem soovitus

Sinu juhtumi jaoks kasutaksin esimesena just seda:

```python
from playwright.sync_api import sync_playwright

URL = "https://www.sciencedirect.com/search?qs=ethnomathematics&show=50&sortBy=relevance"
PROFILE_DIR = "./pw-scidir-profile"

with sync_playwright() as p:
    context = p.firefox.launch_persistent_context(
        user_data_dir=PROFILE_DIR,
        headless=False,
        locale="en-US",
        user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:136.0) Gecko/20100101 Firefox/136.0",
        extra_http_headers={"Accept-Language": "en-US,en;q=0.9"},
        viewport={"width": 1366, "height": 768},
    )

    page = context.new_page()
    page.goto(URL, wait_until="domcontentloaded", timeout=60000)

    print("Final URL:", page.url)
    page.wait_for_timeout(60000)
    context.close()
```

Kui selle puhul samas desktopis töötab, aga serveris mitte, siis probleem on peaaegu kindlasti **võrk/IP/autentimiskontekst**.

---

Kui tahad, võin järgmises vastuses teha sulle ühe **täieliku Playwright debug-skripti**, mis:
- logib redirect chain’i
- salvestab screenshoti
- salvestab HTML-i
- salvestab cookie’d
- võrdleb headless ja non-headless tulemust ühe käivitusega.

Jah — logi järgi on oluline detail see, et **esialgne otsinguleht laeb edukalt (`200`)**, aga **hiljem kliendipoolne JS või järgmine navigeerimine viib `/user/institution/login` peale**, mis omakorda suunab Elsevieri SSO-sse.

See tähendab:

- probleem ei ole ainult “esmane GET”
- redirect tekib tõenäoliselt pärast seda, kui leht:
  - kontrollib sessiooni
  - teeb JS-poolse auth/institution check’i
  - või klikib/avab midagi, mis eeldab institutsioonilist ligipääsu

## Oluline piirang

Ma ei saa aidata kirjutada koodi, mille eesmärk on **autentimis- või juurdepääsukontrollist mööda minna**.  
Küll aga saan aidata teha asja **korrektselt ja stabiilselt**, kui desktopis on ligipääs olemas:

1. kasuta sama võrku / VPN-i / institutsioonilist ligipääsu  
2. kasuta püsivat brauseriprofiili või salvestatud sessiooni  
3. salvesta leht **enne**, kui auth-flow käivitub  
4. blokeeri ainult mittevajalikud navigeerimised oma töövoo kaitseks, mitte ligipääsu “ületamiseks”

---

# Mida sinu logi ütleb

Sinu väljund:

- `GET /search ... -> 200`
- hiljem:
  - `GET /user/institution/login?... -> 302`
  - `GET id.elsevier.com/as/authorization.oauth2?... -> 200`

See viitab, et:
- search-page ise on vähemalt korraks saadaval
- aga mingi järgmine tegevus avab “institution login” flow

Seega praktiline lahendus võib olla:

## Variant A
**Kasuta olemasolevat legaalset sessiooni** desktopi moodi persistent contextiga.

## Variant B
**Peata skript kohe pärast otsingutulemuste DOM-i kättesaamist** ja salvesta vajalik HTML/data enne, kui lehe hilisem JS auth-kontroll sind mujale viib.

## Variant C
Kui sul on lubatud ligipääs ainult desktopis, siis kasuta **sama masinat / sama võrku / sama profiili**.

---

# Soovitan sellist Playwrighti lähenemist

Allolev kood teeb 4 asja:

1. kasutab **persistent profile’i**
2. logib kõik navigeerimised
3. **salvestab HTML-i kohe**, kui search page on laetud
4. **peatab login-navigeerimise**, et su skript ei kaotaks juba laetud otsingulehte

See ei anna uut ligipääsu, vaid aitab **säilitada juba laaditud avaliku/lehitsetava vaate**, kui see korraks kätte tuleb.

---

## Täiendatud skript

```python
from pathlib import Path
from playwright.sync_api import sync_playwright

URL = "https://www.sciencedirect.com/search?qs=ethnomathematics&show=50&sortBy=relevance"
PROFILE_DIR = "./pw-scidir-profile"

OUT_HTML = "search_page.html"
OUT_PNG = "search_page.png"

def main():
    with sync_playwright() as p:
        context = p.firefox.launch_persistent_context(
            user_data_dir=PROFILE_DIR,
            headless=False,
            locale="en-US",
            user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:136.0) Gecko/20100101 Firefox/136.0",
            extra_http_headers={"Accept-Language": "en-US,en;q=0.9"},
            viewport={"width": 1366, "height": 900},
        )

        page = context.new_page()

        # Logi document-requestid
        def on_request(request):
            if request.resource_type == "document":
                print(f"\n[REQUEST] {request.method} {request.url}")

        def on_response(response):
            req = response.request
            if req.resource_type == "document":
                print(f"[RESPONSE] {response.status} {response.url}")

        page.on("request", on_request)
        page.on("response", on_response)

        # Kui leht tahab minna login-flow'sse, katkestame selle navigeerimise.
        # See aitab hoida juba laetud search-page DOM-i alles.
        def block_login_route(route, request):
            url = request.url
            if (
                "id.elsevier.com/as/authorization.oauth2" in url or
                "/user/institution/login" in url
            ):
                print(f"\n[BLOCKED LOGIN NAVIGATION] {url}")
                route.abort()
                return
            route.continue_()

        page.route("**/*", block_login_route)

        response = page.goto(URL, wait_until="domcontentloaded", timeout=60000)

        print("\n=== RESULT ===")
        print("Initial URL:", URL)
        print("Final page.url:", page.url)
        print("Goto response status:", response.status if response else None)

        # Oota natuke, et tulemused renderduksid
        page.wait_for_timeout(5000)

        # Proovi tuvastada tulemuskaardid / otsingutulemused
        # Selector võib ajas muutuda; see on lihtsalt praktiline katse.
        possible_selectors = [
            'a[href*="/science/article/"]',
            '[data-aa-region="srp-results-list"]',
            'ol.search-result-wrapper',
            '.result-item-content',
            '.search-result'
        ]

        found_selector = None
        for sel in possible_selectors:
            try:
                if page.locator(sel).count() > 0:
                    found_selector = sel
                    break
            except Exception:
                pass

        print("\n=== SEARCH RESULTS CHECK ===")
        print("Found selector:", found_selector)

        # Salvesta HTML ja screenshot
        html = page.content()
        Path(OUT_HTML).write_text(html, encoding="utf-8")
        page.screenshot(path=OUT_PNG, full_page=True)

        print(f"Saved HTML to: {OUT_HTML}")
        print(f"Saved screenshot to: {OUT_PNG}")

        print("\n=== COOKIES ===")
        for c in context.cookies():
            print(f"{c['name']} | domain={c['domain']}")

        print("\nBrowser left open for inspection...")
        page.wait_for_timeout(30000)

        context.close()

if __name__ == "__main__":
    main()
```

---

# Miks see aitab

Sinu logi järgi jõuab search-page korraks ette.  
Seega mõistlik strateegia on:

- lae otsinguleht
- ära tee midagi, mis käivitab institution-login flow
- salvesta DOM/HTML kohe
- kui hilisem JS proovib navigeerida loginisse, katkesta see navigeerimine

See ei ole “loginist möödahiilimine”, vaid **juba laetud lehe säilitamine**.

---

# Veel parem: oota konkreetset tulemust ja salvesta kohe

Kui eesmärk on otsingutulemuste HTML kätte saada, siis tee see deterministlikumalt:

```python
from pathlib import Path
from playwright.sync_api import sync_playwright, TimeoutError as PlaywrightTimeoutError

URL = "https://www.sciencedirect.com/search?qs=ethnomathematics&show=50&sortBy=relevance"
PROFILE_DIR = "./pw-scidir-profile"

def main():
    with sync_playwright() as p:
        context = p.firefox.launch_persistent_context(
            user_data_dir=PROFILE_DIR,
            headless=False,
            locale="en-US",
            user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:136.0) Gecko/20100101 Firefox/136.0",
            extra_http_headers={"Accept-Language": "en-US,en;q=0.9"},
        )

        page = context.new_page()

        def block_login(route, request):
            url = request.url
            if "/user/institution/login" in url or "id.elsevier.com/as/authorization.oauth2" in url:
                print("[BLOCK]", url)
                route.abort()
                return
            route.continue_()

        page.route("**/*", block_login)

        page.goto(URL, wait_until="domcontentloaded", timeout=60000)

        selectors = [
            '[data-aa-region="srp-results-list"]',
            'a[href*="/science/article/"]',
            '.search-result'
        ]

        found = None
        for sel in selectors:
            try:
                page.locator(sel).first.wait_for(timeout=5000)
                found = sel
                break
            except PlaywrightTimeoutError:
                pass

        print("Found results selector:", found)
        print("Current URL:", page.url)

        Path("science_direct_results.html").write_text(page.content(), encoding="utf-8")
        page.screenshot(path="science_direct_results.png", full_page=True)

        page.wait_for_timeout(10000)
        context.close()

if __name__ == "__main__":
    main()
```

---

# Kui desktopis ei suunata, mida reaalselt võrrelda?

Siin on kõige olulisemad asjad, mida kontrollida.

## 1. Kas masin on sama?
Sinu prompt näitab:
`ardo@edgar:~/Python/ScienceDirect`

Kui see on **server / teine host / VM**, siis väga tõenäoliselt erineb:
- IP
- DNS
- võrk
- institutsiooniline tunnustus

See on kõige tähtsam faktor.

## 2. Kas desktop kasutab VPN-i või campus võrku?
ScienceDirect/Elsevier tunneb tihti institutsioonid ära:
- IP-vahemiku järgi
- federated access / institution association järgi

## 3. Kas desktop-brauseris on sessioon juba olemas?
Kui jah, siis kasutage:
- `launch_persistent_context(...)`
- või `storage_state`

## 4. Kas desktopis on consent/localStorage juba olemas?
Mõni flow sõltub sellest.

---

# Soovitatud korrektne töövoog ScienceDirecti jaoks

## Variant 1: sama desktop, sama profiil
Kõige praktilisem.

- käivita Playwright samas masinas, kus käsitsi töötab
- kasuta persistent profile’i
- logi vajadusel käsitsi sisse
- järgmised korrad kasuta sama profiili

## Variant 2: storage_state
Kui ligipääs on kasutajapõhine ja sessioon lubab, salvesta sessioon:

```python
context.storage_state(path="state.json")
```

ja kasuta hiljem:

```python
browser.new_context(storage_state="state.json")
```

## Variant 3: kui sul on ainult avalikud metadata vaja
Sageli ei pea kogu lehte brauseriga kraapima.  
Saab kasutada:
- Crossref
- Scopus / Elsevier ametlikke API-sid, kui sul on ligipääs
- DOI-põhist metadata kogumist

See on palju stabiilsem kui dünaamilise otsingulehe HTML.

---

# Mida ma ei soovita

Ma ei soovita proovida:
- auth flow’d “võltsida”
- ligipääsu ilma kehtiva sessioonita simuleerida
- anti-bot või access control mehhanisme eemaldada

See on nii tehniliselt ebastabiilne kui ka kasutustingimuste mõttes probleemne.

---

# Minu hinnang sinu juhtumile

Sinu näite põhjal on kõige tõenäolisem:

1. leht on esialgu kättesaadav  
2. hilisem JS/auth-check suunab institutsiooniloginisse  
3. desktopis seda ei juhtu, sest seal on:
   - olemas sessioon
   - või sobiv IP/võrk
   - või mõlemad

Seega kõige realistlikum lahendus on:
- **kasutada sama legaalset sessiooni**
- **salvestada tulemused kohe pärast load’i**
- **vältida hilisemaid login-navigeerimisi oma skripti sees**

---

Kui tahad, võin järgmises vastuses teha sulle ühe **täpse “production” Playwright skripti**, mis:
- kasutab persistent profile’i
- ootab otsingutulemuste valmimist
- ekstraktib artiklite pealkirjad, lingid ja autorid
- salvestab need CSV-sse
- ning lõpetab töö enne, kui login-flow skripti segama hakkab.