7 points par GN⁺ 2024-09-03 | 1 commentaires | Partager sur WhatsApp
  • Expérimentation d’un scraper web assisté par IA utilisant les structured outputs de l’API OpenAI pour extraire des tableaux HTML en données structurées ; GPT-4o a montré une qualité d’extraction meilleure qu’attendu sur certains tableaux complexes
  • Sur des tableaux à structure d’affichage complexe comme les prévisions à 10 jours de Weather.com, il distingue les prévisions jour/nuit et retrouve même dans le code HTML source des valeurs invisibles à l’écran
  • Sur des tableaux comme le Human Development Index de Wikipedia, où des valeurs répétées apparaissent dans des lignes fusionnées, le nombre de valeurs par colonne ne correspondait pas, rendant la reconstruction du tableau difficile, et une simple modification du prompt n’a pas suffi
  • Pour réduire le coût des appels API, une tentative de génération de XPath a aussi été faite, mais les XPath produits étaient parfois erronés ou vides ; il était plus fiable d’extraire d’abord les données puis de demander les XPath à partir de ces valeurs
  • 24 $ ont été dépensés en deux jours d’expérimentation ; en réduisant les attributs HTML, le nombre de caractères a été divisé par deux sans baisse visible des performances, mais le coût a limité les validations supplémentaires

Extraction de tableaux HTML avec structured outputs

  • Un scraper web assisté par IA a été implémenté à l’aide de la fonctionnalité structured outputs de l’API OpenAI
  • La première expérimentation consistait à envoyer une chaîne HTML à GPT-4o et à lui demander d’extraire les données tabulaires sous une forme structurée
  • Le modèle Pydantic utilisé se compose de ParsedTable, qui contient le nom du tableau et la liste des colonnes, et de ParsedColumn, qui contient le nom d’une colonne et la liste de ses valeurs
  • Le prompt système lui attribuait le rôle d’un scraper web spécialisé dans l’extraction de données structurées à partir de tableaux HTML
  • GPT-4o mini a également été testé, mais les résultats étaient nettement moins bons ; les expériences suivantes ont donc été menées avec GPT-4o

Les points forts observés sur des tableaux complexes

  • Après des tableaux simples, le tableau de prévisions météo sur 10 jours de Weather.com a été utilisé comme entrée
  • Ce tableau comporte une grande ligne en haut, puis 9 autres jours sous forme de lignes plus petites
  • GPT-4o a reconnu la structure des prévisions jour/nuit sur les 9 jours restants et a ajouté une colonne Day/Night
  • Au départ, la colonne Condition extraite semblait relever de l’hallucination, mais une vérification du code HTML a montré qu’elle existait réellement dans des balises invisibles à l’écran

Échec face aux lignes fusionnées

  • Le tableau Human Development Index de Wikipedia semble simple en apparence, mais certaines lignes avec des valeurs répétées sont fusionnées, ce que GPT-4o n’a pas su traiter correctement
  • Le modèle a bien extrait les colonnes individuellement comme demandé, mais le nombre de valeurs différait selon les colonnes, rendant le résultat difficile à représenter sous forme de tableau
  • Le prompt système a été modifié avec une consigne du type « pour les lignes fusionnées, extraire plusieurs valeurs JSON afin que toutes les colonnes aient le même nombre de lignes », mais cela n’a pas fonctionné
  • Un prompt demandant une extraction par ligne plutôt que par colonne n’a pas encore été testé

Les limites de la génération de XPath

  • Comme appeler l’API OpenAI à chaque fois peut coûter cher, une tentative a été faite pour renvoyer des XPath au lieu des données extraites
  • L’objectif était de pouvoir re-récupérer les données mises à jour sur la même page via XPath, sans nouvel appel au modèle
  • Le prompt recevait le contenu HTML et les noms de colonnes, et devait renvoyer des chaînes XPath évaluables dans driver.find_elements(By.XPATH, xpath) de Selenium
  • Cette approche n’était pas fiable
    • GPT-4o renvoyait parfois des XPath incorrects
    • Mentionner Selenium dans le prompt a un peu aidé, mais certains XPath renvoyaient encore des données erronées ou aucun résultat

Combiner extraction des données et génération de XPath

  • L’essai suivant consistait à faire d’abord extraire les données par GPT-4o, puis à utiliser ce résultat comme valeurs de référence pour demander les XPath
  • Cette combinaison a bien mieux fonctionné que le fait de demander uniquement des XPath dès le départ
  • Il arrivait que les XPath générés ne renvoient aucun résultat ; une simple logique de nouvelle tentative a donc été ajoutée en cas d’échec
  • Sur les tableaux testés, cette stratégie de retry s’est révélée efficace
  • De nouveaux problèmes subsistent toutefois
    • Lors de la première étape d’extraction, il arrivait que des images soient converties en texte
    • Par exemple, une image de flèche vers le haut pouvait être extraite comme arrow-upwards
    • La deuxième étape cherchait alors un texte qui n’existait pas réellement dans le HTML, ce qui entraînait un échec
    • Ce problème n’a pas été corrigé séparément

Coût et nettoyage du HTML

  • Faire du scraping web avec GPT-4o peut vite devenir coûteux, car même un petit tableau HTML contient beaucoup de caractères
  • 24 $ ont déjà été dépensés en deux jours d’expérimentation
  • Pour réduire les coûts, une logique de nettoyage a été ajoutée afin de supprimer les données inutiles de la chaîne HTML avant son envoi au modèle
  • En supprimant tous les attributs sauf class, id et data-testid, qui étaient les plus souvent utilisés par les XPath générés, le nombre de caractères du tableau a été réduit de moitié
  • Aucune baisse de performance n’a été observée après ce nettoyage, et il est même jugé possible que la qualité d’extraction s’en trouve améliorée
  • À l’heure actuelle, l’étape de génération de XPath effectue un appel au modèle pour chaque colonne du tableau
  • Une amélioration consistant à générer plusieurs XPath en une seule fois serait possible, mais n’a pas encore été testée ni évaluée

Démo et pistes d’expérimentation supplémentaires

  • La qualité d’extraction de GPT-4o a été jugée impressionnante, mais le coût à payer à OpenAI l’a été tout autant
  • Une démo simple réalisée avec Streamlit est disponible sur https://orange-resonance-9766.ploomberapp.io
  • Le code source est publié sur GitHub, avec l’avertissement qu’il ne faut pas s’attendre à un outil très abouti
  • Davantage de tableaux auraient été testés, mais l’augmentation des coûts OpenAI a limité l’expérimentation à un petit nombre de cas
  • Avec plus de temps, les pistes suivantes seraient explorées
    • La démo actuelle est un processus ponctuel où l’utilisateur saisit une URL et un XPath initial ; une meilleure expérience utilisateur consisterait peut-être à laisser l’utilisateur cliquer sur le tableau à extraire et fournir des lignes d’exemple
    • Sur des tableaux complexes, il peut être difficile d’extraire une colonne entière avec un seul XPath ; il serait intéressant de tester une approche où le LLM renvoie un programme en Python, par exemple
    • Le coût d’utilisation de GPT-4o est élevé et beaucoup de données inutiles semblent être envoyées ; il serait donc utile d’expérimenter davantage les méthodes de nettoyage du HTML

1 commentaires

 
GN⁺ 2024-09-03
Avis sur Hacker News
  • Cela a le mieux fonctionné quand, au lieu d’envoyer directement le HTML au LLM, on le convertissait d’abord dans un format simple comme Markdown
    Parmi les outils que j’ai essayés, il y a Extractus https://github.com/extractus et dom-to-semantic-markdown https://github.com/romansky/dom-to-semantic-markdown
    Dans Magic Loops https://magicloops.dev/, qui tourne dans le cloud, on utilise Apify https://apify.com/ et Firecrawl https://www.firecrawl.dev/, et dans l’extension Chrome, on utilise dom-to-semantic-markdown
    Pour l’instant, on expérimente une approche qui génère des XPath propres à certains sites via un flux assisté par l’utilisateur, puis n’extrait que les éléments nécessaires avant l’appel au LLM ; en simplifiant le problème, GPT-4o mini donnait déjà des résultats plutôt corrects

    • Ce serait bien aussi de jeter un œil à ce que nous construisons : https://browserbase.com/
      Comme on peut exécuter une extension Chrome dans un navigateur headless, on peut faire la conversion en Markdown sémantique directement dans le navigateur avant de sortir les données
      Il existe aussi une vue temps réel du navigateur intégrable en iFrame, ce qui permet de recevoir immédiatement les retours de l’utilisateur sur le XPath en cours de génération : https://docs.browserbase.com/features/session-live-view#give...
    • Je me demande si vous avez comparé la conversion en Markdown avec une approche consistant simplement à supprimer les attributs des balises dans le HTML, déplier les liens et retirer les éléments non affichés
      D’après mon expérience, les performances étaient assez proches de Markdown, tandis que la transformation était plus simple et comportait moins de cas particuliers
    • Je n’avais jamais entendu parler de Semantic Markdown https://hackmd.io/@sparna/semantic-markdown-draft ; on dirait une façon d’intégrer des données RDF dans un document Markdown
      La page trouvée étant marquée “Alpha Draft”, il ne doit pas y avoir beaucoup de corpus de contenus en Semantic Markdown, et le manque de données d’entraînement pourrait même gêner la compréhension par les LLM
      Cela dit, le format reste suffisamment lisible, donc si le LLM traite les métadonnées structurées comme des explications entre parenthèses, il devrait pouvoir s’en sortir assez bien
    • J’ai fait quelque chose de similaire dans un autre contexte : j’ai d’abord converti un JSON complexe représentant un graphe d’exécution en un format Graphviz dot plus simple, puis je l’ai envoyé au LLM, et cela a plutôt bien marché
  • OpenAI a récemment annoncé la Batch API, qui permet de préparer tous les prompts puis de les exécuter par lots, avec un coût réduit de 50 % : https://platform.openai.com/docs/guides/batch
    Je l’ai beaucoup utilisée auparavant avec GPT-4o mini, et elle pouvait traiter 3 000 éléments en moins de 5 minutes
    Cela peut être assez intéressant pour les applications qui n’ont pas besoin de temps réel

    • J’aimerais que les serveurs d’inférence open source prennent bientôt en charge cet endpoint
      vLLM a ajouté une partie du support d’un “offline batch mode” au même format, mais n’en est pas encore à l’implémentation de l’endpoint OpenAI
    • La proposition d’OpenAI est bonne, mais comparée aux méthodes traditionnelles d’extraction de texte offrant une précision et un rappel similaires, je pense que cela reste encore environ un à deux ordres de grandeur plus cher
    • C’est une très bonne décision de la part d’OpenAI, et j’aimerais que d’autres outils cloud comme Azure proposent la même fonctionnalité
      C’est une fonctionnalité tellement naturelle
  • Pour du contenu structuré, par exemple des listes d’éléments ou des tableaux simples, on n’a pas vraiment besoin d’un LLM
    J’ai récemment créé un scraper web qui fonctionne automatiquement sur n’importe quel site https://easyscraper.com ; la version initiale utilisait l’IA, mais au final des heuristiques basées sur les attributs des éléments et leur position se sont révélées plus rapides, moins chères et plus précises
    Sur la plupart des sites web, les approches sans IA fonctionnent très bien ; il vaut donc mieux vérifier d’abord si l’IA est vraiment nécessaire, par exemple lorsque les données sont non structurées ou qu’il faut déduire le format de sortie à partir des données de la page

    • Les LLM résistent mieux aux mises à jour de sites web susceptibles de casser un scraping classique
      Comme l’auteur, on peut faire générer un XPath par le LLM, utiliser ensuite ce XPath pour le scraping classique au quotidien, puis demander au LLM de mettre à jour le XPath quand ça casse
      Et si les données ne circulent toujours pas, ou si une étape plus loin dans le pipeline casse à cause d’un format inattendu, on peut alors prévenir un humain
    • C’est la première fois que je vois un outil permettant de sélectionner directement ce qu’on veut scraper
      Je me suis toujours demandé pourquoi ce genre d’outil n’existait pas
  • Je me demande s’il existe déjà quelque chose comme un « HTML reducer »
    Quand on regarde le source d’une page tel quel, 90 % des tokens sont des déchets à cause du JavaScript aléatoire, des publicités, des attributs inutiles et d’une imbrication excessive destinée au rendu
    En parcourant le DOM avec un parseur et en ne gardant que les nœuds contenant du texte, la structure HTML et les attributs de balises nécessaires (du type class/id), on pourrait sans doute réduire fortement les coûts, et les approches XPath pourraient aussi mieux fonctionner
    J’utilise aussi Readability, mais on perd la structure du DOM, et la qualité baisse sur les sites très chargés en JavaScript ou les pages qui développent le texte avec des éléments comme « continue reading »
    Je me demande quel est l’outil le plus proche d’un standard pour cet usage

  • Je suis surpris que l’auteur ait fait 99 % du travail et de la rédaction, mais n’ait pas fait le dernier 1 % : télécharger un moteur basé sur ollama ou llama.cpp pour tester un bon LLM local
    Pour ce cas d’usage, des modèles 7B ou 30B pourraient très bien faire l’affaire, avec un coût d’exécution suffisamment faible pour que GPT-4o ne soit peut-être pas nécessaire

    • Bonne suggestion
      Je commence tout juste à manipuler les LLM, et je compte aussi regarder les modèles hébergés localement
  • Chez Kadoa https://kadoa.com, nous faisons du web scraping automatisé par IA, et nos premières expérimentations ressemblaient à ce qui est décrit dans l’article
    Nous avons commencé à l’époque où seul GPT-3, cher et lent, était disponible, et il nous fallait une solution rentable à grande échelle
    Au final, plutôt que d’utiliser un LLM à chaque extraction, nous avons opté pour la génération de code afin de produire des sélecteurs CSS ou du code d’extraction XPath, puis d’adapter ensuite le code du scraper aux changements des sites web
    Pour le nettoyage et la transformation, nous utilisons un petit LLM fine-tuné, et pour la validation, nous évaluons la qualité des données avec du LLM-as-a-judge, en complément de méthodes traditionnelles comme la recherche inversée
    L’appliquer à quelques sources de données simples et le faire tourner de manière fiable, scalable et rentable sur des milliers de sites web sont deux problèmes complètement différents ; la bonne approche a été de combiner de l’ingénierie ETL traditionnelle avec de petites étapes LLM bien évaluées

  • Donner un exemple du HTML à scraper et demander un bout de code BeautifulSoup a plutôt bien fonctionné
    En général, la structure que l’on veut récupérer reste stable, mais écrire soi-même la chaîne de parsing obscure qui va avec est fastidieux
    Confier le parsing réel au LLM est excessif, et il y a en plus un risque que des hallucinations contaminent le résultat

  • Prétraiter d’abord le HTML permet d’obtenir de meilleurs résultats à moindre coût
    Je crois que cela n’a pas encore été mentionné, mais personnellement j’ai obtenu de bons résultats avec trafilatura https://trafilatura.readthedocs.io/en/latest/

    • Gros +1 pour trafilatura
      Comme il suffit d’envoyer du texte au LLM, on peut réduire énormément les coûts
      Je l’ai aussi utilisé dans un projet récent, https://github.com/philippe2803/contentmap, une petite bibliothèque Python qui prend comme point de départ le sitemap XML d’un domaine pour créer un stockage vectoriel pour n’importe quel site web
      Comme la structure HTML varie d’un domaine à l’autre, il fallait extraire uniquement le contenu réel et supprimer les balises HTML, etc. ; Trafilatura le fait pour presque toutes les URL en quelques lignes de code
  • C’est la première fois que je vois un article avec autant de tags orange
    Chez NewsCatcher, nous faisons beaucoup de tests avec GPT-4o, et nous devons explorer plus de 100 000 sites d’actualité, puis parser le contenu des articles
    Un modèle à base de règles pour extraire les données de n’importe quel article fonctionnait plutôt bien, et nous n’avons pas trouvé comment l’améliorer avec GPT
    Le plus intéressant, c’est plutôt le crawling : il faut connaître tous les endroits où des articles peuvent être publiés, et il y a parfois plus de 50 sous-sections
    Comme la structure propre à chaque site web ne change pas souvent, je pense que, pour beaucoup de projets, générer le code d’extraction peut suffire
    Nous nous intéressons donc à la génération de code de parsing HTML avec des LLM ; si cela vous intéresse, contactez artem [at] newscatcherapi.com

    • J’aimerais essayer ça dans un projet perso
      Ce serait bien s’il y avait une inscription en libre-service
  • Le web scraping a été la vraie raison qui a poussé mon cofondateur et moi à créer openpipe.ai
    GPT-4 est vraiment très bon pour ça, mais il coûte trop cher
    Cela dit, il est assez facile de distiller la capacité à scraper certains types de sites dans un modèle fine-tuné beaucoup moins cher, et sur ce type de sites, il scrape de façon fiable

    • Kyle, j’aurais dû t’en parler plus tôt
      Nous travaillons aussi sur ce problème depuis un bon moment, et je te contacterai pour te montrer où nous en sommes