Tegelik lahendus asub: How to scrape data from sciencedirect
Töö etapid:
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:
IP / võrk erineb
Cookie’d ja sessioon puuduvad
User-Agent / browser fingerprint
Geolocation / region / consent state
Institutsiooniline ligipääs
authType=SINGLE_SIGN_IN ja idpPolicy=...inst_assocJah, tasub võrrelda vähemalt neid asju:
Praktiliselt:
pip install playwright
playwright install firefox
Kui tahad testida ka Chromiumiga:
playwright install chromium
See script:
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()
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()
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.
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.
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()
See on tavaliselt parem kui hakata cookie’sid käsitsi kopeerima.
Kui sul on üks kord õnnestunud sessioon olemas, saad selle salvestada.
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()
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()
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.
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()
Ma teeks nii:
Käivita persistent context samas desktop masinas, kus käsitsi töötab.
headless=False
Logi vajadusel käsitsi sisse / institution access
Sulge ja käivita uuesti sama profiiliga
Kui töötab, siis alles proovi:
Nii saad kohe teada, kas probleem on:
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:
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:
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:
Sinu väljund:
GET /search ... -> 200GET /user/institution/login?... -> 302GET id.elsevier.com/as/authorization.oauth2?... -> 200See viitab, et:
Seega praktiline lahendus võib olla:
Kasuta olemasolevat legaalset sessiooni desktopi moodi persistent contextiga.
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.
Kui sul on lubatud ligipääs ainult desktopis, siis kasuta sama masinat / sama võrku / sama profiili.
Allolev kood teeb 4 asja:
See ei anna uut ligipääsu, vaid aitab säilitada juba laaditud avaliku/lehitsetava vaate, kui see korraks kätte tuleb.
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()
Sinu logi järgi jõuab search-page korraks ette.
Seega mõistlik strateegia on:
See ei ole “loginist möödahiilimine”, vaid juba laetud lehe säilitamine.
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()
Siin on kõige olulisemad asjad, mida kontrollida.
Sinu prompt näitab:
ardo@edgar:~/Python/ScienceDirect
Kui see on server / teine host / VM, siis väga tõenäoliselt erineb:
See on kõige tähtsam faktor.
ScienceDirect/Elsevier tunneb tihti institutsioonid ära:
Kui jah, siis kasutage:
launch_persistent_context(...)storage_stateMõni flow sõltub sellest.
Kõige praktilisem.
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")
Sageli ei pea kogu lehte brauseriga kraapima.
Saab kasutada:
See on palju stabiilsem kui dünaamilise otsingulehe HTML.
Ma ei soovita proovida:
See on nii tehniliselt ebastabiilne kui ka kasutustingimuste mõttes probleemne.
Sinu näite põhjal on kõige tõenäolisem:
Seega kõige realistlikum lahendus on:
Kui tahad, võin järgmises vastuses teha sulle ühe täpse “production” Playwright skripti, mis: