{"id":44363,"date":"2026-05-06T12:51:19","date_gmt":"2026-05-06T12:51:19","guid":{"rendered":"https:\/\/floppydata.com\/non-categorise\/php-web-scraping-tutorial-comment-recuperer-des-donnees-avec-php\/"},"modified":"2026-05-06T12:51:19","modified_gmt":"2026-05-06T12:51:19","slug":"php-web-scraping-tutorial","status":"publish","type":"post","link":"https:\/\/floppydata.com\/fr\/blog\/scraping\/php-web-scraping-tutorial\/","title":{"rendered":"PHP Web Scraping Tutorial : Comment r\u00e9cup\u00e9rer des donn\u00e9es avec PHP"},"content":{"rendered":"<h2>Introduction<\/h2>\n<p>PHP a \u00e9t\u00e9 l&rsquo;un de mes premiers langages en tant que d\u00e9veloppeur web \u00e0 l&rsquo;\u00e9poque, et j&rsquo;aime toujours l&rsquo;utiliser pour le scraping.<\/p>\n<p>Ce tutoriel couvre ce que j&rsquo;utilise r\u00e9ellement en production. Je vous guiderai \u00e0 travers un workflow complet de scraping web en PHP en utilisant <a href=\"https:\/\/floppydata.com\/web-unlocker\/\">Floppydata Web Unlocker<\/a> comme couche de scraping. <\/p>\n<p><strong>Pourquoi Floppydata ?<\/strong><\/p>\n<p>Parce qu&rsquo;il fournit une API de scraping qui \u00e9limine le besoin de g\u00e9rer des proxys, des en-t\u00eates ou une logique anti-bot. \u00c0 la fin de cet article, vous aurez une bonne connaissance de la mani\u00e8re d&rsquo;effectuer du web scraping avec PHP. <\/p>\n<h2>Qu&rsquo;est-ce que le web scraping en PHP ?<\/h2>\n<p>Le web scraping PHP consiste \u00e0 utiliser du code PHP pour extraire des donn\u00e9es de sites web. Tous les sites ne proposent pas d&rsquo;API, comme Twitter par exemple. Dans de nombreux cas, le seul moyen d&rsquo;obtenir les informations dont vous avez besoin est de r\u00e9cup\u00e9rer la page et d&rsquo;analyser le code HTML vous-m\u00eame. <\/p>\n<p>PHP est tr\u00e8s utile si vous l&rsquo;utilisez d\u00e9j\u00e0 tous les jours. Vous pouvez d\u00e9poser les donn\u00e9es scrapp\u00e9es directement dans un backend existant, les stocker dans MySQL, ou ex\u00e9cuter le scraper sur une t\u00e2che cron sans introduire un autre langage dans la pile. <\/p>\n<p>La question principale n&rsquo;est pas de savoir si PHP peut faire du scrape. Il le peut tout \u00e0 fait. La vraie question est de savoir comment votre scraper g\u00e8re les requ\u00eates bloqu\u00e9es, les restrictions bas\u00e9es sur la localisation et les CAPTCHAs agressifs.  <\/p>\n<p>C&rsquo;est exactement la raison pour laquelle j&rsquo;ai associ\u00e9 PHP \u00e0 Floppydata Web Unlocker pour aider \u00e0 combler le foss\u00e9.<\/p>\n<h2>Biblioth\u00e8ques de scraping web en PHP \u00e0 conna\u00eetre (2026)<\/h2>\n<p>PHP dispose de nombreuses biblioth\u00e8ques de scraping, mais honn\u00eatement, je n&rsquo;en ai retenu que quelques-unes que j&rsquo;utilise r\u00e9ellement. Voici un aper\u00e7u de ces biblioth\u00e8ques. <\/p>\n<ul>\n<li><strong>Guzzle :<\/strong> Un client HTTP solide qui g\u00e8re proprement les requ\u00eates POST, les charges utiles JSON, les redirections et les en-t\u00eates. Nous l&rsquo;utiliserons tout au long de ce tutoriel pour communiquer avec l&rsquo;API Web Unlocker. <\/li>\n<li><strong>Symfony DomCrawler :<\/strong> Il vous permet de naviguer dans le HTML et le XML en utilisant des s\u00e9lecteurs CSS ou XPath. Associ\u00e9 au composant symfony\/css-selector, il vous donne un filtrage de type jQuery qui fonctionne de mani\u00e8re fiable sur du HTML d\u00e9sordonn\u00e9. Il est autonome, vous n&rsquo;avez donc pas besoin du reste de Symfony.  <\/li>\n<li><strong>Symfony HttpBrowser :<\/strong> Il s&rsquo;agit du remplacement moderne de la biblioth\u00e8que Goutte, d\u00e9sormais obsol\u00e8te. Elle est construite au-dessus de BrowserKit et DomCrawler, et vous permet de simuler des clics, des soumissions de formulaires, et des cha\u00eenes de redirection. C&rsquo;est id\u00e9al lorsque votre logique de scraping s&rsquo;\u00e9tend sur plusieurs pages.  <\/li>\n<li><strong>DiDOM :<\/strong> DiDOM est un parseur rapide, sans d\u00e9pendance, avec une API de type jQuery. Parfait pour les petits scripts o\u00f9 vous voulez \u00e9viter de tirer des composants Symfony. <\/li>\n<li><strong>Symfony Panther :<\/strong> Pilote un vrai navigateur Chrome ou Chromium via WebDriver. Vous l&rsquo;utilisez lorsqu&rsquo;un site rend tout en JavaScript (React, Vue, SPAs lourdes) et qu&rsquo;une simple requ\u00eate HTTP renvoie une coquille vide. C&rsquo;est plus lourd, donc je ne l&rsquo;utilise que lorsque rien d&rsquo;autre ne fonctionne.  <\/li>\n<\/ul>\n<p>Goutte \u00e9tait une recommandation courante, mais elle est maintenant obsol\u00e8te, et je ne recommanderais donc pas de construire un nouveau projet autour d&rsquo;elle.<\/p>\n<p>Pour ce guide, Guzzle et Symfony DomCrawler suffisent. Parce que le Web Unlocker ex\u00e9cute d\u00e9j\u00e0 le JavaScript et renvoie le rendu final du HTML, nous n&rsquo;avons pas besoin d&rsquo;ex\u00e9cuter un navigateur sans t\u00eate de notre c\u00f4t\u00e9. <\/p>\n<h2>Conditions pr\u00e9alables<\/h2>\n<p>Avant d&rsquo;\u00e9crire du code, assurez-vous d&rsquo;avoir mis en place les quatre \u00e9l\u00e9ments suivants. Si vous n&rsquo;avez jamais mis en place un projet PHP \u00e0 partir de z\u00e9ro, ne vous inqui\u00e9tez pas, je vous guiderai \u00e0 travers chaque \u00e9tape. <\/p>\n<h3>1. PHP 8.2 ou plus r\u00e9cent<\/h3>\n<p>PHP est pr\u00e9install\u00e9 sur de nombreux syst\u00e8mes Mac et Linux, mais il n&rsquo;est jamais inutile de v\u00e9rifier. Ouvrez votre terminal et v\u00e9rifiez la version de PHP : <\/p>\n<div style=\"margin: 18px 0 26px 0;\">\n<pre style=\"background: #f8fafc; border: 1px solid #e5e7eb; border-radius: 10px; padding: 16px 18px; margin: 0; font-size: 14px; line-height: 1.7;\"><code><span style=\"color: #9333ea;\">php<\/span> <span style=\"color: #16a34a;\">-v<\/span><\/code><\/pre>\n<\/div>\n<p>Si PHP est d\u00e9j\u00e0 install\u00e9, vous devriez voir un num\u00e9ro de version. Pour ce tutoriel, utilisez PHP 8.2 ou une version plus r\u00e9cente. C&rsquo;est le point de d\u00e9part le plus s\u00fbr avec les versions des d\u00e9pendances que nous allons installer.  <\/p>\n<p>Si PHP est manquant, suivez les instructions pour l&rsquo;installer :<\/p>\n<div style=\"margin: 18px 0 26px 0;\">\n<pre style=\"background: #f8fafc; border: 1px solid #e5e7eb; border-radius: 10px; padding: 16px 18px; margin: 0; font-size: 14px; line-height: 1.7;\"><code><span style=\"color: #64748b;\"># Windows (Chocolatey, run PowerShell as Administrator)<\/span>\n<span style=\"color: #9333ea;\">choco<\/span> <span style=\"color: #16a34a;\">install<\/span> php\n\n<span style=\"color: #64748b;\"># macOS (Homebrew)<\/span>\n<span style=\"color: #9333ea;\">brew<\/span> <span style=\"color: #16a34a;\">install<\/span> php<\/code><\/pre>\n<\/div>\n<p>Apr\u00e8s l&rsquo;installation, ex\u00e9cutez \u00e0 nouveau <code>php -v<\/code> pour confirmer la version. Sur Homebrew, vous n&rsquo;avez pas besoin de paquets php-curl ou php-xml s\u00e9par\u00e9s pour ce tutoriel. Ces extensions sont d\u00e9j\u00e0 incluses dans l&rsquo;installation principale de PHP.  <\/p>\n<h3>2. Compositeur<\/h3>\n<p>Composer est le gestionnaire de paquets standard pour PHP. C&rsquo;est l&rsquo;\u00e9quivalent de npm ou pip pour les projets PHP. Nous allons l&rsquo;utiliser pour installer Guzzle et les paquets d&rsquo;analyseur Symfony.  <\/p>\n<p>Tout d&rsquo;abord, v\u00e9rifiez s&rsquo;il est d\u00e9j\u00e0 disponible :<\/p>\n<div style=\"margin: 18px 0 26px 0;\">\n<pre style=\"background: #f8fafc; border: 1px solid #e5e7eb; border-radius: 10px; padding: 16px 18px; margin: 0; font-size: 14px; line-height: 1.7;\"><code><span style=\"color: #9333ea;\">composer<\/span> <span style=\"color: #16a34a;\">--version<\/span><\/code><\/pre>\n<\/div>\n<p>Si Composer n&rsquo;est pas encore install\u00e9, utilisez :<\/p>\n<div style=\"margin: 18px 0 26px 0;\">\n<pre style=\"background: #f8fafc; border: 1px solid #e5e7eb; border-radius: 10px; padding: 16px 18px; margin: 0; font-size: 14px; line-height: 1.7;\"><code><span style=\"color: #64748b;\"># Windows (Chocolatey, as Administrator)<\/span>\n<span style=\"color: #9333ea;\">choco<\/span> <span style=\"color: #16a34a;\">install<\/span> composer\n\n<span style=\"color: #64748b;\"># macOS (Homebrew)<\/span>\n<span style=\"color: #9333ea;\">brew<\/span> <span style=\"color: #16a34a;\">install<\/span> composer<\/code><\/pre>\n<\/div>\n<p>Une fois cela fait, <code>composer --version<\/code> devrait imprimer un num\u00e9ro de version, et vous \u00eates pr\u00eat \u00e0 cr\u00e9er le projet.<\/p>\n<h3>3. Un compte Floppydata<\/h3>\n<p>Cr\u00e9ez un <a href=\"http:\/\/app.floppydata.com\">compte Floppydata<\/a> et copiez votre cl\u00e9 API depuis le tableau de bord. Chaque nouveau compte re\u00e7oit 5 scrapes gratuits pour le Web Unlocker. <\/p>\n<p><img fetchpriority=\"high\" decoding=\"async\" class=\"alignnone size-full wp-image-44186\" src=\"https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image5-2.png\" alt=\"  Compte Floppydata  \" width=\"1999\" height=\"764\" srcset=\"https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image5-2.png 1999w, https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image5-2-300x115.png 300w, https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image5-2-1024x391.png 1024w, https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image5-2-768x294.png 768w, https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image5-2-1536x587.png 1536w\" sizes=\"(max-width: 1999px) 100vw, 1999px\" \/><\/p>\n<p>Apr\u00e8s vous \u00eatre connect\u00e9 \u00e0 votre tableau de bord, allez \u00e0 <strong>G\u00e9rer les cl\u00e9s API<\/strong> dans le Web Unlocker et g\u00e9n\u00e9rez une cl\u00e9 API. Copiez-la imm\u00e9diatement et conservez-la en lieu s\u00fbr. <\/p>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-44195\" src=\"https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image6-2.png\" alt=\"G\u00e9rer les cl\u00e9s API\" width=\"1999\" height=\"680\" srcset=\"https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image6-2.png 1999w, https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image6-2-300x102.png 300w, https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image6-2-1024x348.png 1024w, https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image6-2-768x261.png 768w, https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image6-2-1536x523.png 1536w\" sizes=\"(max-width: 1999px) 100vw, 1999px\" \/><\/p>\n<p>Vous utiliserez cette cl\u00e9 dans l&rsquo;en-t\u00eate X-Api-Key de chaque requ\u00eate de Web Unlocker. Nous allons l&rsquo;ajouter \u00e0 notre code dans quelques minutes. <\/p>\n<h3>4. R\u00e9pertoire du projet et d\u00e9pendances<\/h3>\n<p>Maintenant, cr\u00e9ons le dossier dans lequel se trouvera notre scraper et installons les biblioth\u00e8ques PHP dont nous avons besoin. Dans votre terminal : <\/p>\n<div style=\"margin: 18px 0 26px 0;\">\n<pre style=\"background: #f8fafc; border: 1px solid #e5e7eb; border-radius: 10px; padding: 16px 18px; margin: 0; font-size: 14px; line-height: 1.7;\"><code><span style=\"color: #9333ea;\">mkdir<\/span> php-scrape-countries\n<span style=\"color: #9333ea;\">cd<\/span> php-scrape-countries<\/code><\/pre>\n<\/div>\n<p>Initialiser un nouveau projet Composer :<\/p>\n<div style=\"margin: 18px 0 26px 0;\">\n<pre style=\"background: #f8fafc; border: 1px solid #e5e7eb; border-radius: 10px; padding: 16px 18px; margin: 0; font-size: 14px; line-height: 1.7;\"><code><span style=\"color: #9333ea;\">composer<\/span> <span style=\"color: #16a34a;\">init<\/span> <span style=\"color: #16a34a;\">--name=<\/span><span style=\"color: #dc2626;\">\"myname\/country-scraper\"<\/span> <span style=\"color: #16a34a;\">--require=<\/span><span style=\"color: #dc2626;\">\"php:^8.2\"<\/span> <span style=\"color: #16a34a;\">--no-interaction<\/span><\/code><\/pre>\n<\/div>\n<p>Installez maintenant les paquets dont nous avons besoin :<\/p>\n<div style=\"margin: 18px 0 26px 0;\">\n<pre style=\"background: #f8fafc; border: 1px solid #e5e7eb; border-radius: 10px; padding: 16px 18px; margin: 0; font-size: 14px; line-height: 1.7;\"><code><span style=\"color: #9333ea;\">composer<\/span> <span style=\"color: #16a34a;\">require<\/span> guzzlehttp\/guzzle symfony\/dom-crawler:^7.4 symfony\/css-selector:^7.4<\/code><\/pre>\n<\/div>\n<p>Composer t\u00e9l\u00e9chargera les trois biblioth\u00e8ques et leurs d\u00e9pendances dans un dossier vendor\/ et cr\u00e9era un fichier composer.json qui indiquera exactement les versions que vous utilisez.<\/p>\n<p>D\u00e9sormais, chaque fichier PHP du projet peut charger les d\u00e9pendances avec :<\/p>\n<div style=\"margin: 18px 0 26px 0;\">\n<pre style=\"background: #f8fafc; border: 1px solid #e5e7eb; border-radius: 10px; padding: 16px 18px; margin: 0; font-size: 14px; line-height: 1.7;\"><code><span style=\"color: #ea580c;\">require_once<\/span> <span style=\"color: #6366f1;\">__DIR__<\/span> . <span style=\"color: #dc2626;\">'\/vendor\/autoload.php'<\/span>;<\/code><\/pre>\n<\/div>\n<p>\u00c0 ce stade, la configuration est termin\u00e9e et nous pouvons passer au grattoir proprement dit.<\/p>\n<h2>Comment r\u00e9cup\u00e9rer des donn\u00e9es avec PHP en utilisant Floppydata Web Unlocker<\/h2>\n<h3>\u00c9tape 1 : Testez votre cible<\/h3>\n<p>Je n&rsquo;aime jamais \u00e9crire du code \u00e0 l&rsquo;aveugle, de sorte que je sais exactement \u00e0 quels s\u00e9lecteurs et \u00e0 quelle structure de donn\u00e9es m&rsquo;attendre. Pour cet exemple, je vais cibler <a href=\"https:\/\/www.scrapethissite.com\/pages\/simple\/\" rel=\"nofollow noopener\" target=\"_blank\">scrapethissite<\/a>, un site de d\u00e9monstration pour le scraping de donn\u00e9es. Il contient une liste des 250 pays avec leur capitale, leur population et leur superficie.  <\/p>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-44177\" src=\"https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image4-2.png\" alt=\"scrapethissite\" width=\"1999\" height=\"1184\" srcset=\"https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image4-2.png 1999w, https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image4-2-300x178.png 300w, https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image4-2-1024x607.png 1024w, https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image4-2-768x455.png 768w, https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image4-2-1536x910.png 1536w\" sizes=\"(max-width: 1999px) 100vw, 1999px\" \/><\/p>\n<p>Pour suivre l&rsquo;\u00e9volution, visitez le <a href=\"http:\/\/app.floppydata.com\/tools\/scrape\">terrain de jeu Floppydata Web Unlocker<\/a>. Cet outil sans code est disponible directement \u00e0 partir de votre tableau de bord et vous permet de voir le code HTML exact que l&rsquo;API renverra sans avoir \u00e0 configurer un projet. <\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-44150\" src=\"https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image1-2.png\" alt=\"floppydata\" width=\"1057\" height=\"419\" srcset=\"https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image1-2.png 1057w, https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image1-2-300x119.png 300w, https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image1-2-1024x406.png 1024w, https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image1-2-768x304.png 768w\" sizes=\"(max-width: 1057px) 100vw, 1057px\" \/><\/p>\n<p>Saisissez l&rsquo;URL et cliquez sur Scrape. En quelques secondes, vous verrez le code HTML complet dans l&rsquo;aper\u00e7u de la sortie. C&rsquo;est exactement le m\u00eame HTML que votre script PHP recevra dans quelques instants.  <\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-44168 size-full\" src=\"https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image3-2.png\" alt=\"Script PHP\" width=\"1010\" height=\"499\" srcset=\"https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image3-2.png 1010w, https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image3-2-300x148.png 300w, https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image3-2-768x379.png 768w\" sizes=\"(max-width: 1010px) 100vw, 1010px\" \/><\/p>\n<p>Si les donn\u00e9es semblent correctes, vous pouvez copier le code HTML ou t\u00e9l\u00e9charger la r\u00e9ponse. Mais dans notre cas, nous laisserons le script PHP le faire automatiquement. <\/p>\n<h3>\u00c9tape 2 : Envoi de votre premi\u00e8re demande de d\u00e9blocage de site Web avec Guzzle<\/h3>\n<p>Le c\u0153ur de l&rsquo;ensemble du flux de travail est une requ\u00eate POST vers le point de terminaison de Floppydata :<\/p>\n<div style=\"margin: 18px 0 26px 0;\">\n<pre style=\"background: #f8fafc; border: 1px solid #e5e7eb; border-radius: 10px; padding: 16px 18px; margin: 0; font-size: 14px; line-height: 1.7;\"><code>https:\/\/client-api.floppy.host\/v1\/webUnlocker<\/code><\/pre>\n<\/div>\n<p>Pour ce faire, nous cr\u00e9ons d&rsquo;abord un client Guzzle et pr\u00e9parons la configuration de la demande. Ensuite, nous envoyons la requ\u00eate et traitons la r\u00e9ponse. <\/p>\n<p>Cr\u00e9ez un fichier appel\u00e9 <strong>scrape.php<\/strong> et commencez par le squelette de base :<\/p>\n<div style=\"margin: 20px 0 28px 0;\">\n<pre style=\"background: #f8fafc; border: 1px solid #e5e7eb; border-radius: 10px; padding: 18px; margin: 0; font-size: 13px; line-height: 1.6; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;\"><code><span style=\"color: #9333ea;\">&lt;?php<\/span>\n<span style=\"color: #64748b;\">\/\/ scrape.php<\/span>\n\n<span style=\"color: #ea580c;\">require_once<\/span> <span style=\"color: #6366f1;\">__DIR__<\/span> . <span style=\"color: #dc2626;\">'\/vendor\/autoload.php'<\/span>;\n\n<span style=\"color: #ea580c;\">use<\/span> GuzzleHttp\\Client;\n\n<span style=\"color: #0891b2;\">$apiKey<\/span> = <span style=\"color: #dc2626;\">'YOUR_API_KEY'<\/span>;   <span style=\"color: #64748b;\">\/\/ Replace with your real key<\/span>\n<span style=\"color: #0891b2;\">$targetUrl<\/span> = <span style=\"color: #dc2626;\">'https:\/\/www.scrapethissite.com\/pages\/simple\/'<\/span>;\n\n<span style=\"color: #0891b2;\">$client<\/span> = <span style=\"color: #ea580c;\">new<\/span> <span style=\"color: #9333ea;\">Client<\/span>([\n    <span style=\"color: #dc2626;\">'base_uri'<\/span> =&gt; <span style=\"color: #dc2626;\">'https:\/\/client-api.floppy.host'<\/span>,\n    <span style=\"color: #dc2626;\">'timeout'<\/span> =&gt; <span style=\"color: #16a34a;\">60<\/span>,\n]);<\/code><\/pre>\n<\/div>\n<p>Remplacez YOUR_API_KEY par votre v\u00e9ritable cl\u00e9. Maintenant, nous construisons l&rsquo;appel POST r\u00e9el. Nous envoyons du JSON au point de terminaison de l&rsquo;API, nous incluons la cl\u00e9 d&rsquo;API dans les en-t\u00eates et nous passons l&rsquo;URL cible ainsi que quelques args dans le corps du message :  <\/p>\n<div style=\"margin: 20px 0 28px 0;\">\n<pre style=\"background: #f8fafc; border: 1px solid #e5e7eb; border-radius: 10px; padding: 18px; margin: 0; font-size: 13px; line-height: 1.6; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;\"><code><span style=\"color: #0891b2;\">$response<\/span> = <span style=\"color: #0891b2;\">$client<\/span>-&gt;<span style=\"color: #9333ea;\">post<\/span>(<span style=\"color: #dc2626;\">'\/v1\/webUnlocker'<\/span>, [\n    <span style=\"color: #dc2626;\">'headers'<\/span> =&gt; [\n        <span style=\"color: #dc2626;\">'Content-Type'<\/span> =&gt; <span style=\"color: #dc2626;\">'application\/json'<\/span>,\n        <span style=\"color: #dc2626;\">'X-Api-Key'<\/span> =&gt; <span style=\"color: #0891b2;\">$apiKey<\/span>,\n    ],\n    <span style=\"color: #dc2626;\">'json'<\/span> =&gt; [\n        <span style=\"color: #dc2626;\">'url'<\/span> =&gt; <span style=\"color: #0891b2;\">$targetUrl<\/span>,\n        <span style=\"color: #dc2626;\">'country'<\/span> =&gt; <span style=\"color: #dc2626;\">'US'<\/span>,\n        <span style=\"color: #dc2626;\">'city'<\/span> =&gt; <span style=\"color: #dc2626;\">'New York'<\/span>,\n        <span style=\"color: #dc2626;\">'difficulty'<\/span> =&gt; <span style=\"color: #dc2626;\">'low'<\/span>,\n        <span style=\"color: #dc2626;\">'expiration'<\/span> =&gt; <span style=\"color: #16a34a;\">0<\/span>,\n    ],\n]);\n\n<span style=\"color: #0891b2;\">$payload<\/span> = <span style=\"color: #9333ea;\">json_decode<\/span>((<span style=\"color: #ea580c;\">string<\/span>) <span style=\"color: #0891b2;\">$response<\/span>-&gt;<span style=\"color: #9333ea;\">getBody<\/span>(), <span style=\"color: #6366f1;\">true<\/span>);\n<span style=\"color: #0891b2;\">$html<\/span> = <span style=\"color: #0891b2;\">$payload<\/span>[<span style=\"color: #dc2626;\">'html'<\/span>] ?? <span style=\"color: #dc2626;\">''<\/span>;\n<span style=\"color: #ea580c;\">echo<\/span> <span style=\"color: #dc2626;\">\"HTML received! Length: \"<\/span> . <span style=\"color: #9333ea;\">strlen<\/span>(<span style=\"color: #0891b2;\">$html<\/span>) . <span style=\"color: #dc2626;\">\" characters\\n\"<\/span>;<\/code><\/pre>\n<\/div>\n<p>Les champs \u00a0\u00bb <strong>pays\u00a0\u00bb<\/strong> et \u00a0\u00bb <strong>ville\u00a0\u00bb<\/strong> indiquent au Web Unlocker le lieu g\u00e9ographique par lequel la demande doit \u00eatre achemin\u00e9e. Le champ <strong>difficulty (difficult\u00e9)<\/strong> d\u00e9termine le degr\u00e9 d&rsquo;agressivit\u00e9 avec lequel le d\u00e9verrouilleur g\u00e8re les protections anti-bots. J&rsquo;utilise ici le champ \u00a0\u00bb <strong>faible\u00a0\u00bb<\/strong> car la cible de notre bac \u00e0 sable ne dispose d&rsquo;aucune protection.  <\/p>\n<p>Pour les cibles prot\u00e9g\u00e9es par Cloudflare ou DataDome, r\u00e9glez ce param\u00e8tre sur <strong>moyen<\/strong> afin que le d\u00e9verrouilleur applique une logique de r\u00e9solution d&#8217;empreintes digitales et de CAPTCHA plus forte.<\/p>\n<p>Notez que le Web Unlocker renvoie le code HTML brut dans un objet JSON, ce qui signifie que vous devez d\u00e9coder le JSON et extraire les balises de la page dans le champ <strong>html.<\/strong> <\/p>\n<p>Si vous oubliez cela et que vous traitez tout le corps de la r\u00e9ponse comme du HTML, votre analyseur s&rsquo;arr\u00eatera. Avec ceci, la partie requ\u00eate est termin\u00e9e, et nous pouvons passer \u00e0 l&rsquo;analyse syntaxique. <\/p>\n<h3>\u00c9tape 3 : Inspecter la structure de la page<\/h3>\n<p>Une fois que la requ\u00eate a abouti, la t\u00e2che suivante consiste \u00e0 inspecter la structure de la page et \u00e0 cibler les \u00e9l\u00e9ments r\u00e9p\u00e9t\u00e9s qui contiennent les donn\u00e9es souhait\u00e9es. Chaque pays de la page suit exactement ce mod\u00e8le HTML : <\/p>\n<div style=\"margin: 20px 0 28px 0;\">\n<pre style=\"background: #f8fafc; border: 1px solid #e5e7eb; border-radius: 10px; padding: 18px; margin: 0; font-size: 13px; line-height: 1.6; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;\"><code><span style=\"color: #9333ea;\">&lt;div<\/span> <span style=\"color: #16a34a;\">class=<\/span><span style=\"color: #dc2626;\">\"col-md-4 country\"<\/span><span style=\"color: #9333ea;\">&gt;<\/span>\n    <span style=\"color: #9333ea;\">&lt;h3<\/span> <span style=\"color: #16a34a;\">class=<\/span><span style=\"color: #dc2626;\">\"country-name\"<\/span><span style=\"color: #9333ea;\">&gt;<\/span>\n        <span style=\"color: #9333ea;\">&lt;i<\/span> <span style=\"color: #16a34a;\">class=<\/span><span style=\"color: #dc2626;\">\"flag-icon flag-icon-ad\"<\/span><span style=\"color: #9333ea;\">&gt;&lt;\/i&gt;<\/span>\n        Andorra\n    <span style=\"color: #9333ea;\">&lt;\/h3&gt;<\/span>\n    <span style=\"color: #9333ea;\">&lt;div<\/span> <span style=\"color: #16a34a;\">class=<\/span><span style=\"color: #dc2626;\">\"country-info\"<\/span><span style=\"color: #9333ea;\">&gt;<\/span>\n        <span style=\"color: #9333ea;\">&lt;strong&gt;<\/span>Capital:<span style=\"color: #9333ea;\">&lt;\/strong&gt;<\/span> <span style=\"color: #9333ea;\">&lt;span<\/span> <span style=\"color: #16a34a;\">class=<\/span><span style=\"color: #dc2626;\">\"country-capital\"<\/span><span style=\"color: #9333ea;\">&gt;<\/span>Andorra la Vella<span style=\"color: #9333ea;\">&lt;\/span&gt;&lt;br&gt;<\/span>\n        <span style=\"color: #9333ea;\">&lt;strong&gt;<\/span>Population:<span style=\"color: #9333ea;\">&lt;\/strong&gt;<\/span> <span style=\"color: #9333ea;\">&lt;span<\/span> <span style=\"color: #16a34a;\">class=<\/span><span style=\"color: #dc2626;\">\"country-population\"<\/span><span style=\"color: #9333ea;\">&gt;<\/span>84000<span style=\"color: #9333ea;\">&lt;\/span&gt;&lt;br&gt;<\/span>\n        <span style=\"color: #9333ea;\">&lt;strong&gt;<\/span>Area (km<span style=\"color: #9333ea;\">&lt;sup&gt;<\/span>2<span style=\"color: #9333ea;\">&lt;\/sup&gt;<\/span>):<span style=\"color: #9333ea;\">&lt;\/strong&gt;<\/span> <span style=\"color: #9333ea;\">&lt;span<\/span> <span style=\"color: #16a34a;\">class=<\/span><span style=\"color: #dc2626;\">\"country-area\"<\/span><span style=\"color: #9333ea;\">&gt;<\/span>468.0<span style=\"color: #9333ea;\">&lt;\/span&gt;&lt;br&gt;<\/span>\n    <span style=\"color: #9333ea;\">&lt;\/div&gt;<\/span>\n<span style=\"color: #9333ea;\">&lt;\/div&gt;<\/span><\/code><\/pre>\n<\/div>\n<p>C&rsquo;est cette structure r\u00e9p\u00e9t\u00e9e qui rend cette page si pr\u00e9visible. Chaque fiche pays utilise les m\u00eames noms de classe : <strong>.country<\/strong> pour l&rsquo;enveloppe, <strong>.country-name<\/strong> pour l&rsquo;en-t\u00eate, et<strong>.country-capital<\/strong>, <strong>.country-population<\/strong>, et <strong>.country-area<\/strong> pour les champs de donn\u00e9es \u00e0 l&rsquo;int\u00e9rieur de <strong>.country-info<\/strong>. <\/p>\n<h3>\u00c9tape 4 : Analyse des donn\u00e9es avec Symfony DomCrawler<\/h3>\n<p>Comme les classes sont coh\u00e9rentes sur l&rsquo;ensemble des 250 entr\u00e9es, nous pouvons parcourir en boucle chaque \u00e9l\u00e9ment <strong>.country<\/strong> et extraire les valeurs des s\u00e9lecteurs enfants. Mais tout d&rsquo;abord, ajoutons une petite fonction d&rsquo;aide pour nous aider \u00e0 nettoyer le texte que nous extrayons : <\/p>\n<div style=\"margin: 20px 0 28px 0;\">\n<pre style=\"background: #f8fafc; border: 1px solid #e5e7eb; border-radius: 10px; padding: 18px; margin: 0; font-size: 13px; line-height: 1.6; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;\"><code><span style=\"color: #ea580c;\">use<\/span> Symfony\\Component\\DomCrawler\\Crawler;\n\n<span style=\"color: #ea580c;\">function<\/span> <span style=\"color: #9333ea;\">normalizeText<\/span>(<span style=\"color: #ea580c;\">string<\/span> <span style=\"color: #0891b2;\">$text<\/span>): <span style=\"color: #ea580c;\">string<\/span>\n{\n    <span style=\"color: #ea580c;\">return<\/span> <span style=\"color: #9333ea;\">preg_replace<\/span>(<span style=\"color: #dc2626;\">'\/\\s+\/'<\/span>, <span style=\"color: #dc2626;\">' '<\/span>, <span style=\"color: #9333ea;\">trim<\/span>(<span style=\"color: #0891b2;\">$text<\/span>)) ?? <span style=\"color: #9333ea;\">trim<\/span>(<span style=\"color: #0891b2;\">$text<\/span>);\n}<\/code><\/pre>\n<\/div>\n<p>Si vous regardez le code HTML brut, les noms de pays sont entour\u00e9s d&rsquo;espaces blancs et de nouvelles lignes \u00e0 cause des balises &lt;i&gt; qui se trouvent \u00e0 l&rsquo;int\u00e9rieur des balises &lt;h3&gt;.<\/p>\n<p>La fonction <em>normalizeText()<\/em> permet de supprimer les espaces blancs de d\u00e9but et de fin, puis utilise une expression rationnelle pour r\u00e9duire les espaces ou les nouvelles lignes restantes, de sorte que des noms comme Andorra ou St. John&rsquo;s reviennent proprement au lieu de porter les espaces blancs restants du code HTML.<\/p>\n<p>Une fois l&rsquo;assistant pr\u00eat, nous cr\u00e9ons une instance de Crawler et passons en revue chaque carte de pays :<\/p>\n<div style=\"margin: 20px 0 28px 0;\">\n<pre style=\"background: #f8fafc; border: 1px solid #e5e7eb; border-radius: 10px; padding: 18px; margin: 0; font-size: 13px; line-height: 1.6; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;\"><code><span style=\"color: #0891b2;\">$crawler<\/span> = <span style=\"color: #ea580c;\">new<\/span> <span style=\"color: #9333ea;\">Crawler<\/span>(<span style=\"color: #0891b2;\">$html<\/span>);\n<span style=\"color: #0891b2;\">$countries<\/span> = [];\n\n<span style=\"color: #0891b2;\">$crawler<\/span>-&gt;<span style=\"color: #9333ea;\">filter<\/span>(<span style=\"color: #dc2626;\">'.country'<\/span>)-&gt;<span style=\"color: #9333ea;\">each<\/span>(<span style=\"color: #ea580c;\">function<\/span> (<span style=\"color: #9333ea;\">Crawler<\/span> <span style=\"color: #0891b2;\">$node<\/span>) <span style=\"color: #ea580c;\">use<\/span> (&<span style=\"color: #0891b2;\">$countries<\/span>): <span style=\"color: #ea580c;\">void<\/span> {\n    <span style=\"color: #0891b2;\">$countries<\/span>[] = [\n        <span style=\"color: #dc2626;\">'name'<\/span> =&gt; <span style=\"color: #9333ea;\">normalizeText<\/span>(<span style=\"color: #0891b2;\">$node<\/span>-&gt;<span style=\"color: #9333ea;\">filter<\/span>(<span style=\"color: #dc2626;\">'.country-name'<\/span>)-&gt;<span style=\"color: #9333ea;\">text<\/span>()),\n        <span style=\"color: #dc2626;\">'capital'<\/span> =&gt; <span style=\"color: #9333ea;\">normalizeText<\/span>(<span style=\"color: #0891b2;\">$node<\/span>-&gt;<span style=\"color: #9333ea;\">filter<\/span>(<span style=\"color: #dc2626;\">'.country-capital'<\/span>)-&gt;<span style=\"color: #9333ea;\">text<\/span>()),\n        <span style=\"color: #dc2626;\">'population'<\/span> =&gt; <span style=\"color: #9333ea;\">normalizeText<\/span>(<span style=\"color: #0891b2;\">$node<\/span>-&gt;<span style=\"color: #9333ea;\">filter<\/span>(<span style=\"color: #dc2626;\">'.country-population'<\/span>)-&gt;<span style=\"color: #9333ea;\">text<\/span>()),\n        <span style=\"color: #dc2626;\">'area'<\/span> =&gt; <span style=\"color: #9333ea;\">normalizeText<\/span>(<span style=\"color: #0891b2;\">$node<\/span>-&gt;<span style=\"color: #9333ea;\">filter<\/span>(<span style=\"color: #dc2626;\">'.country-area'<\/span>)-&gt;<span style=\"color: #9333ea;\">text<\/span>()),\n    ];\n});\n\n<span style=\"color: #ea580c;\">echo<\/span> <span style=\"color: #dc2626;\">'Parsed '<\/span> . <span style=\"color: #9333ea;\">count<\/span>(<span style=\"color: #0891b2;\">$countries<\/span>) . <span style=\"color: #dc2626;\">\" countries\\n\"<\/span>;<\/code><\/pre>\n<\/div>\n<p>DomCrawler nous donne un moyen propre de nous d\u00e9placer \u00e0 travers le HTML en utilisant des s\u00e9lecteurs CSS. Nous commen\u00e7ons par envelopper le HTML dans un objet Crawler, puis nous filtrons jusqu&rsquo;\u00e0 chaque bloc .country de la page. A l&rsquo;int\u00e9rieur de chaque bloc, nous r\u00e9cup\u00e9rons le nom, la capitale, la population et la superficie.<\/p>\n<p>\u00c0 ce stade, si vous ex\u00e9cutez le script, vous devriez voir le message \u00ab\u00a0Parsed 250 countries\u00a0\u00bb s&rsquo;afficher dans le terminal.<\/p>\n<h3>\u00c9tape 5 : Exporter les r\u00e9sultats au format CSV et JSON<\/h3>\n<p>Une fois que l&rsquo;analyseur syntaxique vous a fourni un tableau <strong>$countries<\/strong>, l&rsquo;exportation des donn\u00e9es devient tr\u00e8s simple.<\/p>\n<div style=\"margin: 20px 0 28px 0;\">\n<pre style=\"background: #f8fafc; border: 1px solid #e5e7eb; border-radius: 10px; padding: 18px; margin: 0; font-size: 13px; line-height: 1.6; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;\"><code><span style=\"color: #0891b2;\">$csvHandle<\/span> = <span style=\"color: #9333ea;\">fopen<\/span>(<span style=\"color: #dc2626;\">'countries.csv'<\/span>, <span style=\"color: #dc2626;\">'w'<\/span>);\n\n<span style=\"color: #9333ea;\">fputcsv<\/span>(<span style=\"color: #0891b2;\">$csvHandle<\/span>, [<span style=\"color: #dc2626;\">'Country'<\/span>, <span style=\"color: #dc2626;\">'Capital'<\/span>, <span style=\"color: #dc2626;\">'Population'<\/span>, <span style=\"color: #dc2626;\">'Area (km2)'<\/span>], <span style=\"color: #dc2626;\">','<\/span>, <span style=\"color: #dc2626;\">'\"'<\/span>, <span style=\"color: #dc2626;\">''<\/span>);\n\n<span style=\"color: #ea580c;\">foreach<\/span> (<span style=\"color: #0891b2;\">$countries<\/span> <span style=\"color: #ea580c;\">as<\/span> <span style=\"color: #0891b2;\">$country<\/span>) {\n    <span style=\"color: #9333ea;\">fputcsv<\/span>(<span style=\"color: #0891b2;\">$csvHandle<\/span>, [\n        <span style=\"color: #0891b2;\">$country<\/span>[<span style=\"color: #dc2626;\">'name'<\/span>],\n        <span style=\"color: #0891b2;\">$country<\/span>[<span style=\"color: #dc2626;\">'capital'<\/span>],\n        <span style=\"color: #0891b2;\">$country<\/span>[<span style=\"color: #dc2626;\">'population'<\/span>],\n        <span style=\"color: #0891b2;\">$country<\/span>[<span style=\"color: #dc2626;\">'area'<\/span>],\n    ], <span style=\"color: #dc2626;\">','<\/span>, <span style=\"color: #dc2626;\">'\"'<\/span>, <span style=\"color: #dc2626;\">''<\/span>);\n}\n\n<span style=\"color: #9333ea;\">fclose<\/span>(<span style=\"color: #0891b2;\">$csvHandle<\/span>);\n\n<span style=\"color: #9333ea;\">file_put_contents<\/span>(<span style=\"color: #dc2626;\">'countries.json'<\/span>, <span style=\"color: #9333ea;\">json_encode<\/span>(<span style=\"color: #0891b2;\">$countries<\/span>, <span style=\"color: #6366f1;\">JSON_PRETTY_PRINT<\/span> | <span style=\"color: #6366f1;\">JSON_UNESCAPED_SLASHES<\/span>));<\/code><\/pre>\n<\/div>\n<p>L&rsquo;exportation CSV est utile car elle donne aux lecteurs un fichier qu&rsquo;ils peuvent ouvrir imm\u00e9diatement dans Excel, Google Sheets ou tout autre outil de feuille de calcul. L&rsquo;exportation JSON est tout aussi pratique s&rsquo;ils veulent introduire les donn\u00e9es scann\u00e9es dans un autre script PHP ou une API ult\u00e9rieurement. <\/p>\n<p>Une petite mise \u00e0 jour ici est l&rsquo;argument explicite escape dans <strong>fputcsv()<\/strong>. Sur les nouvelles versions de PHP, cela \u00e9vite les avertissements de d\u00e9pr\u00e9ciation et permet \u00e0 l&rsquo;exemple de rester propre lorsque les lecteurs l&rsquo;ex\u00e9cutent depuis le terminal. <\/p>\n<h3>\u00c9tape n\u00b0 6 : Rassembler tous les \u00e9l\u00e9ments dans un seul script<\/h3>\n<p>Maintenant que chaque partie fonctionne de mani\u00e8re autonome, voici le script complet :<\/p>\n<div style=\"margin: 20px 0 28px 0;\">\n<pre style=\"background: #f8fafc; border: 1px solid #e5e7eb; border-radius: 10px; padding: 18px; margin: 0; font-size: 13px; line-height: 1.6; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;\"><code><span style=\"color: #9333ea;\">&lt;?php<\/span>\n\n<span style=\"color: #9333ea;\">declare<\/span>(<span style=\"color: #6366f1;\">strict_types<\/span>=<span style=\"color: #16a34a;\">1<\/span>);\n\n<span style=\"color: #ea580c;\">require_once<\/span> <span style=\"color: #6366f1;\">__DIR__<\/span> . <span style=\"color: #dc2626;\">'\/vendor\/autoload.php'<\/span>;\n\n<span style=\"color: #ea580c;\">use<\/span> GuzzleHttp\\Client;\n<span style=\"color: #ea580c;\">use<\/span> Symfony\\Component\\DomCrawler\\Crawler;\n\n<span style=\"color: #ea580c;\">function<\/span> <span style=\"color: #9333ea;\">normalizeText<\/span>(<span style=\"color: #ea580c;\">string<\/span> <span style=\"color: #0891b2;\">$text<\/span>): <span style=\"color: #ea580c;\">string<\/span>\n{\n    <span style=\"color: #ea580c;\">return<\/span> <span style=\"color: #9333ea;\">preg_replace<\/span>(<span style=\"color: #dc2626;\">'\/\\s+\/'<\/span>, <span style=\"color: #dc2626;\">' '<\/span>, <span style=\"color: #9333ea;\">trim<\/span>(<span style=\"color: #0891b2;\">$text<\/span>)) ?? <span style=\"color: #9333ea;\">trim<\/span>(<span style=\"color: #0891b2;\">$text<\/span>);\n}\n\n<span style=\"color: #0891b2;\">$apiKey<\/span> = <span style=\"color: #dc2626;\">'YOUR_API_KEY'<\/span>;\n<span style=\"color: #0891b2;\">$targetUrl<\/span> = <span style=\"color: #dc2626;\">'https:\/\/www.scrapethissite.com\/pages\/simple\/'<\/span>;\n\n<span style=\"color: #ea580c;\">if<\/span> (<span style=\"color: #0891b2;\">$apiKey<\/span> === <span style=\"color: #dc2626;\">'YOUR_API_KEY'<\/span>) {\n    <span style=\"color: #9333ea;\">fwrite<\/span>(<span style=\"color: #6366f1;\">STDERR<\/span>, <span style=\"color: #dc2626;\">\"Replace YOUR_API_KEY before running the script.\\n\"<\/span>);\n    <span style=\"color: #ea580c;\">exit<\/span>(<span style=\"color: #16a34a;\">1<\/span>);\n}\n\n<span style=\"color: #0891b2;\">$client<\/span> = <span style=\"color: #ea580c;\">new<\/span> <span style=\"color: #9333ea;\">Client<\/span>([\n    <span style=\"color: #dc2626;\">'base_uri'<\/span> =&gt; <span style=\"color: #dc2626;\">'https:\/\/client-api.floppy.host'<\/span>,\n    <span style=\"color: #dc2626;\">'timeout'<\/span> =&gt; <span style=\"color: #16a34a;\">60<\/span>,\n]);\n\n<span style=\"color: #ea580c;\">try<\/span> {\n    <span style=\"color: #0891b2;\">$response<\/span> = <span style=\"color: #0891b2;\">$client<\/span>-&gt;<span style=\"color: #9333ea;\">post<\/span>(<span style=\"color: #dc2626;\">'\/v1\/webUnlocker'<\/span>, [\n        <span style=\"color: #dc2626;\">'headers'<\/span> =&gt; [\n            <span style=\"color: #dc2626;\">'Content-Type'<\/span> =&gt; <span style=\"color: #dc2626;\">'application\/json'<\/span>,\n            <span style=\"color: #dc2626;\">'X-Api-Key'<\/span> =&gt; <span style=\"color: #0891b2;\">$apiKey<\/span>,\n        ],\n        <span style=\"color: #dc2626;\">'json'<\/span> =&gt; [\n            <span style=\"color: #dc2626;\">'url'<\/span> =&gt; <span style=\"color: #0891b2;\">$targetUrl<\/span>,\n            <span style=\"color: #dc2626;\">'country'<\/span> =&gt; <span style=\"color: #dc2626;\">'US'<\/span>,\n            <span style=\"color: #dc2626;\">'city'<\/span> =&gt; <span style=\"color: #dc2626;\">'New York'<\/span>,\n            <span style=\"color: #dc2626;\">'difficulty'<\/span> =&gt; <span style=\"color: #dc2626;\">'low'<\/span>,\n            <span style=\"color: #dc2626;\">'expiration'<\/span> =&gt; <span style=\"color: #16a34a;\">0<\/span>,\n        ],\n    ]);\n} <span style=\"color: #ea580c;\">catch<\/span> (<span style=\"color: #9333ea;\">Throwable<\/span> <span style=\"color: #0891b2;\">$e<\/span>) {\n    <span style=\"color: #9333ea;\">fwrite<\/span>(<span style=\"color: #6366f1;\">STDERR<\/span>, <span style=\"color: #dc2626;\">\"Request failed: {<\/span><span style=\"color: #0891b2;\">$e<\/span>-><span style=\"color: #9333ea;\">getMessage<\/span>()<span style=\"color: #dc2626;\">}\\n\"<\/span>);\n    <span style=\"color: #ea580c;\">exit<\/span>(<span style=\"color: #16a34a;\">1<\/span>);\n}\n\n<span style=\"color: #0891b2;\">$payload<\/span> = <span style=\"color: #9333ea;\">json_decode<\/span>((<span style=\"color: #ea580c;\">string<\/span>) <span style=\"color: #0891b2;\">$response<\/span>-&gt;<span style=\"color: #9333ea;\">getBody<\/span>(), <span style=\"color: #6366f1;\">true<\/span>);\n\n<span style=\"color: #ea580c;\">if<\/span> (!<span style=\"color: #9333ea;\">is_array<\/span>(<span style=\"color: #0891b2;\">$payload<\/span>) || !<span style=\"color: #9333ea;\">isset<\/span>(<span style=\"color: #0891b2;\">$payload<\/span>[<span style=\"color: #dc2626;\">'html'<\/span>]) || !<span style=\"color: #9333ea;\">is_string<\/span>(<span style=\"color: #0891b2;\">$payload<\/span>[<span style=\"color: #dc2626;\">'html'<\/span>])) {\n    <span style=\"color: #9333ea;\">fwrite<\/span>(<span style=\"color: #6366f1;\">STDERR<\/span>, <span style=\"color: #dc2626;\">\"Unexpected API response. Expected JSON with an html field.\\n\"<\/span>);\n    <span style=\"color: #ea580c;\">exit<\/span>(<span style=\"color: #16a34a;\">1<\/span>);\n}\n\n<span style=\"color: #0891b2;\">$crawler<\/span> = <span style=\"color: #ea580c;\">new<\/span> <span style=\"color: #9333ea;\">Crawler<\/span>(<span style=\"color: #0891b2;\">$payload<\/span>[<span style=\"color: #dc2626;\">'html'<\/span>]);\n<span style=\"color: #0891b2;\">$countries<\/span> = [];\n\n<span style=\"color: #0891b2;\">$crawler<\/span>-&gt;<span style=\"color: #9333ea;\">filter<\/span>(<span style=\"color: #dc2626;\">'.country'<\/span>)-&gt;<span style=\"color: #9333ea;\">each<\/span>(<span style=\"color: #ea580c;\">function<\/span> (<span style=\"color: #9333ea;\">Crawler<\/span> <span style=\"color: #0891b2;\">$node<\/span>) <span style=\"color: #ea580c;\">use<\/span> (&<span style=\"color: #0891b2;\">$countries<\/span>): <span style=\"color: #ea580c;\">void<\/span> {\n    <span style=\"color: #0891b2;\">$countries<\/span>[] = [\n        <span style=\"color: #dc2626;\">'name'<\/span> =&gt; <span style=\"color: #9333ea;\">normalizeText<\/span>(<span style=\"color: #0891b2;\">$node<\/span>-&gt;<span style=\"color: #9333ea;\">filter<\/span>(<span style=\"color: #dc2626;\">'.country-name'<\/span>)-&gt;<span style=\"color: #9333ea;\">text<\/span>()),\n        <span style=\"color: #dc2626;\">'capital'<\/span> =&gt; <span style=\"color: #9333ea;\">normalizeText<\/span>(<span style=\"color: #0891b2;\">$node<\/span>-&gt;<span style=\"color: #9333ea;\">filter<\/span>(<span style=\"color: #dc2626;\">'.country-capital'<\/span>)-&gt;<span style=\"color: #9333ea;\">text<\/span>()),\n        <span style=\"color: #dc2626;\">'population'<\/span> =&gt; <span style=\"color: #9333ea;\">normalizeText<\/span>(<span style=\"color: #0891b2;\">$node<\/span>-&gt;<span style=\"color: #9333ea;\">filter<\/span>(<span style=\"color: #dc2626;\">'.country-population'<\/span>)-&gt;<span style=\"color: #9333ea;\">text<\/span>()),\n        <span style=\"color: #dc2626;\">'area'<\/span> =&gt; <span style=\"color: #9333ea;\">normalizeText<\/span>(<span style=\"color: #0891b2;\">$node<\/span>-&gt;<span style=\"color: #9333ea;\">filter<\/span>(<span style=\"color: #dc2626;\">'.country-area'<\/span>)-&gt;<span style=\"color: #9333ea;\">text<\/span>()),\n    ];\n});\n\n<span style=\"color: #ea580c;\">if<\/span> (<span style=\"color: #0891b2;\">$countries<\/span> === []) {\n    <span style=\"color: #9333ea;\">fwrite<\/span>(<span style=\"color: #6366f1;\">STDERR<\/span>, <span style=\"color: #dc2626;\">\"No countries were parsed.\\n\"<\/span>);\n    <span style=\"color: #ea580c;\">exit<\/span>(<span style=\"color: #16a34a;\">1<\/span>);\n}\n\n<span style=\"color: #0891b2;\">$csvHandle<\/span> = <span style=\"color: #9333ea;\">fopen<\/span>(<span style=\"color: #6366f1;\">__DIR__<\/span> . <span style=\"color: #dc2626;\">'\/countries.csv'<\/span>, <span style=\"color: #dc2626;\">'w'<\/span>);\n\n<span style=\"color: #ea580c;\">if<\/span> (<span style=\"color: #0891b2;\">$csvHandle<\/span> === <span style=\"color: #6366f1;\">false<\/span>) {\n    <span style=\"color: #9333ea;\">fwrite<\/span>(<span style=\"color: #6366f1;\">STDERR<\/span>, <span style=\"color: #dc2626;\">\"Could not create countries.csv.\\n\"<\/span>);\n    <span style=\"color: #ea580c;\">exit<\/span>(<span style=\"color: #16a34a;\">1<\/span>);\n}\n\n<span style=\"color: #9333ea;\">fputcsv<\/span>(<span style=\"color: #0891b2;\">$csvHandle<\/span>, [<span style=\"color: #dc2626;\">'Country'<\/span>, <span style=\"color: #dc2626;\">'Capital'<\/span>, <span style=\"color: #dc2626;\">'Population'<\/span>, <span style=\"color: #dc2626;\">'Area (km2)'<\/span>], <span style=\"color: #dc2626;\">','<\/span>, <span style=\"color: #dc2626;\">'\"'<\/span>, <span style=\"color: #dc2626;\">''<\/span>);\n\n<span style=\"color: #ea580c;\">foreach<\/span> (<span style=\"color: #0891b2;\">$countries<\/span> <span style=\"color: #ea580c;\">as<\/span> <span style=\"color: #0891b2;\">$country<\/span>) {\n    <span style=\"color: #9333ea;\">fputcsv<\/span>(<span style=\"color: #0891b2;\">$csvHandle<\/span>, [\n        <span style=\"color: #0891b2;\">$country<\/span>[<span style=\"color: #dc2626;\">'name'<\/span>],\n        <span style=\"color: #0891b2;\">$country<\/span>[<span style=\"color: #dc2626;\">'capital'<\/span>],\n        <span style=\"color: #0891b2;\">$country<\/span>[<span style=\"color: #dc2626;\">'population'<\/span>],\n        <span style=\"color: #0891b2;\">$country<\/span>[<span style=\"color: #dc2626;\">'area'<\/span>],\n    ], <span style=\"color: #dc2626;\">','<\/span>, <span style=\"color: #dc2626;\">'\"'<\/span>, <span style=\"color: #dc2626;\">''<\/span>);\n}\n\n<span style=\"color: #9333ea;\">fclose<\/span>(<span style=\"color: #0891b2;\">$csvHandle<\/span>);\n\n<span style=\"color: #9333ea;\">file_put_contents<\/span>(<span style=\"color: #6366f1;\">__DIR__<\/span> . <span style=\"color: #dc2626;\">'\/countries.json'<\/span>, <span style=\"color: #9333ea;\">json_encode<\/span>(<span style=\"color: #0891b2;\">$countries<\/span>, <span style=\"color: #6366f1;\">JSON_PRETTY_PRINT<\/span> | <span style=\"color: #6366f1;\">JSON_UNESCAPED_SLASHES<\/span>));\n\n<span style=\"color: #ea580c;\">echo<\/span> <span style=\"color: #dc2626;\">'Done! Parsed '<\/span> . <span style=\"color: #9333ea;\">count<\/span>(<span style=\"color: #0891b2;\">$countries<\/span>) . <span style=\"color: #dc2626;\">\" countries.\\n\"<\/span>;\n<span style=\"color: #ea580c;\">echo<\/span> <span style=\"color: #dc2626;\">\"Saved countries.csv and countries.json\\n\"<\/span>;<\/code><\/pre>\n<\/div>\n<p>Remplacez &lsquo;YOUR_API_KEY&rsquo; et ex\u00e9cutez-le comme suit :<\/p>\n<div style=\"margin: 18px 0 26px 0;\">\n<pre style=\"background: #f8fafc; border: 1px solid #e5e7eb; border-radius: 10px; padding: 16px 18px; margin: 0; font-size: 14px; line-height: 1.7;\"><code><span style=\"color: #9333ea;\">php<\/span> scrape.php<\/code><\/pre>\n<\/div>\n<p>Lorsque tout est configur\u00e9 correctement, le script r\u00e9cup\u00e8re la page via Web Unlocker, analyse les 250 pays et \u00e9crit les fichiers countries.csv et countries.json dans le dossier de votre projet.<\/p>\n<h3>Visualisation des r\u00e9sultats<\/h3>\n<p>Une fois le script termin\u00e9, vous pouvez ouvrir le fichier countries.csv imm\u00e9diatement. Les premi\u00e8res lignes ressembleront \u00e0 ceci : <\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-44159\" src=\"https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image2-2.png\" alt=\"pays.csv\" width=\"1152\" height=\"1148\" srcset=\"https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image2-2.png 1152w, https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image2-2-300x300.png 300w, https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image2-2-1024x1020.png 1024w, https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image2-2-150x150.png 150w, https:\/\/floppydata.com\/wp-content\/uploads\/2026\/05\/image2-2-768x765.png 768w\" sizes=\"(max-width: 1152px) 100vw, 1152px\" \/><\/p>\n<p>Vous pouvez maintenant importer le CSV dans une feuille de calcul ou envoyer le JSON dans une autre application. Si vous souhaitez utiliser ce flux de travail pour le suivi des prix, vous pouvez l&rsquo;associer aux <a href=\"https:\/\/floppydata.com\/use-case\/price-monitoring-proxy\/\">proxies de suivi des prix de<\/a> Floppydata. <\/p>\n<h2>Traiter les mesures anti-scraping<\/h2>\n<p>Une simple page statique n&rsquo;est pas difficile \u00e0 analyser, comme nous venons de le voir. Mais les sites prot\u00e9g\u00e9s peuvent \u00eatre un casse-t\u00eate. <\/p>\n<p>Vous pouvez rencontrer des blocages, des donn\u00e9es manquantes, des CAPTCHA, un rendu JavaScript ou des limites de taux. C&rsquo;est l\u00e0 qu&rsquo;un scraper PHP normal commence \u00e0 \u00e9prouver des difficult\u00e9s. <\/p>\n<p>Voici les probl\u00e8mes les plus courants auxquels vous pouvez \u00eatre confront\u00e9 :<\/p>\n<ul>\n<li><strong>Blocage de l&rsquo;adresse IP :<\/strong> Les sites web peuvent bloquer votre adresse IP s&rsquo;ils d\u00e9tectent plusieurs requ\u00eates provenant de la m\u00eame IP sur une courte p\u00e9riode.<\/li>\n<li><strong>CAPTCHAs :<\/strong> Les syst\u00e8mes CAPTCHA sont utilis\u00e9s pour diff\u00e9rencier les robots des humains en pr\u00e9sentant des d\u00e9fis difficiles \u00e0 r\u00e9soudre pour les robots.<\/li>\n<li><strong>Limitation du taux :<\/strong> Les sites web limitent souvent le nombre de requ\u00eates que vous pouvez effectuer dans un laps de temps donn\u00e9 afin d&rsquo;\u00e9viter un scraping excessif.<\/li>\n<li><strong>D\u00e9tection de l&rsquo;agent utilisateur :<\/strong> Les agents utilisateurs qui ne sont pas des navigateurs sont bloqu\u00e9s parce qu&rsquo;ils ne ressemblent pas \u00e0 de vrais visiteurs.<\/li>\n<li><strong>D\u00e9fis JavaScript :<\/strong> Le contenu n&rsquo;est charg\u00e9 qu&rsquo;apr\u00e8s l&rsquo;ex\u00e9cution de JavaScript, ce qu&rsquo;une simple requ\u00eate HTTP peut ne pas faire.<\/li>\n<\/ul>\n<p>Vous pouvez essayer de r\u00e9soudre ces probl\u00e8mes manuellement, mais ce n&rsquo;est ni pratique ni \u00e9volutif.<\/p>\n<p>C&rsquo;est l\u00e0 que Floppydata Web Unlocker entre en jeu. Au lieu de relever chaque d\u00e9fi vous-m\u00eame, vous pouvez vous d\u00e9charger de toute la couche anti-bot et vous concentrer sur l&rsquo;extraction et le stockage des donn\u00e9es. <\/p>\n<p><strong>Les poign\u00e9es de Floppydata Web Unlocker :<\/strong><\/p>\n<ul>\n<li>Rotation d&rsquo;IP avec un grand nombre de proxies r\u00e9sidentiels et de centres de donn\u00e9es<\/li>\n<li>Empreintes des navigateurs et navigateurs sans t\u00eate<\/li>\n<li>Rendu JavaScript pour les pages dynamiques<\/li>\n<li>R\u00e9essais automatiques et r\u00e9solution du CAPTCHA<\/li>\n<li>Ciblage g\u00e9ographique jusqu&rsquo;au niveau de la ville<\/li>\n<\/ul>\n<p>Si vous avez besoin de plus de contr\u00f4le, Floppydata propose \u00e9galement des <a href=\"https:\/\/floppydata.com\/proxy-type\/isp-proxy\/\">proxys r\u00e9sidentiels statiques<\/a> pour le scraping de longue dur\u00e9e et des <a href=\"https:\/\/floppydata.com\/proxy-type\/datacenter-proxy\/\">proxys de centre de donn\u00e9es<\/a> pour le travail en volume \u00e0 grande vitesse.<\/p>\n<p>Mais pour la plupart des pages prot\u00e9g\u00e9es, Web Unlocker est le moyen le plus rapide de passer d&rsquo;une requ\u00eate bloqu\u00e9e \u00e0 un code HTML analysable.<\/p>\n<h2>Derni\u00e8res r\u00e9flexions<\/h2>\n<p>PHP est un langage tr\u00e8s performant pour le web scraping, et vous devriez maintenant avoir des bases solides sur le web scraping avec PHP.<\/p>\n<p>Je vais arr\u00eater ce tutoriel \u00e0 ce stade puisqu&rsquo;il s&rsquo;agit d&rsquo;une introduction au web scraping avec PHP. Dans les prochains tutoriels, nous d\u00e9velopperons notre scraper afin qu&rsquo;il puisse suivre les liens, g\u00e9rer la pagination et scanner des cibles plus complexes. <\/p>\n<p>Si vous souhaitez en savoir plus sur le web scraping, consultez les ressources suivantes :<\/p>\n<ul>\n<li><a href=\"https:\/\/floppydata.com\/blog\/what-is-web-unblocker\/\">Qu&rsquo;est-ce qu&rsquo;un d\u00e9bloqueur de sites web ?<\/a><\/li>\n<li><a href=\"https:\/\/floppydata.com\/blog\/best-proxies-for-web-scrapers\/\">Les meilleurs proxys pour les racleurs de sites web<\/a><\/li>\n<\/ul>\n<p>Pr\u00eat \u00e0 essayer le Web Unlocker ? Commencez <a href=\"https:\/\/app.floppydata.com\/\">d\u00e8s aujourd&rsquo;hui<\/a> avec 5 scraps gratuits et scrapez tout ce que vous voulez sans vous prendre la t\u00eate.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction PHP a \u00e9t\u00e9 l&rsquo;un de mes premiers langages en tant que d\u00e9veloppeur web \u00e0 l&rsquo;\u00e9poque, et j&rsquo;aime toujours l&rsquo;utiliser pour le scraping. Ce tutoriel couvre ce que j&rsquo;utilise r\u00e9ellement en production. Je vous guiderai \u00e0 travers un workflow complet de scraping web en PHP en utilisant Floppydata Web Unlocker comme couche de scraping. Pourquoi [&hellip;]<\/p>\n","protected":false},"author":15,"featured_media":44216,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[561,439,487],"tags":[],"class_list":["post-44363","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scraping","category-blog","category-how-to"],"acf":[],"_links":{"self":[{"href":"https:\/\/floppydata.com\/fr\/wp-json\/wp\/v2\/posts\/44363","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/floppydata.com\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/floppydata.com\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/floppydata.com\/fr\/wp-json\/wp\/v2\/users\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/floppydata.com\/fr\/wp-json\/wp\/v2\/comments?post=44363"}],"version-history":[{"count":0,"href":"https:\/\/floppydata.com\/fr\/wp-json\/wp\/v2\/posts\/44363\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/floppydata.com\/fr\/wp-json\/wp\/v2\/media\/44216"}],"wp:attachment":[{"href":"https:\/\/floppydata.com\/fr\/wp-json\/wp\/v2\/media?parent=44363"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/floppydata.com\/fr\/wp-json\/wp\/v2\/categories?post=44363"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/floppydata.com\/fr\/wp-json\/wp\/v2\/tags?post=44363"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}