## I don't understand what the difference is between two pieces of code. First I will define some constants and thereafter my two approaches with different outcomes.

API\_KEY = \<api\_key>
EMAIL = <email>
PW = <password>
LOGIN\_URL = "[https://www.iea.org/account/login](https://www.iea.org/account/login)"
LOGIN\_VERIFICATION\_URL = "[https://www.iea.org/product/download/019959-000291-019927](https://www.iea.org/product/download/019959-000291-019927)"
SEARCH\_DOWNLOAD\_URL = "[https://www.iea.org/data-and-statistics/data-product/monthly-oil-price-statistics-2](https://www.iea.org/data-and-statistics/data-product/monthly-oil-price-statistics-2)"
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

import requests
from bs4 import BeautifulSoup

headers = {
'User-Agent': (
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:123.0)'
'Gecko/20100101 Firefox/123.0'
)
}

payload = {
"email": EMAIL,
"password": PW,
"\_token": "",
}

session = requests.Session()
session.headers.update(headers)

resp = session.get(LOGIN\_URL)
resp.raise\_for\_status()
html = BeautifulSoup(resp.text, "html.parser")

token = html.find("input", {"name": "\_token"})\["value"]

payload\["\_token"] = token
login\_response = session.post(LOGIN\_URL, data=payload)
login\_response.raise\_for\_status()

# [https://www.iea.org/product/download/019959-000291-019927](https://www.iea.org/product/download/019959-000291-019927)

resp1 = session.get(LOGIN\_VERIFICATION\_URL)

if resp1.status\_code != 200:
raise RuntimeError(f"Login failed (status {resp1.status\_code})")
print("Login successful")
-------------------------

## Login successful

import random, bs4
from zenrows import ZenRowsClient

SID = str(random.randint(1, 99999))

client = ZenRowsClient(API\_KEY)

# 1️⃣ Get login page to read CSRF token

login\_html = client.get(
LOGIN\_URL,
params={"session\_id": SID}
).text
token = bs4.BeautifulSoup(login\_html, "html.parser")&#x20;
.find("input", {"name": "\_token"})\["value"]

# 2️⃣ Post credentials + token

client.post(
LOGIN\_URL,
data={"email": EMAIL, "password": PW, "\_token": token},
params={"session\_id": SID}
).raise\_for\_status()

# 3️⃣ Quick sanity-check: try a protected direct-download URL

check = client.get(
"[https://www.iea.org/product/download/019959-000291-019927](https://www.iea.org/product/download/019959-000291-019927)",
params={"session\_id": SID},
stream=True          # avoid loading the whole XLSX into memory
)
if check.status\_code != 200:
raise RuntimeError(f"Login failed (status {check.status\_code})")
-----------------------------------------------------------------

RuntimeError                              Traceback (most recent call last)
Cell In\[58], line 48
41 check = client.get(
42     "[https://www.iea.org/product/download/019959-000291-019927](https://www.iea.org/product/download/019959-000291-019927)",
43     params={"session\_id": SID, "custom\_headers": "true"},
44     headers=hdrs,
45     stream=True          # don’t pull the whole XLSX into RAM
46 )
47 if check.status\_code != 200:
\---> 48     raise RuntimeError(f"Login failed (status {check.status\_code})")
49 print("✅ login OK – continuing")

RuntimeError: Login failed (status 404)