HTMLParser.feed - TypeError: feed() missing 1 required positional argument

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
Pythagon
User
Beiträge: 52
Registriert: Mittwoch 3. Juli 2019, 18:21

Guten Morgen liebe Forumsgemeinde,

ich bin absoluter Python Neuling und habe bisher nur VBA programmiert. Ich möchte mit folgendem Code das HTML Skript einer Webseite mit Hilfe der HTMLParser.feed Methode einlesen in ein DOM Element, allerdings bekomme ich eine Fehlermeldung aus der ich nicht schlau werde:
import requests

from html.parser import HTMLParser

s = requests.Session()

r = s.get("https://de.finance.yahoo.com/quote/DAI. ... 1d/cookies")

t = HTMLParser.feed(r.text)
Der folgende Fehler wird angezeigt wenn ich den Code starte:
RESTART: C:\Users\Public\Geldanlage & Börse\Pivot Tabellen & Auswertungen\Dividendenbewertung\Dividenden-Tool 1.4.py
Traceback (most recent call last):
File "C:\Users\Public\Geldanlage & Börse\Pivot Tabellen & Auswertungen\Dividendenbewertung\Dividenden-Tool 1.4.py", line 9, in <module>
t = HTMLParser.feed(r.text)
TypeError: feed() missing 1 required positional argument: 'data'
Kann mir jemand mitteilen was ich falsch mache?

Beste grüße,
Marc
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

Du solltest nicht die ungebundene Methode der Klasse aufrufen, sondern erst eine Instanz erzeugen, auf der Du `feed` dann aufrufen kannst. Aber, ein HTMLParser an sich, macht nicht viel, `feed` hat keinen Rückgabewert. Um ihn wirklich benutzen zu können, muß man eine Klasse davon ableiten, siehe die Dokumentation. Um mit HTML arbeiten zu können, bietet sich BeautifulSoup an, da muß man sich nicht um die Speicherung in einer passenden Struktur kümmern, sondern kann direkt die Elemente bequem abfragen.

Gewöhn Dir gleich an, sprechende Variablennamen zu benutzen. Einbuchstabige sind das garantiert nicht. `session` statt `s`, `response` statt `r`, nichts statt `t`.
Jankie
User
Beiträge: 592
Registriert: Mittwoch 26. September 2018, 14:06

mit BeautifulSoup geht es meiner Meinung nach einfacher, so würde das ganze dann aussehen, wenn du nur den aktuellen Kurs abfragen willst:

Code: Alles auswählen

import requests
from bs4 import BeautifulSoup


HEADERS = {"User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0"}
URL = "https://de.finance.yahoo.com/quote/DAI.DE/history?period1=1404165600&period2=1561932000&interval=div|split&filter=div&frequency=1d/cookies"

def get_current_course(URL):          
    page = requests.get(URL, headers=HEADERS)
    soup = BeautifulSoup(page.content, "html.parser")
    price = soup.find('span', {'class' : 'Trsdu(0.3s) Fw(b) Fz(36px) Mb(-4px) D(ib)'}).get_text()
    converted_price = float(price.replace(",","."))
    return converted_price
    
        
print(get_current_course(URL))
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@Jankie: bei CSS-Klassen, die eigentlich nur Formatierungsangaben enthalten, sollte man vorsichtig sein. Die können sich schnell mal ändern, es fehlt also an Robustheit der Lösung.
Pythagon
User
Beiträge: 52
Registriert: Mittwoch 3. Juli 2019, 18:21

Sirius3 hat geschrieben: Mittwoch 10. Juli 2019, 07:12 Du solltest nicht die ungebundene Methode der Klasse aufrufen, sondern erst eine Instanz erzeugen, auf der Du `feed` dann aufrufen kannst. Aber, ein HTMLParser an sich, macht nicht viel, `feed` hat keinen Rückgabewert. Um ihn wirklich benutzen zu können, muß man eine Klasse davon ableiten, siehe die Dokumentation. Um mit HTML arbeiten zu können, bietet sich BeautifulSoup an, da muß man sich nicht um die Speicherung in einer passenden Struktur kümmern, sondern kann direkt die Elemente bequem abfragen.

Gewöhn Dir gleich an, sprechende Variablennamen zu benutzen. Einbuchstabige sind das garantiert nicht. `session` statt `s`, `response` statt `r`, nichts statt `t`.
Hallo Sirius,

Deiner Aussage entnehme ich, dass ich meinen Aufruf anscheinend via Late Binding getätigt habe. Das war dann unbewusst denn ich habe noch keine Ahnung wie man Early & Late Binding in Python unterscheidet. Mit Beautiful Soap sollte ich mich dann mal befassen und was die Variablen angeht; nun es war einfach nur ein kurzes Beispielskript.

Trotzdem würde es mich freuen wenn Du mir mitteilen könntest was an meinem Skript bzw. an der Zeile "t = HTMLParser.feed(r.text)" falsch ist bzw. was die Fehlermeldung genau bedeutet. Ist die Methode .Feed nicht geeignet die HTML DOM-Struktur der Seite in das HTML-Objekt zu laden?

Gruß,
Marc
Pythagon
User
Beiträge: 52
Registriert: Mittwoch 3. Juli 2019, 18:21

Jankie hat geschrieben: Mittwoch 10. Juli 2019, 07:19 mit BeautifulSoup geht es meiner Meinung nach einfacher, so würde das ganze dann aussehen, wenn du nur den aktuellen Kurs abfragen willst:

Code: Alles auswählen

import requests
from bs4 import BeautifulSoup


HEADERS = {"User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0"}
URL = "https://de.finance.yahoo.com/quote/DAI.DE/history?period1=1404165600&period2=1561932000&interval=div|split&filter=div&frequency=1d/cookies"

def get_current_course(URL):          
    page = requests.get(URL, headers=HEADERS)
    soup = BeautifulSoup(page.content, "html.parser")
    price = soup.find('span', {'class' : 'Trsdu(0.3s) Fw(b) Fz(36px) Mb(-4px) D(ib)'}).get_text()
    converted_price = float(price.replace(",","."))
    return converted_price
    
        
print(get_current_course(URL))
Hallo Jankie,

das sieht interessant aus aber ich sollte euch am besten mal etwas genauer beschreiben was ich eigentlich vorhabe.

Ich möchte ein Request.Session Objekt erstellen um zunächst über einen Http-Request den Cookie-Crumb zu suchen um diesen bei meinem zweiten Http-Request einem Link hinzuzufügen mit dessen Hilfe ich mir ein CSV-File ziehe (Kurse bzw. Dividenden).

Mein Plan war zunächst ein HTML-Objekt zu erstellen, die DOM-Struktur der Seite darin zu speichern und darin zu iterieren bis ich den Cookie-Crumb habe. Wenn es mit Beautiful Soap einfacher sein sollte verwende ich auch gerne das.
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

Das hat nichts mit late oder early zu tun, sondern, ob Du eine Instanz erzeugst oder nicht.
Hast Du die Dokumentation zu HTMLParser schon gelesen, da findest Du die Beispiele.
Und ja, mit BeautifulSoup dürfte Deine Aufgabe einfacher zu lösen sein.
Pythagon
User
Beiträge: 52
Registriert: Mittwoch 3. Juli 2019, 18:21

Sirius3 hat geschrieben: Mittwoch 10. Juli 2019, 19:53 Das hat nichts mit late oder early zu tun, sondern, ob Du eine Instanz erzeugst oder nicht.
Hast Du die Dokumentation zu HTMLParser schon gelesen, da findest Du die Beispiele.
Und ja, mit BeautifulSoup dürfte Deine Aufgabe einfacher zu lösen sein.
Hallo Sirius3,

also es hat anscheinend geklappt mit folgendem Code das DOMObj zumindest schonmal mit Inhalt zu füllen:
import requests

from html.parser import HTMLParser

session = requests.Session()

parser = HTMLParser()

request = session.get("https://de.finance.yahoo.com/quote/DAI. ... 1d/cookies")

DOMObj = parser.feed(request.text)
Allerdings weiß ich nicht mit welcher Methode ich mir nun den inhalt des DOMObj anzeigen lassen könnte um sicherzustellen, dass der HTML-String sich tatsächlich darin befindet. (Ich will das jetzt einfach mal durchspielen. Später versuche ich es dann mit Beautiful Soap.)
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

Wie schon ganz am Anfang geschrieben, speichert ein HTMLParser nichts, das mußt Du selbst programmieren. Wie das geht, steht als Beispiel in der Dokumentation.
Pythagon
User
Beiträge: 52
Registriert: Mittwoch 3. Juli 2019, 18:21

Sirius3 hat geschrieben: Mittwoch 10. Juli 2019, 20:52 Wie schon ganz am Anfang geschrieben, speichert ein HTMLParser nichts, das mußt Du selbst programmieren. Wie das geht, steht als Beispiel in der Dokumentation.
Ich hab mir den Text natürlich durchgelesen aber dieser liest sich für mich so als ob man dem Parser mit der .Feed Methode einen String übergibt. Wenn der Parser damit aber nicht das Objekt füllt, was macht er dann?
Benutzeravatar
__blackjack__
User
Beiträge: 13103
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Pythagon: Das `Session`-Objekt ist übrigens ein Kontextmanager den man mit ``with`` benutzen kann/sollte. Ansonsten müsste man mit ``try``/``finally`` sicherstellen das die `close()`-Methode von der Sitzung aufgerufen wird, wenn man damit fertig ist.

Wie kommst Du darauf dass `DOMObj` etwas ist das irgendwie Inhalt hätte? Das hat immer den Wert `None`, denn die `feed()`-Methode hat keinen Rückgabewert. `DOMObj` ist auch falsch geschrieben, das müsste `dom_obj` heissen. Und dann kann man sich das `_obj` sparen. So etwas hat keinen Mehrwert weil *alles* was man in Python an einen Namen binden kann ist ein Objekt. Da hättest Du dann konsequenterweise auch `session_obj`, `parser_obj`, und `request_obj` schreiben müssen. Ich denke daran wird klar wie sinnfrei dieser Zusatz ist.

Der Parser macht gar nichts ausser Methoden auf sich selbst aufrufen die nichts machen. Die muss man in einer abgeleiteten Klasse überschreiben und sinnvoll auf die Aufrufe und Argumente reagieren. Das selbst machen zu wollen ist aber ziemlicher Unsinn, weil man sich am Ende `BeautifulSoup` selbst schreibt, nur in viel schlechter und mit weniger Möglichkeiten.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Pythagon
User
Beiträge: 52
Registriert: Mittwoch 3. Juli 2019, 18:21

__blackjack__ hat geschrieben: Mittwoch 10. Juli 2019, 21:19 @Pythagon: Das `Session`-Objekt ist übrigens ein Kontextmanager den man mit ``with`` benutzen kann/sollte. Ansonsten müsste man mit ``try``/``finally`` sicherstellen das die `close()`-Methode von der Sitzung aufgerufen wird, wenn man damit fertig ist.

Wie kommst Du darauf dass `DOMObj` etwas ist das irgendwie Inhalt hätte? Das hat immer den Wert `None`, denn die `feed()`-Methode hat keinen Rückgabewert. `DOMObj` ist auch falsch geschrieben, das müsste `dom_obj` heissen. Und dann kann man sich das `_obj` sparen. So etwas hat keinen Mehrwert weil *alles* was man in Python an einen Namen binden kann ist ein Objekt. Da hättest Du dann konsequenterweise auch `session_obj`, `parser_obj`, und `request_obj` schreiben müssen. Ich denke daran wird klar wie sinnfrei dieser Zusatz ist.

Der Parser macht gar nichts ausser Methoden auf sich selbst aufrufen die nichts machen. Die muss man in einer abgeleiteten Klasse überschreiben und sinnvoll auf die Aufrufe und Argumente reagieren. Das selbst machen zu wollen ist aber ziemlicher Unsinn, weil man sich am Ende `BeautifulSoup` selbst schreibt, nur in viel schlechter und mit weniger Möglichkeiten.
Diese Beschreibung der Feed Methode bringt mich zu der Annahme ich könne damit etwas an das Objekt übergeben:
HTMLParser.feed(data)

Feed some text to the parser. It is processed insofar as it consists of complete elements; incomplete data is buffered until more data is fed or close() is called. data must be str.
Was ist denn Deiner Aussage nach durch folgender Codezeile geschehen?
domObj = parser.feed(request.text)
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

HTMLParser ist ein Parser, das heißt, es teilt den übergebenen Text in seine Bestandteile. Mit diesen werden Methoden aufgerufen, die in der Basisklasse nichts machen. Deshalb mußt Du die Klasse ableiten und die Methoden implementieren, wie in der Dokumentation beispielhaft geschehen.
Benutzeravatar
__blackjack__
User
Beiträge: 13103
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Pythagon: Die Annahme das man der `feed()`-Methode Text übergeben kann ist ja auch korrekt, aber die Methode gibt halt nichts zurück. Also ist es sinnfrei den nicht vorhandenen (expliziten) Rückgabwert irgendeinem Namen zuzuweisen. Die gezeigte Codezeile ist äquivalent zu:

Code: Alles auswählen

parser.feed(request.text)
domObj = None
Die zweite Zeile kann man sich sparen, weil eben nicht wirklich sinnvoll.

Edit: Wo mir gerade auffällt das `request` falsch ist, denn das ist keine Anfrage sondern eine Antwort, also `response`.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Pythagon
User
Beiträge: 52
Registriert: Mittwoch 3. Juli 2019, 18:21

Ich bin nun eurem rat gefolgt und habe es mit BS versucht und es klappt ganz hervorragend. Vielen Dank für eure Unterstützung und die Zeit, die ihr euch genommen habt!

Beste Grüße
Antworten