Web scraping

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
pixewakb
User
Beiträge: 1412
Registriert: Sonntag 24. April 2011, 19:43

Hallo zusammen,

ich scrape gerade eine Seite, die ein CSRF-Token setzt. Im Browser kopiere ich in der Entwicklerkonsole die Anfragekopfzeilen heraus und kann damit dann eine Anfrage erzeugen, aber mit requests habe ich das noch nicht hinbekommen. Ich kann das CSRF-Token zwar im Quelltext einer Seite auslesen, aber irgendwie gebe ich es anscheinend nicht richtig bei.

Hat jemand eine Idee, wo ich eine Anregung bekommen könnte, das Problem zu händeln!? Ich dachte bislang, dass meine Anfrage an die Seite eigentlich eine Rückgabe erzeugen müsste, mit der ich dann wiederum korrekte Anfragen stellen kann, das erscheint mir aber als Trugschluss. Selenium kenne ich, hier verstehe ich aktuell das eigentliche Problem aber nicht.

Hat jemand eine Idee?
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Hast Du die Cookies richtig gesetzt? Zeig doch deinen Code. Der sagt mehr als tausend Worte.
Benutzeravatar
pixewakb
User
Beiträge: 1412
Registriert: Sonntag 24. April 2011, 19:43

Momentan kopiere ich die Anfragekopfzeilen direkt aus dem Browser und kann damit auf die Daten zugreifen, allerdings würde ich diesen Schritt gern automatisieren.

Ich verstehe noch nicht so richtig, wie ich an ein gültiges Cookie von der Seite komme (incl. X-CSRF-TOKEN), um eine richtige Anfrage an die Seite zu stellen. Meine aktuellen Versuche scheitern da, mein Quelltext scheint fehlerhaft.

Die Daten, die mich interessieren, habe ich bereits, aber ansonsten würde ich es halt gerne auch verstehen, wie ich bei anderen Seiten solche Sachen regeln könnte.

Code: Alles auswählen

import requests
import webbrowser
from pprint import pprint
from bs4 import BeautifulSoup

url = "https://www.egn-abfallkalender.de/kalender"

parameter = {'city': 'Brüggen',
             'district': 'Bracht',
             'street': 'Agrisstrasse',
             'street_number': '1'}

# Aus der Entwicklerkonsole herauskopieren
w = """Host: www.egn-abfallkalender.de
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: */*
Accept-Language: de,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-CSRF-TOKEN: fMOjWQGoimreuxxplYCOTPRG2c6pceYq4xkEaExn
X-Requested-With: XMLHttpRequest
Content-Length: 69
Origin: https://www.egn-abfallkalender.de
Connection: keep-alive
Referer: https://www.egn-abfallkalender.de/kalender
Cookie: disclaimer=true; _ga=GA1.2.205931581.1577560646; _gid=GA1.2.884210314.1577560646; _hjid=ba9dfd24-14bb-4d7d-9788-f947ae730b10; _hjIncludedInSample=1; XSRF-TOKEN=eyJpdiI6IkdoaCt4MURyaFN4UzBTdCtPVkFrdHc9PSIsInZhbHVlIjoiZFhWQUpWTEM2YUxKR0VCbmQ5c0YwZllUbGNLdG0zb1wvR01VM3hGYUxBU1NsVnBLYVFtY2hGWFVcL3lLTjh4MUt5IiwibWFjIjoiOGVhMjE5MjI5MDI5YjZhYmEwZTYzMDc0M2VjOWVjNDMyMWVmMDRhYmRlMzNiNDU0NjljNjY1YmRhZjA4NDVlMCJ9; egn_abfallkalender_session=eyJpdiI6Ijl5NVJPY0V0YWloTUpnRmtFYXc2Umc9PSIsInZhbHVlIjoia1FDaDB3T1pHMitKTmw5WGNkcTM1cE9BYStBWVgyTkp2cXgwTFM5R0VCTnNBMHRub1wvS3lVeHo4cFNQY3FqTjgiLCJtYWMiOiIyMmIyMTg1NTkyYjY1NTQwZjVkMWMxYTRiYjQyZDliNDFmZDU2ZjUwMzY0NWZlMGMwZTAxOWMzZTViZmY4NjFjIn0%3D
TE: Trailers"""

s = requests.Session()

response = s.post(url)

soup = BeautifulSoup(response.text, "html5lib")

metas = soup.find_all("meta")
for meta in metas:
    if "csrf-token" in str(meta):
        csrftoken = str(meta).split('content="')[1].split('"')[0]

headers_new = {}
for line in w.split("\n"):
    key, item = line.split(": ")

    headers_new[key] = item

data = s.post(url, data=parameter, headers=headers_new, cookies={'__CSRFToken__': csrftoken}) # cookies=... ist wirkungslos

print(data.headers)
print(data.text)
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Einbuchstabige Variablennamen sind generell schlecht. Ein post-Request ohne Inhalt? Die erste Anfrage an eine Seite wäre ein GET-Request.

Du benutzt BeautifulSoup zum Parsen des HTML, dann wandelst Du aber wieder Teile davon in Strings um, um mit Stringmethoden drauf los zu gehen?

Die ganzen Header-Informationen sind überflüssig. Die werden schon durch die Session verwaltet. Wie kommst Du drauf, dass es ein Cookie mit dem Namen __CSRFToken__ geben sollte?

Code: Alles auswählen

import requests
from bs4 import BeautifulSoup

KALENDER_URL = "https://www.egn-abfallkalender.de/kalender"

session = requests.Session()
response = session.get(KALENDER_URL)
soup = BeautifulSoup(response.text, "html5lib")
meta_token = soup.find("meta", attrs={"name": "csrf-token"})

parameter = {
    'city': 'Brüggen',
    'district': 'Bracht',
    'street': 'Agrisstrasse',
    'street_number': '1'
}
data = session.post(KALENDER_URL, data=parameter,
    headers={"x-csrf-token": meta_token.attrs['content']})
Benutzeravatar
pixewakb
User
Beiträge: 1412
Registriert: Sonntag 24. April 2011, 19:43

Erst einmal danke! Das hätte ich so nicht hinbekommen. Ich werde in den nächsten Tagen ausgehend von Deiner Lösung schauen, ob ich damit in der Dokumentation noch einmal weiterkomme!
Benutzeravatar
pixewakb
User
Beiträge: 1412
Registriert: Sonntag 24. April 2011, 19:43

Möglicherweise kannst Du mir noch einmal helfen:

Auf dieser Seite https://www.egn-abfallkalender.de/kalender kann ich meine Stadt, dann meine Straße und zuletzt meine Hausnummer auswählen und je nach Eingabe (z. B. Stadt) werden dann die Straßen nachgeladen. Ich würde das gerne abfragen.

Ich habe in der Entwicklerkonsole geschaut und die Daten werden von der Adresse https://www.egn-abfallkalender.de/alexa bereitgestellt. Ich habe deinen Quelltext hier versucht und sehe bei den Anfragen in der Entwicklerkonsole eigentlich keinen Unterschied. Ich erhalte aber nicht die Daten, die ich in der Entwicklerkonsole sehen kann:

Code: Alles auswählen

{'data': {'message': {'text': 'Der Code scheint ungültig zu sein. Frage '
                              'Ameisenkalender, bitte nach einem neuem Setup '
                              'Code.',
                      'type': 'danger'}},
 'error': True}
Kannst Du mir mal einen Tipp geben, wie ich mein Problem löse und vor allem, wie ich strategisch selbst an die Lösung herankomme.

Ich erwarte, dass die Anfrage an die alexa-Adresse mir die Daten zurückgibt. Irgendetwas sehe oder verstehe ich aber offensichtlich nicht. Danke!
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Was hast Du denn ausprobiert?

Code: Alles auswählen

ALEXA_URL = "https://www.egn-abfallkalender.de/alexa"

data = session.post(ALEXA_URL,
    params={
        "_token": meta_token.attrs['content'],
        "city": "",
        "street": "",
        "district": "",
        "street_number": "",
    },
    headers={
        "x-csrf-token": meta_token.attrs['content'],
        "x-requested-with": "XMLHttpRequest",
    })
Antworten