Analyse Backend : Pourquoi vos scrapers Python ne récupèrent pas de données

Ce guide explore plusieurs raisons courantes pour lesquelles les scripts de scraping Python peuvent échouer à extraire des données, en se concentrant sur l'analyse côté serveur et les différentes méthodes d'implémentation web.

  1. Données directement dans le HTML

La méthode la plus simple consiste à utiliser des bibliothèques comme requests pour récupérer le contenu d'une page et lxml (ou BeautifulSoup) pour en extraire les données. Si vos données sont présentes directement dans le balisage HTML, cette approche devrait fonctionner.

Exemple Python :

Extraction d'informations de profil depuis une page web :


import requests
from lxml import etree

url = 'https://blog.example.com/user_profile'
headers = {
   'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36'
}
response = requests.get(url, headers=headers)
html_content = etree.HTML(response.text)
profile_description = html_content.xpath('//p[@class="profile-desc"]/text()')

if profile_description:
   print(f"Description: {profile_description[0].strip()}")
else:
   print("Description non trouvée.")
 

Implémentation Backend (Java/Spring Boot) :

Un serveur simulant la fourniture de ces données via une API simple.


package com.example.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.Map;
import java.util.HashMap;

@Controller
public class DataController {

   @GetMapping("/profile-data")
   public String getProfilePage(Model model) {
       Map<String, Object> userData = new HashMap<>();
       userData.put("username", "tech_guru");
       userData.put("followers", 1500);
       model.addAttribute("data", userData);
       return "profile_template"; // Thymeleaf template name
   }
}
 

Template Frontend (Thymeleaf) :



<html lang="fr" xmlns:th="http://www.thymeleaf.org">
<head>
   <meta charset="UTF-8">
   <title>Profil Utilisateur</title>
</head>
<body>
   <p>Nom d'utilisateur: <span th:text="${data.username}"></span></p>
   <p>Abonnés: <span th:text="${data.followers}"></span></p>
</body>
</html>
 

Pour vérifier si les données sont accessibles directement, vous pouvez inspecter le code source de la page ou utiliser les outils de développement de votre navigateur (onglet Réseau, puis charger la réponse de la requête principale).

  1. Données dans les balises <script>

Parfois, les données ne sont pas dans le HTML standard mais intégrées dans des blocs <script>, souvent sous forme de variables JavaScript ou d'objets JSON. L'analyse de ces scripts est alors nécessaire.

Exemple Python :

Extraction de données d'icônes/badges à partir d'un script :


import requests
from lxml import etree
import json

url = 'https://blog.example.com/user_profile'
headers = {
   'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36'
}
response = requests.get(url, headers=headers)
html_content = etree.HTML(response.text)

# Cherche le texte dans les balises script
script_texts = html_content.xpath('//script/text()')
all_badges = []

for script in script_texts:
   if 'badgeData' in script: # Trouver le script pertinent
       try:
           # Extraire le JSON (souvent après un '=' ou une assignation)
           json_start_index = script.find('=') + 1
           if json_start_index > 0:
               data_object = json.loads(script[json_start_index:].strip().rstrip(';'))
               if 'userBadges' in data_object:
                   for badge in data_object['userBadges']:
                       all_badges.append(badge['name'])
       except json.JSONDecodeError:
           print("Erreur de décodage JSON dans un script.")
       except Exception as e:
           print(f"Erreur lors du traitement du script : {e}")

if all_badges:
   print("Badges :", " | ".join(all_badges))
else:
   print("Aucun badge trouvé dans les scripts.")
 

Template Frontend (Thymeleaf avec script) :

Le JavaScript peut lire des données passées par le back end.



<html lang="fr" xmlns:th="http://www.thymeleaf.org">
<head>
   <meta charset="UTF-8">
   <title>Profil Utilisateur Dynamique</title>
</head>
<body>
   <p>Nom: <span id="userName"></span></p>
   <p>Statut: <span id="userStatus"></span></p>

   <script th:inline="javascript">
       // Les données sont passées ici par le backend Thymeleaf
       var serverData = [[${userData}]]; // Assumant que userData est un Map ou un objet similaire

       document.getElementById('userName').innerText = serverData.username || 'N/A';
       document.getElementById('userStatus').innerText = serverData.status || 'En ligne';
   </script>
</body>
</html>
 
  1. Requêtes AJAX (API)

Si les deux premières méthodes échouent, les données peuvent être chargées via des requêtes JavaScript asynchrones (AJAX) après le chargement initial de la page. L'identification de ces appels API est la clé.

Exemple Python :

Récupération d'une liste d'articles via une API dédiée :


import requests
import json

api_endpoint = 'https://api.example.com/v1/articles'
params = {
   'userId': 'user123',
   'pageSize': 10,
   'page': 1
}
headers = {
   'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36',
   'Accept': 'application/json'
}

try:
   response = requests.get(api_endpoint, params=params, headers=headers)
   response.raise_for_status() # Lève une exception pour les codes d'erreur HTTP
   data = response.json()

   if 'articles' in data:
       for article in data['articles']:
           print(f"Titre de l'article : {article.get('title', 'Titre inconnu')}")
   else:
       print("Structure de données inattendue reçue.")

except requests.exceptions.RequestException as e:
   print(f"Erreur lors de la requête API : {e}")
except json.JSONDecodeError:
   print("Erreur : La réponse de l'API n'est pas un JSON valide.")
 

Implémentation Backend (Java/Spring Boot avec @ResponseBody) :

Un contrôleur qui renvoie directement des données JSON.


package com.example.demo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
import java.util.HashMap;

@RestController // Utilise RestController pour renvoyer des données directement
public class ApiController {

   @GetMapping("/api/user-info")
   public Map<String, Object> getUserInfo() {
       Map<String, Object> userInfo = new HashMap<>();
       userInfo.put("username", "api_user");
       userInfo.put("status", "Actif");
       return userInfo;
   }

   @GetMapping("/legacy/page") // Route pour la page HTML simple
   public String getLegacyPage() {
       return "legacy_template"; // Fichier HTML standard
   }
}
 

Template Frontand (Utilisation de Fetch API) :

Le JavaScript fait une requête à l'API après le chargement de la page.



<html lang="fr">
<head>
   <meta charset="UTF-8">
   <title>Page avec AJAX</title>
</head>
<body>
   <p>Utilisateur: <span id="apiUsername">Chargement...</span></p>
   <p>Statut API: <span id="apiStatus">Chargement...</span></p>

   <script>
       document.addEventListener('DOMContentLoaded', function() {
           fetch('/api/user-info')
               .then(response => {
                   if (!response.ok) {
                       throw new Error('Erreur réseau lors de la récupération des données utilisateur');
                   }
                   return response.json();
               })
               .then(data => {
                   document.getElementById('apiUsername').innerText = data.username || 'Non disponible';
                   document.getElementById('apiStatus').innerText = data.status || 'Inconnu';
               })
               .catch(error => {
                   console.error('Erreur lors de la récupération des données API:', error);
                   document.getElementById('apiUsername').innerText = 'Erreur';
                   document.getElementById('apiStatus').innerText = 'Erreur';
               });
       });
   </script>
</body>
</html>
 

L'incapacité à récupérer des données peut être liée à la manière dont le contenu est chargé dynamiquement. Les requêtes AJAX ou l'exécution de JavaScript sont souvent responsables du rendu final des données visibles par l'utilisateur.

Étiquettes: Python scraping web scraping AJAX API

Publié le 1 juin à 08h02