Avec Laravel, tu peux scraper un site web en trois étapes : installer un package comme Symfony DomCrawler via Composer, créer une commande Artisan, puis cibler les éléments HTML avec des sélecteurs CSS.
Ce guide de web scraping te montre comment faire concrètement, avec du code PHP prêt à l’emploi.

Prérequis pour faire du scraping avec Laravel
Laravel est un framework PHP pensé pour les applications web modernes. Son écosystème riche en fait une base idéale pour organiser un projet de scraping propre et facile à maintenir.
Avant de te lancer, assure-toi d’avoir le bon environnement :
- Composer, le gestionnaire de dépendances pour installer les packages.
- Une version récente de PHP compatible avec ta version de Laravel.
- Laravel installé via
composer create-project laravel/laravel mon-scraper.
Côté compétences, quelques bases suffisent pour démarrer :
- Connaître les fondamentaux de PHP et la structure d’une application Laravel (contrôleurs, routes, architecture MVC).
- Comprendre le HTML et les sélecteurs CSS pour cibler précisément les éléments d’une page.
- Savoir utiliser Composer en ligne de commande pour ajouter un package au projet.
Pour le crawling lui-même, voici les outils de scraping les plus utiles :
- Symfony DomCrawler + HttpClient : le duo de référence aujourd’hui. Il télécharge une page et navigue dans le HTML grâce à la méthode
filter()du DomCrawler. Pour initialiser le client, tu utilisesHttpClient::create()avec les options souhaitées. - HTTP Client de Laravel : basé sur Guzzle, il récupère un contenu simple avec
Http::get()et gère bien les appels à une API. - Puppeteer / Headless Chrome : un navigateur sans interface, indispensable pour scraper les pages qui chargent leur contenu en JavaScript ou via Ajax.
Tutoriel pour créer son premier scraper avec Laravel
Suis ces étapes pour créer un scraper fonctionnel avec Laravel. Tu vas installer un package de scraping, générer une commande Artisan, puis cibler les données avec des sélecteurs CSS.
Étape 1 : Installation et configuration
Crée un nouveau projet Laravel avec Composer, puis ajoute Goutte, une intégration pratique pour le scraping :
# 1) Créer un nouveau projet Laravel
composer create-project laravel/laravel scraper-demo
cd scraper-demo
# 2) Ajouter Goutte (intégration Laravel)
composer require weidner/goutte
Les packages weidner/goutte et fabpot/goutte sont aujourd’hui officiellement abandonnés. Ils fonctionnent encore, mais pour un projet neuf, le remplacement recommandé côté Symfony est symfony/browser-kit, couplé à symfony/http-client et symfony/dom-crawler. Le code ci-dessous reste valable si tu utilises weidner/goutte, qui encapsule simplement Goutte pour Laravel.
Étape 2 : Créer une commande Artisan
Génère une commande qui contiendra ta logique de scraping avec php artisan :
php artisan make:command ScrapeData
Le fichier est créé ici : app/Console/Commands/ScrapeData.php. C’est dans cette classe que tu vas écrire la requête HTTP et l’extraction des données. La classe ScrapeData étend Command, et la méthode public function handle() contient toute la logique de scraping.
Étape 3 : Écrire le code du scraper
Dans la commande générée, tu vas assembler trois briques essentielles :
- Une requête HTTP pour récupérer le contenu HTML de la page.
- Des sélecteurs CSS passés au DomCrawler pour cibler les données via
filter(). - Une boucle pour parcourir les éléments et afficher les résultats.
Voici un exemple de code complet pour scraper les titres d’articles d’un blog :
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Weidner\Goutte\GoutteFacade as Goutte;
use Symfony\Component\DomCrawler\Crawler;
class ScrapeData extends Command
{
protected $signature = 'scrape:data';
protected $description = 'Scraper simple des titres d\'articles';
public function handle(): int
{
$url = 'https://example.com/blog'; // URL du blog à scraper
$this->info("Scraping: {$url}");
// 1) Requête HTTP pour récupérer le HTML
$crawler = Goutte::request('GET', $url);
// 2) Utilisation de sélecteurs CSS avec DomCrawler
$nodes = $crawler->filter('h2 a');
// 3) Boucle sur les éléments et affichage
$nodes->each(function (Crawler $node, $i) {
$title = $node->text();
$link = $node->attr('href');
$this->line(($i+1) . ". " . $title . " - " . $link);
});
return self::SUCCESS;
}
}
Ici, DomCrawler fait tout le travail d’analyse du HTML. La méthode filter('h2 a') récupère chaque lien situé dans un titre, puis each() boucle dessus pour extraire le texte et l’attribut href. Lance ensuite le scraper depuis ton terminal avec php artisan scrape:data et tu verras les titres s’afficher un par un. Tu peux aussi lancer php artisan serve pour tester ton application localement avant de déployer.
Bonnes pratiques pour le web scraping avec Laravel
Pour scraper proprement avec Laravel, quelques réflexes changent tout. Voici les bonnes pratiques à appliquer, que tu gères un bot de web scraping ou une commande ponctuelle.
1. Gestion des tâches et de la mise en file d’attente
Le scraping peut prendre plusieurs secondes par page. Imagine devoir scraper 1000 pages d’un site : ton application serait bloquée et inutilisable pendant un bon moment. La solution tient en deux mots : les jobs et les queues de Laravel.
- Un job, c’est une tâche que tu veux exécuter en arrière-plan.
- Une queue (file d’attente), c’est l’endroit où on range ces jobs pour les exécuter petit à petit, sans bloquer le reste.
Voici comment encapsuler la logique de scraping dans un job :
// app/Jobs/ScrapePageJob.php
<?php
namespace App\Jobs;
use Goutte\Client; // Ou Guzzle/Http, selon ta stack
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class ScrapePageJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected string $url;
public function __construct(string $url)
{
$this->url = $url;
}
public function handle(): void
{
$client = new Client();
$crawler = $client->request('GET', $this->url);
// Exemple simple : extraire tous les <h1>
$titles = $crawler->filter('h1')->each(function ($node) {
return $node->text();
});
// Persistance / logs / events...
foreach ($titles as $title) {
\Log::info("[Scraping] {$this->url} - H1: {$title}");
}
}
}
// app/Http/Controllers/ScraperController.php
<?php
namespace App\Http\Controllers;
use App\Jobs\ScrapePageJob;
class ScraperController extends Controller
{
public function start()
{
$urls = [
'https://example.com/page1',
'https://example.com/page2',
'https://example.com/page3',
];
foreach ($urls as $url) {
ScrapePageJob::dispatch($url); // file d'attente par defaut
// ScrapePageJob::dispatch($url)->onQueue('scraping'); // si tu veux une queue dediee
}
return response()->json(['status' => 'Scraping lance en arriere-plan']);
}
}
Pour déclencher ce contrôleur, déclare une route dans ton fichier routes/web.php ou routes/api.php, par exemple Route::get('/scrape', [ScraperController::class, 'start']). Tu peux aussi générer un contrôleur dédié avec php artisan make:controller ScraperController.
Laravel propose plusieurs systèmes pour gérer cette file. Les deux plus utilisés :
- File avec base de données : les jobs sont stockés comme des lignes dans une table SQL, puis exécutés un par un par un worker.
- File avec Redis : les jobs sont placés en mémoire dans une file ultra-rapide, idéale pour un gros volume de tâches.
2. Automatisation avec le planificateur de tâches de Laravel
Laravel intègre un planificateur de tâches (scheduler) qui te permet d’automatiser tes scrapers sans y penser. Tu peux ainsi planifier l’exécution d’une commande à intervalles réguliers, par exemple toutes les heures.
Voici comment le configurer dans app/Console/Kernel.php :
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* Planifie les commandes artisan.
*/
protected function schedule(Schedule $schedule): void
{
// Toutes les heures
$schedule->command('scraper:run')->hourly();
// Exemples utiles :
// $schedule->command('scraper:run')->everyFifteenMinutes();
// $schedule->command('scraper:run')->dailyAt('02:30')->timezone('Indian/Antananarivo');
}
/**
* Enregistrement des commandes.
*/
protected function commands(): void
{
$this->load(__DIR__ . '/Commands');
}
}
3. Contourner les protections anti-scraping
Beaucoup de sites mettent en place des protections contre les scrapers. Pour éviter d’être bloqué :
- Changer l’User-Agent : simule un vrai navigateur au lieu de l’en-tête par défaut du client HTTP.
- Gérer les délais : insère des pauses (sleep, throttle) entre les requêtes pour ne pas surcharger le serveur cible.
- Utiliser des proxys : répartis les requêtes sur plusieurs adresses IP.
4. Respecter le robots.txt et le cadre légal
Contourner une protection ne veut pas dire faire n’importe quoi. Le scraping reste encadré, et l’ignorer peut te coûter cher.
- Respecte le fichier robots.txt : il indique les pages que le site autorise ou interdit à l’exploration. C’est la première règle de politesse à suivre.
- Vérifie les conditions d’utilisation : un site peut interdire le scraping via ses CGU.
- Pense au RGPD : si tu récupères des données personnelles, tu dois respecter le règlement européen sur leur collecte et leur traitement.
Quelles sont les alternatives au web scraping avec Laravel ?
Laravel reste pratique pour intégrer le scraping dans une application PHP existante. Mais selon ton projet, d’autres solutions sont parfois plus adaptées. Voici les deux grandes alternatives, avec leurs avantages et leurs limites.
Le web scraping avec Python
Python est le langage le plus utilisé pour le scraping. Il s’appuie sur des bibliothèques matures comme Scrapy et BeautifulSoup.
- Avantages : écosystème très riche, gestion native du crawling à grande échelle, énorme communauté.
- Inconvénients : il faut sortir de l’univers Laravel. Peu pratique si ton site et ton API tournent déjà en PHP.
Concrètement, tu choisis Python si le scraping est le cœur du projet, pas juste une brique de ton application.
Les outils sans code
De plus en plus d’outils permettent de scraper sans coder, parfois avec l’aide de l’IA. Les plus connus sont Bright Data, Octoparse et Apify.
- Avantages : configuration visuelle, gestion des pages en JavaScript et des blocages intégrée, aucune ligne de code à écrire.
- Inconvénients : abonnement payant, moins de contrôle fin qu’un scraper maison en Laravel.

FAQ
Comment scraper un site web protégé par un login avec Laravel ?
Le principe est simple : tu simules une connexion, puis tu réutilises la session pour atteindre les pages protégées. Concrètement, tu dois :
- Simuler la connexion avec une requête POST qui envoie l’email et le mot de passe au formulaire.
- Conserver les cookies de session pour que les requêtes suivantes restent authentifiées.
Avec le HttpBrowser de Symfony, tu peux enchaîner les deux étapes très proprement. Il instancie le client via HttpClient::create(), puis gère les cookies automatiquement entre chaque requête :
use Symfony\Component\BrowserKit\HttpBrowser;
use Symfony\Component\HttpClient\HttpClient;
$browser = new HttpBrowser(HttpClient::create());
$crawler = $browser->request('GET', 'https://exemple.com/login');
$form = $crawler->selectButton('Se connecter')->form();
$browser->submit($form, [
'email' => 'ton@email.com',
'password' => 'ton_mot_de_passe',
]);
// Les cookies de session sont gardés automatiquement
$page = $browser->request('GET', 'https://exemple.com/compte');
echo $page->filter('h1')->text();
À noter : le HttpBrowser gère les cookies tout seul entre deux requêtes. Tu n’as donc rien à stocker à la main.
Comment gérer la pagination lors du web scraping avec Laravel ?
Pour parcourir plusieurs pages à la suite, l’idée est de repérer le lien “page suivante” avec un sélecteur CSS, puis de boucler tant qu’il existe. Voici la logique :
- Scraper la première page et extraire les données utiles.
- Détecter le lien “suivant” via un sélecteur CSS.
- Boucler jusqu’à ce qu’il n’y ait plus de page suivante.
$url = 'https://exemple.com/blog?page=1';
while ($url) {
$crawler = $browser->request('GET', $url);
$crawler->filter('.article-title')->each(function ($node) {
echo $node->text() . PHP_EOL;
});
// Récupère le lien "page suivante" s'il existe
$next = $crawler->filter('a.next');
$url = $next->count() ? $next->attr('href') : null;
}
Cette boucle s’arrête d’elle-même dès que le sélecteur a.next ne renvoie plus rien.
Comment exporter les données scrapées (vers CSV, Excel ou JSON) ?
Une fois tes données récupérées, tu peux les exporter dans plusieurs formats avec Laravel :
fputcsv()pour générer un fichier CSV natif.- La librairie
Maatwebsite\Excelpour produire un fichier Excel. - La fonction native
json_encode()pour un export JSON, pratique si tu exposes ensuite tes données via une API.
Comment gérer les erreurs et les exceptions pendant le scraping ?
Un site peut renvoyer une erreur, changer sa structure HTML ou couper la connexion. Pour un scraper robuste, tu dois anticiper ces cas :
- Encapsuler chaque requête dans un
try/catch. - Vérifier les codes HTTP (404, 429, 500…) et logger l’erreur ou relancer un essai avec un délai.
try {
$crawler = $browser->request('GET', $url);
$status = $browser->getResponse()->getStatusCode();
if ($status !== 200) {
\Log::warning("Réponse inattendue: $status sur $url");
}
} catch (\Exception $e) {
\Log::error('Scraping échoué: ' . $e->getMessage());
}
Le web scraping est-il légal ou illégal ?
La légalité du web scraping dépend du site ciblé et de l’usage que tu fais des données. Voici les trois points à garder en tête :
- Droit sui generis sur les bases de données : la directive européenne 96/9/CE protège le contenu d’une base de données. Extraire une part importante d’un site peut être interdit.
- Conditions d’utilisation : l’arrêt Ryanair contre PR Aviation (CJUE, 2015) a confirmé qu’un site peut interdire le scraping dans ses CGU, même sans protection par le droit d’auteur.
- RGPD : dès que tu collectes des données personnelles (emails, noms, profils), tu tombes sous le coup du règlement européen. Prudence maximale.
En pratique, respecte toujours le fichier robots.txt, limite ta fréquence de requêtes et évite les données personnelles sans base légale. Tu as une question ou un cas particulier ? Dis-le en commentaire.





