Web Scraping mit GPT-4o: leistungsstark, aber teuer
(blancas.io)- Es wurde ein KI-gestützter Web Scraper erprobt, der mit den structured outputs der OpenAI API HTML-Tabellen als strukturierte Daten extrahiert; GPT-4o zeigte bei einigen komplexen Tabellen eine bessere Extraktionsqualität als erwartet
- Bei Tabellen mit komplexer Darstellungsstruktur, etwa der 10-Tage-Vorhersage von Weather.com, unterschied GPT-4o zwischen Tages- und Nachtvorhersagen und fand auch Werte im HTML-Quelltext, die auf dem Bildschirm nicht sichtbar waren
- Bei Tabellen wie dem Human Development Index auf Wikipedia, in denen wiederholte Werte in zusammengeführten Zeilen stehen, geriet die Anzahl der Werte pro Spalte auseinander, wodurch sich die Tabelle nur schwer rekonstruieren ließ; allein durch Prompt-Anpassungen ließ sich das nicht lösen
- Um API-Aufrufkosten zu senken, wurde auch die XPath-Erzeugung ausprobiert, doch dabei entstanden falsche XPaths oder solche mit leeren Ergebnissen; stabiler war es, zuerst die Daten zu extrahieren und anschließend anhand dieser Werte XPaths anzufordern
- Für zwei Tage Experimente wurden 24 $ ausgegeben; durch das Reduzieren von HTML-Attributen halbierte sich die Zeichenanzahl, ohne sichtbaren Leistungsabfall, doch wegen der Kosten blieb die weitere Validierung begrenzt
HTML-Tabellen mit structured outputs extrahieren
- Mit der Funktion structured outputs der OpenAI API wurde ein KI-gestützter Web Scraper implementiert
- Im ersten Experiment wurde ein HTML-String an GPT-4o übergeben und das Modell gebeten, Tabellendaten in strukturierter Form zu extrahieren
- Das verwendete Pydantic-Modell bestand aus
ParsedTable, das den Tabellennamen und eine Spaltenliste enthält, sowieParsedColumn, das Spaltenname und Werteliste enthält - Im System-Prompt erhielt das Modell die Rolle eines spezialisierten Web Scrapers, der strukturierte Daten aus HTML-Tabellen extrahiert
- GPT-4o mini wurde ebenfalls ausprobiert, lieferte aber deutlich schlechtere Ergebnisse; die weiteren Experimente wurden daher mit GPT-4o durchgeführt
Stärken bei komplexen Tabellen
- Nach einer einfachen Tabelle wurde die Tabelle der 10-Tage-Wettervorhersage von Weather.com eingegeben
- Diese Tabelle hat oben eine große Zeile, während die übrigen 9 Tage aus kleineren Zeilen bestehen
- GPT-4o erkannte die Struktur aus Tages- und Nachtvorhersagen für die übrigen 9 Tage und fügte eine
Day/Night-Spalte hinzu - Die zunächst extrahierte Spalte
Conditionwirkte wie eine Halluzination, existierte nach Prüfung des HTML-Quelltexts aber tatsächlich als nicht sichtbarer Tag
Fehler bei zusammengeführten Zeilen
- Die Tabelle zum Human Development Index auf Wikipedia wirkt äußerlich einfach, enthält aber Zeilen mit wiederholten Werten, die zusammengeführt sind, was GPT-4o nicht korrekt verarbeiten konnte
- Das Modell extrahierte wie angewiesen einzelne Spalten, doch jede Spalte hatte eine unterschiedliche Anzahl von Werten, sodass sich das Ergebnis nur schwer als Tabelle darstellen ließ
- Der System-Prompt wurde in etwa zu „Extrahiere zusammengeführte Zeilen als mehrere JSON-Werte, damit alle Spalten die gleiche Zeilenanzahl haben“ geändert, doch das funktionierte nicht
- Ein Prompt, der statt Spalten eine zeilenweise Extraktion anweist, wurde noch nicht ausprobiert
Grenzen der XPath-Erzeugung
- Da wiederholte Aufrufe der OpenAI API teuer werden können, wurde versucht, statt der extrahierten Daten XPath zurückzugeben
- Ziel war es, aktualisierte Daten von derselben Seite erneut per XPath zu scrapen, ohne das Modell aufzurufen
- Der Prompt war so aufgebaut, dass er HTML-Inhalt und Spaltennamen erhält und einen XPath-String zurückgibt, der in Seleniums
driver.find_elements(By.XPATH, xpath)ausgewertet werden kann - Dieser Ansatz war nicht stabil
- GPT-4o gab mitunter falsche XPaths zurück
- Die Erwähnung von Selenium in der Formulierung entschärfte das teilweise, dennoch entstanden auch XPaths, die falsche Daten oder leere Ergebnisse zurückgaben
Datenextraktion und XPath-Erzeugung kombinieren
- Der nächste Versuch bestand darin, GPT-4o zuerst Daten extrahieren zu lassen und diese Ergebnisse als Referenzwerte für die XPath-Anfrage zu verwenden
- Diese Kombination funktionierte deutlich besser als der Ansatz, von Anfang an nur XPath anzufordern
- Da erzeugte XPaths gelegentlich keine Ergebnisse lieferten, wurde eine einfache Retry-Logik ergänzt, die bei ausbleibenden Ergebnissen erneut versucht
- Bei den getesteten Tabellen war diese Retry-Methode wirksam
- Es bleiben aber neue Probleme
- Die Datenextraktion im ersten Schritt wandelte Bilder gelegentlich in Text um
- Beispielsweise konnte ein Pfeil-nach-oben-Bild als Text wie
arrow-upwardsextrahiert werden - Im zweiten Schritt wurde dann nach Text gesucht, der im tatsächlichen HTML nicht vorkommt, was zum Scheitern führte
- Dieses Problem wurde nicht gesondert behoben
Kosten und HTML-Bereinigung
- Web Scraping mit GPT-4o kann teuer werden, da selbst kleine HTML-Tabellen viele Zeichen enthalten können und damit Kosten verursachen
- In zwei Tagen Experimentieren wurden bereits 24 $ ausgegeben
- Um die Kosten zu senken, wurde eine Bereinigungslogik ergänzt, die vor der Übergabe an das Modell unnötige Daten aus dem HTML-String entfernt
- Nachdem alle Attribute außer den von den erzeugten XPaths hauptsächlich verwendeten
class,idunddata-testidentfernt wurden, halbierte sich die Zeichenanzahl der Tabelle - Nach dieser Bereinigung war kein Leistungsabfall zu erkennen; möglicherweise verbessert sich die Extraktionsqualität dadurch sogar tatsächlich
- Der aktuelle Schritt zur XPath-Erzeugung führt pro Tabellenspalte jeweils einen Modellaufruf aus
- Eine Verbesserung, bei der mehrere XPaths auf einmal erzeugt werden, wäre möglich, wurde aber noch nicht ausprobiert oder hinsichtlich der Leistung bewertet
Demo und Ideen für weitere Experimente
- Die Extraktionsqualität von GPT-4o war beeindruckend, zugleich fühlten sich die an OpenAI zu zahlenden Kosten hoch an
- Eine einfache mit Streamlit erstellte Demo ist unter https://orange-resonance-9766.ploomberapp.io verfügbar
- Der Quellcode ist auf GitHub veröffentlicht, mit dem Hinweis, kein ausgereiftes Tool zu erwarten
- Es sollten eigentlich mehr Tabellen getestet werden, doch wegen steigender OpenAI-Kosten wurden nur wenige Tabellen ausprobiert
- Wenn mehr Zeit verfügbar wäre, wären folgende Versuche geplant
- Die aktuelle Demo ist ein einmaliger Prozess, bei dem Nutzer URL und initiales XPath eingeben; eine bessere User Experience könnte darin bestehen, dass Nutzer die zu extrahierende Tabelle anklicken und Beispielzeilen bereitstellen
- Bei komplexen Tabellen kann es schwierig sein, eine ganze Spalte mit nur einem XPath zu extrahieren; daher wäre es interessant, zu testen, ob das LLM ein Programm etwa in Python zurückgeben kann
- Da die Nutzung von GPT-4o teuer ist und offenbar viele unnötige Daten übergeben werden, sollten weitere Ansätze zur HTML-Bereinigung ausprobiert werden
1 Kommentare
Meinungen auf Hacker News
Am besten funktionierte es, HTML nicht direkt in ein LLM zu geben, sondern es zuerst in ein einfacheres Format wie Markdown umzuwandeln.
Als Tools habe ich unter anderem Extractus https://github.com/extractus und dom-to-semantic-markdown https://github.com/romansky/dom-to-semantic-markdown ausprobiert.
In Magic Loops https://magicloops.dev/, das in der Cloud läuft, verwenden wir intern Apify https://apify.com/ und Firecrawl https://www.firecrawl.dev/; in der Chrome Extension nutzen wir dom-to-semantic-markdown.
Derzeit experimentieren wir damit, in einem nutzerunterstützten Flow XPaths für bestimmte Sites zu erzeugen und vor dem LLM-Aufruf nur die benötigten Elemente herauszuziehen; durch die Vereinfachung des Problems war selbst GPT-4o mini ziemlich brauchbar.
Dort kann man Chrome Extensions in einem Headless Browser ausführen, sodass die semantische Markdown-Umwandlung im Browser stattfinden kann, bevor die Daten nach außen gegeben werden.
Außerdem gibt es eine iFrame-fähige Live-Ansicht des Browsers, sodass Nutzer sofort Feedback zum gerade erzeugten XPath geben können: https://docs.browserbase.com/features/session-live-view#give...
Meiner Erfahrung nach war die Performance ziemlich ähnlich wie bei Markdown, die Umwandlung war aber einfacher und hatte weniger Sonderfälle.
Die gefundene Seite ist ein „Alpha Draft“, daher dürfte es nicht besonders viele Semantic-Markdown-Inhaltskorpora geben, und der Mangel an Trainingsdaten könnte das Verständnis durch LLMs eher behindern.
Trotzdem ist es ein gut lesbares Format, und wenn ein LLM die strukturierten Metadaten wie erläuternde Klammerzusätze behandelt, könnte es damit ziemlich gut umgehen.
OpenAI hat kürzlich die Batch API angekündigt, mit der man alle Prompts vorbereiten und dann gesammelt ausführen kann; die Kosten sinken dabei ebenfalls auf 50 %: https://platform.openai.com/docs/guides/batch
Ich habe sie früher viel mit GPT-4o mini genutzt und konnte 3.000 Elemente in unter 5 Minuten verarbeiten.
Für Anwendungen, die keine Echtzeitverarbeitung brauchen, kann das ziemlich gut sein.
vLLM hat teilweise Unterstützung für einen „offline batch mode“ im selben Format hinzugefügt, ist aber noch nicht bei einer OpenAI-Endpunkt-Implementierung angekommen.
Es ist eine sehr naheliegende Funktion.
Für strukturierte Inhalte, etwa Listen von Einträgen oder einfache Tabellen, braucht man nicht unbedingt ein LLM.
Ich habe kürzlich einen Web Scraper gebaut, der automatisch auf jeder Website funktioniert: https://easyscraper.com. Die frühe Version war mit AI gebaut, aber am Ende waren Heuristiken auf Basis von Elementattributen und Positionen schneller, günstiger und genauer.
Auf den meisten Websites funktionieren Nicht-AI-Ansätze sehr gut; daher sollte man zuerst prüfen, ob AI wirklich nötig ist, etwa wenn die Daten unstrukturiert sind oder das Ausgabeformat aus den Seitendaten abgeleitet werden muss.
Wie der Autor kann man ein LLM XPaths erzeugen lassen, im Normalfall mit diesen XPaths klassisch scrapen und bei einem Bruch das LLM die XPaths aktualisieren lassen.
Wenn die Daten dann trotzdem nicht wieder fließen oder die Pipeline weiter hinten wegen eines unerwarteten Formats bricht, kann man immer noch einen Menschen benachrichtigen.
Ich habe mich immer gefragt, warum es so ein Tool nicht gibt.
Ich frage mich, ob es so etwas wie einen „HTML reducer“ bereits gibt
Wenn man sich den Seitenquelltext unverändert ansieht, bestehen 90 % der Tokens aus Müll: zufälligem JavaScript, Werbung, unnötigen Attributen und übermäßiger Verschachtelung fürs Rendering
Wenn man mit einem DOM-Parser hindurchläuft und nur Knoten mit Text, die HTML-Struktur und benötigte Tag-Attribute (etwa class/id) übrig lässt, ließen sich die Kosten wohl stark senken, und auch XPath-Ansätze könnten besser funktionieren
Readability wird zwar ebenfalls genutzt, verliert aber die DOM-Struktur, und bei Websites mit viel JavaScript oder Seiten, die Text per „continue reading“ erweitern, sinkt die Qualität
Ich frage mich, welches Tool für diesen Zweck quasi als Standard gilt
Bei Interesse könnten wir es als Open Source veröffentlichen, und es war erstaunlich, wie viel besser die LLM-Ausgabe nach dem Reducer wurde
Wenn man vor eine beliebige URL https://r.jina.ai/ setzt, bekommt man eine Markdown-Version der wichtigsten Inhalte dieser Seite zurück, die sich gut in ein LLM geben lässt
Ein Beispiel ist https://r.jina.ai/https://simonwillison.net/2024/Sep/2/anato..., die Originalseite ist https://simonwillison.net/2024/Sep/2/anatomy-of-a-textual-us...
Der Code ist Open Source und kann selbst ausgeführt werden: https://github.com/jina-ai/reader
Er ist in TypeScript geschrieben und nutzt Puppeteer sowie https://github.com/mozilla/readability
Ich habe nur Readability ohne Markdown-Konvertierung genutzt, um Seitentitel und Haupttext zu extrahieren, und es gibt auch ein Rezept, um das mit Playwright und shot-scraper auszuführen: https://shot-scraper.datasette.io/en/stable/javascript.html#...
Der Ansatz wurde von vimium übernommen und angepasst; er destilliert HTML so, dass nur die wichtigen Teile übrig bleiben, und behandelt dabei auch diverse Ausnahmefälle
Es überrascht mich, dass der Autor 99 % der Arbeit und des Schreibens erledigt hat, aber nicht das letzte 1 %: eine ollama- oder llama.cpp-basierte Engine herunterzuladen und ein ordentliches lokales LLM zu testen
Für diesen Anwendungsfall könnten auch 7B- oder 30B-Modelle gut funktionieren, und die Ausführungskosten wären niedrig genug, sodass GPT-4o möglicherweise gar nicht nötig ist
Ich fange gerade erst an, mit LLMs herumzuspielen, und werde mir auch lokal gehostete Modelle ansehen
Bei Kadoa https://kadoa.com haben wir automatisches Web-Scraping mit KI betrieben, und die frühen Experimente ähnelten dem Artikel
Wir haben angefangen, als es nur das teure und langsame GPT-3 gab, und brauchten eine kosteneffiziente Lösung im großen Maßstab
Am Ende haben wir in der Extraktionsphase nicht jedes Mal ein LLM eingesetzt, sondern per Codegenerierung CSS-Selektoren oder XPath-Extraktionscode erzeugt und den Scraper-Code anschließend an Website-Änderungen anpassen lassen
Für Bereinigung und Transformation nutzten wir ein kleines feinabgestimmtes LLM, und für die Validierung bewerteten wir die Datenqualität mit LLM-as-a-judge zusammen mit traditionellen Methoden wie Reverse Search
Das auf ein paar einfache Datenquellen anzuwenden und es zuverlässig, skalierbar und kosteneffizient über Tausende Websites hinweg zu betreiben, waren völlig verschiedene Probleme; die richtige Lösung war eine Mischung aus traditionellem ETL-Engineering und kleinen, gut evaluierten LLM-Schritten
Wenn man ein Beispiel des HTML gibt, das man scrapen möchte, und nach einem BeautifulSoup-Codefragment fragt, funktioniert das ziemlich gut
Meist bleibt die Struktur, die man auslesen will, unverändert; den kniffligen String zum Parsen dafür selbst zu schreiben, ist aber mühsam
Das eigentliche Parsen einem LLM zu überlassen, ist übertrieben und birgt zudem das Risiko, dass Halluzinationen die Ergebnisse verunreinigen
Wenn man HTML zuerst vorverarbeitet, bekommt man günstigere und bessere Ergebnisse
Ich glaube, es wurde noch nicht erwähnt, aber persönlich habe ich mit trafilatura https://trafilatura.readthedocs.io/en/latest/ gute Ergebnisse erzielt
Man muss dem LLM nur den Text schicken und kann die Kosten dadurch enorm senken
Ich habe es auch in einem aktuellen Projekt verwendet: https://github.com/philippe2803/contentmap. Das ist eine einfache Python-Bibliothek, die ausgehend von der Domain-XML-Sitemap einen Vektorspeicher für beliebige Websites erstellt
Da die HTML-Struktur je nach Domain unterschiedlich ist, mussten nur die eigentlichen Inhalte extrahiert und HTML-Tags usw. entfernt werden; Trafilatura erledigt das mit wenigen Codezeilen für fast jede URL
Das ist wohl der erste Beitrag, den ich sehe, der so viele orangefarbene Tags hat.
Bei NewsCatcher führen wir viele Tests mit GPT-4o durch; wir crawlen mehr als 100.000 News-Websites und müssen anschließend die News-Inhalte parsen.
Ein regelbasiertes Modell, das aus beliebigen Artikeln Daten extrahiert, funktionierte ziemlich gut, und wir haben keinen Weg gefunden, es mit GPT weiter zu verbessern.
Spannender ist der Bereich Crawling: Man muss alle Stellen kennen, an denen News-Artikel veröffentlicht werden können, und manchmal gibt es mehr als 50 Unterbereiche.
Da sich die Struktur einzelner Websites nicht häufig ändert, denke ich, dass es für viele Projekte ausreichen kann, Extraktionscode generieren zu lassen.
Deshalb schauen wir uns an, mit LLMs HTML-Parsing-Code zu generieren; wer Interesse hat, kann sich unter artem [at] newscatcherapi.com melden.
Es wäre schön, wenn es eine Self-Service-Registrierung gäbe.
Web Scraping war tatsächlich der Anlass, aus dem mein Mitgründer und ich das heutige openpipe.ai gebaut haben.
GPT-4 ist wirklich sehr gut darin, aber viel zu teuer.
Allerdings lässt sich die Fähigkeit, bestimmte Arten von Websites zu scrapen, ziemlich leicht in ein deutlich günstigeres Fine-Tuning-Modell distillieren, und für diese Art von Websites scraped es zuverlässig gut.
Wir beschäftigen uns auch schon ziemlich lange mit diesem Problem und ich melde mich, um zu zeigen, wie weit wir gekommen sind.