query näited sciencedirect.md 24 KB

Tegelik lahendus asub: 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

pip install playwright
playwright install firefox

Kui tahad testida ka Chromiumiga:

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

    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().

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.

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.

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

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

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:

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.

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:

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

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:

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:

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

ja kasuta hiljem:

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.