Données & IA

    LLM-Based Parsing

    Mis à jour le 1 février 2026

    Définition

    Le LLM-Based Parsing utilise des modèles de langage pour extraire des données structurées depuis du HTML brut ou du texte. Au lieu de sélecteurs CSS fragiles, le LLM comprend sémantiquement le contenu et extrait les champs demandés. Cette approche est plus résiliente aux changements de structure des sites.

    Deep Dive

    LLM Parsing : quand l'IA remplace les sélecteurs CSS

    Comparatif des approches

    | Aspect | Sélecteurs CSS/XPath | LLM Parsing |

    |--------|---------------------|-------------|

    | Précision | Haute (si bien ciblés) | Variable (95%+) |

    | Résilience | Fragile aux changements | Très résiliente |

    | Coût | Minimal | Tokens LLM |

    | Vitesse | Très rapide | Plus lent |

    | Setup | Configuration par site | Prompt universel |

    Cas d'usage idéaux

    1. **Sites changeants** : E-commerce avec A/B testing fréquent

    2. **Contenu non-structuré** : Articles, reviews, forums

    3. **Extraction sémantique** : Sentiment, entités, relations

    4. **Prototypage rapide** : POC sans développement

    Architecture typique

    ```

    HTML brut → Simplification (readability) → Prompt LLM → Parsing JSON → Validation

    ```

    Optimisations de coût

  1. Utiliser des modèles plus petits (GPT-4 mini, Claude Haiku)
  2. Simplifier le HTML avant envoi (supprimer scripts, styles)
  3. Batching : plusieurs extractions par appel
  4. Cache : même structure = même résultat
  5. Code Playground

    Extracteur LLM avec simplification HTML, validation Pydantic et fallback sur parsing traditionnel

    python
    # Extraction de données par LLM avec validation Pydantic
    from pydantic import BaseModel, Field
    from typing import List, Optional
    import json
    # from openai import OpenAI
    
    class ExtractedProduct(BaseModel):
        """Schéma de validation pour les produits extraits"""
        name: str = Field(description="Nom du produit")
        price: float = Field(description="Prix en euros")
        description: Optional[str] = Field(description="Description courte")
        availability: bool = Field(description="Disponibilité en stock")
        rating: Optional[float] = Field(ge=0, le=5, description="Note sur 5")
    
    class LLMExtractor:
        """Extracteur de données basé sur LLM avec fallback"""
        
        def __init__(self, model: str = "gpt-4o-mini"):
            self.model = model
            # self.client = OpenAI()
        
        def simplify_html(self, html: str) -> str:
            """Simplifie le HTML pour réduire les tokens"""
            from selectolax.parser import HTMLParser
            
            tree = HTMLParser(html)
            
            # Supprimer les éléments non-pertinents
            for tag in ['script', 'style', 'nav', 'footer', 'iframe', 'noscript']:
                for node in tree.css(tag):
                    node.decompose()
            
            # Supprimer les attributs sauf class et id
            for node in tree.css('*'):
                for attr in list(node.attributes.keys()):
                    if attr not in ['class', 'id', 'href', 'src', 'data-price']:
                        node.attrs.pop(attr, None)
            
            return tree.html
        
        def extract_product(self, html: str) -> ExtractedProduct:
            """Extrait un produit depuis du HTML via LLM"""
            simplified = self.simplify_html(html)
            
            prompt = f'''Extrait les informations du produit depuis ce HTML.
    Retourne UNIQUEMENT un objet JSON valide avec ces champs:
    - name (string): nom du produit
    - price (number): prix en euros (nombre, pas de symbole)
    - description (string ou null): description courte
    - availability (boolean): true si en stock
    - rating (number ou null): note sur 5
    
    HTML:
    {simplified[:8000]}  # Limiter pour éviter overflow
    
    JSON:'''
            
            # En production:
            # response = self.client.chat.completions.create(
            #     model=self.model,
            #     messages=[{"role": "user", "content": prompt}],
            #     temperature=0,  # Déterminisme
            #     response_format={"type": "json_object"}
            # )
            # json_str = response.choices[0].message.content
            
            # Placeholder
            json_str = '{"name": "Product", "price": 99.99, "availability": true}'
            
            # Validation avec Pydantic
            data = json.loads(json_str)
            return ExtractedProduct(**data)
        
        def extract_with_fallback(self, html: str) -> ExtractedProduct:
            """Extraction avec fallback sur parsing traditionnel"""
            try:
                return self.extract_product(html)
            except Exception as e:
                print(f"LLM extraction failed: {e}")
                return self._fallback_extraction(html)
        
        def _fallback_extraction(self, html: str) -> ExtractedProduct:
            """Fallback vers extraction par sélecteurs"""
            from selectolax.parser import HTMLParser
            import re
            
            tree = HTMLParser(html)
            
            name = tree.css_first('h1')
            price_elem = tree.css_first('[data-price], .price')
            
            price = 0.0
            if price_elem:
                price_match = re.search(r'[d,]+.?d*', price_elem.text())
                if price_match:
                    price = float(price_match.group().replace(',', ''))
            
            return ExtractedProduct(
                name=name.text(strip=True) if name else "Unknown",
                price=price,
                description=None,
                availability=True,
                rating=None
            )
    
    # Usage avec batch processing
    async def batch_extract(urls: List[str], extractor: LLMExtractor) -> List[ExtractedProduct]:
        """Extraction batch avec rate limiting"""
        import asyncio
        import httpx
        
        results = []
        semaphore = asyncio.Semaphore(5)  # Limite concurrence LLM
        
        async with httpx.AsyncClient() as client:
            async def process_one(url):
                async with semaphore:
                    response = await client.get(url)
                    product = extractor.extract_with_fallback(response.text)
                    return product
            
            tasks = [process_one(url) for url in urls]
            results = await asyncio.gather(*tasks, return_exceptions=True)
        
        return [r for r in results if isinstance(r, ExtractedProduct)]

    Avis d'Expert 2026

    Le LLM-Based Parsing est une révolution pour le scraping en 2026, mais pas une solution miracle. Les coûts en tokens peuvent exploser à grande échelle. L'approche hybride (LLM pour cas difficiles, sélecteurs pour patterns stables) reste optimale. Les modèles vision (GPT-4V) ouvrent aussi la voie au scraping de screenshots.

    Besoin d'aide sur LLM-Based Parsing ?

    Nos experts peuvent vous accompagner sur vos projets de crawling et d'optimisation GEO.

    Contactez l'expert Crawlers.fr
    4.6/5 (73 avis d'experts)