Menü Schließen

Python requests.get Error 403 bei Web Scraping

Python Logo

Ich starte grade mit Python und habe mir als Aufgabe gesetzt die API von Yahoo Finance auszulesen bzw. abzufragen. Um z.B. die Finanzdaten der Apple Aktie abzufragen habe ich folgenden Code in Python verwendet. Als Parameter wird:

  • Symbol hier AAPL
  • Yahoo API Modul hier financialData
    verwendet.
import requests
response = requests.get('https://query1.finance.yahoo.com/v11/finance/quoteSummary/aapl?modules=financialData')
print(response.json())

Hierfür wird das Module requests benötigt, dass wie folgt mit pip installiert werden kann:

pip install requests

Leider erhielt ich folgende Fehlermeldung:

Exception has occurred: JSONDecodeError
Expecting value: line 1 column 1 (char 0)
StopIteration: 0
During handling of the above exception, another exception occurred:
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

Um der Ursache auf die Schliche zu kommen, habe ich in der Ausgabe, die Umwandlung in ein lesbares json-Format ( json() ) entfernt, wodurch ich diese Fehlermeldung erhielt:

import requests
response = requests.get('https://query1.finance.yahoo.com/v11/finance/quoteSummary/aapl?modules=financialData')
print(response)
...
<Response [403]>

Hier nun gut zu sehen, die Rückgabe der Abfrage von Yahoo Finance ist der HTTP Statuscode 403. Dieser bedeutet schlicht, Zugriff verweigert.

Uff, was nun, also etwas lesen, ist ja neu für mich. … Ok also… die Art der Abfrage bzw. des ziehen von Content aus Webseiten wird auch Web Scraping genannt, oder etwas freundlicher und offizieller erlaubt und somit normale API Abfragen sein können, wie in diesem Beispiel. Webseitenbetreiber schützen sich also gegen hohe und viele und vor allem „unberechtigte“ Abfragen durch Gegenmaßnahmen.

Eine dieser ist das Abfragen des Headers des anfragenden. Hier wird von normalen Benutzer der über seinen Browser zuggreift ausgegangen, also keine Bots oder Skripte. Browser senden einen Header mit mehr oder wenig vielen und nützlichen Informationen und das mache ich mir in dieser Abfrage mit Python zu nutze.

HEADERS = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:113.0) Gecko/20100101 Firefox/98.0",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.5",
        "Accept-Encoding": "gzip, deflate",
        "Connection": "keep-alive",
        "Upgrade-Insecure-Requests": "1",
        "Sec-Fetch-Dest": "document",
        "Sec-Fetch-Mode": "navigate",
        "Sec-Fetch-Site": "none",
        "Sec-Fetch-User": "?1",
        "Cache-Control": "max-age=0",
    }
response = requests.get('https://query1.finance.yahoo.com/v11/finance/quoteSummary/aapl?modules=financialData', headers=HEADERS)
print(response.json())
{'quoteSummary': {'result': [{'financialData': .... 'financialCurrency': 'USD'}}], 'error': None}}    

Ich habe also einfach vorgegeben, dass diese Abfrage aus einem Browser, genauer gesagt von Firefox Version 113.0, von einem Windows 10 Client erfolgt. Zudem habe ich weitere Angaben gemacht, damit dies plausibler ist. Dies wurde von der Yahoo Finance API akzeptiert und ich habe die Rückgabe im JSON-Format erhalten und mittels Python json() ausgegeben.

Als ein Update würde ich die obige Abfrage mit einer vorgeschalteten Abfrage zum HTTP Status Code wie folgt abfragen. Hierbei wird bei einem positiven HTTP Status Code 2xx das Skript weiter ausgeführt, während das Skript bei allem was ein 4xx liefert einen Fehler liefert.

if response.ok:
    print('Status HTTP:',response.status_code)
    data = response.json()
    print(data)
else:
    print("Fehler:", response.status_code)

Thats it … Have Fun!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert