llm-scraper : extraire des données structurées d'une page web avec un schéma Zod
Turn any webpage into structured data using LLMs
En bref
- De quoi s’agit-il ?
- La bibliothèque TypeScript de mishushakov combine Playwright et un modèle de langage pour produire un objet conforme à un schéma, avec six formats d'entrée et une fonction de génération de script. Son intérêt réel dépend de la stabilité des pages que vous ciblez.
- À qui s’adresse-t-il ?
- llm-scraper convient aux équipes TypeScript qui doivent extraire des données d'un petit nombre de pages dont la structure change souvent, et qui acceptent de payer un appel de modèle par extraction. Il ne convient pas à un crawl à grande échelle, où un parseur CSS reste moins cher et déterministe.
- Puis-je l’utiliser commercialement ?
- Oui. MIT est une licence permissive : vous pouvez utiliser, modifier et vendre un logiciel qui en dépend, à condition de conserver les mentions de droit d’auteur et de licence.
- Est-il encore maintenu ?
- Oui. Les derniers commits datent d’il y a 6 jours.
- En quel langage est-il écrit ?
- Principalement TypeScript, d’après les statistiques de langage de GitHub.
Ces réponses reposent sur les données GitHub du projet (dernière synchronisation le 15 septembre 2026) et sur notre analyse. Elles ne constituent pas un avis juridique.
ANALYSE OPEN SOURCE APPROFONDIE
Le problème : un schéma Zod au lieu d'un sélecteur CSS
Un scraper classique encode la structure de la page dans des sélecteurs CSS. Le jour où le site change de gabarit, le sélecteur casse et il faut le réécrire. llm-scraper déplace le contrat : vous décrivez la forme des données attendues dans un schéma Zod, et le modèle de langage se charge de faire correspondre le contenu de la page à cette forme. Le README donne l'exemple d'un schéma qui décrit un tableau de cinq objets, chacun avec un titre, un nombre de points, un auteur et une URL de commentaires. Le champ est annoté avec describe, ce qui sert d'indication au modèle. Ce choix a une conséquence directe : la robustesse ne vient plus du sélecteur mais de la capacité du modèle à comprendre une page qu'il n'a jamais vue. C'est utile quand la mise en page bouge, coûteux quand elle ne bouge pas. La bibliothèque vise donc les développeurs TypeScript qui extraient des données depuis une poignée de pages, pas ceux qui alimentent un entrepôt à partir de milliers de domaines.
Playwright charge la page, le SDK AI produit l'objet
Le flux est explicite dans le README. Vous lancez un navigateur avec chromium.launch() de Playwright, vous ouvrez une page, vous appelez page.goto() sur l'URL cible. Vous instanciez ensuite LLMScraper avec un modèle du SDK AI, puis vous appelez scraper.run(page, Output.object({ schema }), { format: 'html' }). La fonction renvoie un objet dont le champ data contient la sortie déjà validée par le schéma. Playwright fournit le rendu, y compris JavaScript, et le modèle fait la lecture. Six modes de formatage déterminent ce qui est envoyé au modèle : html pour du HTML prétraité, raw_html sans traitement, markdown, text via Readability.js, image pour une capture d'écran en mode multimodal, et custom pour une fonction maison. Ce paramètre est le vrai levier de coût et de qualité. Le mode text réduit fortement la taille du contexte, le mode image l'augmente et exige un modèle multimodal. La documentation ne chiffre aucun de ces compromis, ce qui laisse le réglage à l'expérimentation.
Installation et fournisseurs de modèles
L'installation de base tient en une commande : npm i zod playwright llm-scraper. Le fournisseur se choisit séparément. Pour OpenAI, npm i @ai-sdk/openai puis openai('gpt-4o'). Pour Anthropic, npm i @ai-sdk/anthropic puis anthropic('claude-3-5-sonnet-20240620'). Pour Google, npm i @ai-sdk/google puis google('gemini-1.5-flash'). Groq passe par le paquet OpenAI avec une URL de base personnalisée : createOpenAI({ baseURL: 'https://api.groq.com/openai/v1', apiKey: process.env.GROQ_API_KEY }), puis groq('llama3-8b-8192'). Ollama passe par ollama-ai-provider-v2 et ollama('llama3'). La clé d'API se lit depuis l'environnement, comme le montre GROQ_API_KEY. La liste des modèles cités dans le README couvre les séries GPT, Sonnet, Gemini, Llama et Qwen. Toute la configuration tient donc dans le choix du paquet de fournisseur et dans la chaîne passée au constructeur. Rien dans le matériel fourni ne décrit de fichier de configuration propre à llm-scraper : il n'y en a pas.
Streaming et génération de code : deux usages distincts
Deux fonctions accompagnent run. La première, stream, remplace run pour obtenir un flux d'objets partiels. Le README donne la boucle for await (const data of stream) et affiche data.top à chaque itération. Cela sert à afficher un résultat progressif dans une interface, pas à accélérer l'extraction : le coût de l'appel au modèle reste identique. La seconde, generate, produit un script Playwright réutilisable à partir du même schéma. L'exemple enchaîne const { code } = await scraper.generate(...), puis page.evaluate(code), puis schema.parse(result). L'idée est de transformer une extraction par modèle en un parseur déterministe exécuté dans la page. C'est la partie la plus intéressante du projet, et aussi la moins documentée : le README ne dit pas ce qui se passe quand le script généré échoue sur une page dont le DOM a changé depuis. Aucune stratégie de repli n'est décrite. À traiter comme une piste à valider sur vos propres pages, pas comme une garantie.
Ce que la bibliothèque ne promet pas
Le point faible est structurel : chaque extraction est un appel de modèle, avec un coût par page et une latence qui n'a rien à voir avec un parseur HTML local. Sur un site stable et volumineux, un sélecteur CSS reste plus rapide, moins cher et parfaitement reproductible. Le README ne mentionne ni cache, ni mécanisme de repli vers un parseur classique, ni gestion des erreurs de validation quand le modèle renvoie un objet non conforme. Il ne décrit pas non plus de stratégie pour les pages derrière une authentification, les CAPTCHA ou les rendus fortement dynamiques, au-delà du fait que Playwright est à la base. Le choix du format d'entrée devient donc un arbitrage que vous portez seul : envoyer du HTML brut à un grand modèle coûte cher en jetons, envoyer du texte via Readability.js peut supprimer l'information dont dépend votre schéma. Enfin, rien n'indique dans le matériel fourni comment la bibliothèque se comporte face à une page qui ne contient pas les données demandées : le schéma Zod valide la forme, pas la véracité des valeurs extraites.
Face à un pipeline classique d'extraction
L'alternative la plus directe n'est pas un autre outil d'IA mais l'approche sans modèle : Playwright seul, avec des sélecteurs et un parseur comme Cheerio ou l'API DOM, plus éventuellement Readability.js pour isoler le contenu principal. La différence n'est pas une question de qualité mais de nature du contrat. Un pipeline à sélecteurs est déterministe : la même page donne le même résultat, l'échec est un sélecteur introuvable, visible immédiatement. llm-scraper déplace l'échec vers la validation du schéma, ce qui est plus difficile à diagnostiquer puisque le modèle peut produire un objet valide avec des valeurs fausses. En contrepartie, il absorbe les changements de gabarit sans intervention. La bonne question n'est donc pas lequel est meilleur, mais à quelle fréquence vos pages changent. Si la réponse est rarement, le coût par appel de modèle est difficile à justifier. Si la réponse est souvent, la maintenance des sélecteurs devient le poste principal et l'arbitrage s'inverse.
Licence, maintenance et coût de mise à jour
Le dépôt est publié sous licence MIT, ce qui autorise l'usage commercial, la modification et la redistribution avec conservation de la mention de licence. Le matériel fourni ne contient aucune information sur les droits des modèles appelés : ceux-ci relèvent de vos propres accords avec OpenAI, Anthropic, Google, Groq ou de l'exécution locale via Ollama. Ce point compte, car la bibliothèque n'est qu'un intermédiaire. La version 2.0 a introduit le support du SDK AI 6 et mis à jour les exemples, ce qui signifie que le passage depuis une version antérieure implique probablement de revoir l'initialisation du modèle, puisque le README montre désormais Output.object({ schema }) comme second argument de run. Aucune version publiée n'apparaît dans les informations récupérées, donc aucun cycle de publication ne peut être déduit. Le coût de maintenance se situe ailleurs : chaque montée de version majeure du SDK AI, de Playwright ou de Zod peut toucher votre code d'appel, et la bibliothèque ne contrôle aucun de ces trois composants.
Conclusion éditoriale
llm-scraper convient aux équipes TypeScript qui doivent extraire des données d'un petit nombre de pages dont la structure change souvent, et qui acceptent de payer un appel de modèle par extraction. Il ne convient pas à un crawl à grande échelle, où un parseur CSS reste moins cher et déterministe. Avant d'adopter, vérifiez trois points dans le dépôt : le contenu du dossier examples, le comportement de la fonction generate sur vos propres pages, et la manière dont la version 2.0 traite les schémas Zod complexes.
Notes de la communauté