Parser les publications Facebook avec cURL et simpleXML en PHP

Mathieu Chartier Programmation 28 commentaires

Les parseurs de contenus sont souvent intéressants car ils permettent de récupérer des informations sur les sites externes afin de les syndiquer et les afficher dans nos propres pages ou systèmes en ligne. Les réseaux sociaux sont devenus logiquement la cible des développeurs car nous cherchons parfois à récupérer nos publications (ou autres informations) à la volée pour les afficher sur nos sites web (c'est le cas sur mon site www.internet-formation.fr, je parse les publications de ma page pro Google+ par exemple). Notre cible sera Facebook aujourd'hui, et peut-être que je vous donnerai d'autres méthodes à l'avenir pour d'autres réseaux sociaux (si vous êtes sage !!! :D).

Vous pouvez télécharger le code du parseur dans le fichier suivant, en sachant que le style et l'affichage peuvent être totalement modifiés bien entendu (le rendu affiché ci-dessous correspond au code PHP fourni et à la capture finale de cet article).

Télécharger “Parseur Facebook”parser-facebook.zip – Téléchargé 24105 fois – 2,54 Ko

Comment parser avec PHP ?

Il existe plusieurs méthodes pour récupérer des contenus provenant d'autres sites. Toutes ont leurs avantages et inconvénients, et je dirais que c'est davantage nos habitudes qui nous font pencher pour une technique plutôt qu'une autre. En voici une courte liste :

  • récupérer des flux RSS (ou Atom) et les informations qu'il contient grâce à JSON ou simpleXML ;
  • récupérer des informations avec cURL ou file_get_contents() en PHP (ou autre langage) puis traiter les contenus ;
  • mélanger ces deux types de techniques.

Nous allons mélanger les deux méthodes dans notre cas pour Facebook, mais sachez qu'un parseur avec simpleXML pourrait suffire au fond, bien que ce soit peut-être moins efficace à la longue.

Quelles données dans les flux RSS de Facebook ?

Facebook ne fournit pas beaucoup d'informations dans ses flux RSS ou Atom des pages professionnelles, nous devons donc nous contenter du minimum, que ce soit en termes de contenus mais aussi du point de vue technique. Par exemple, les publications n'ont pas de titre à proprement parler, il s'agit uniquement du début des publications, donc parfois, le doublon est gênant voir perturbant quand nous voulons parser proprement.

Nous allons récupérer les données suivantes grâce à l'ID de la page (ou du compte) de l'utilisateur :

  • titre généré de publication ;
  • date de publication ;
  • auteur de la publication (toujours le même dans le cas d'une page unique) ;
  • contenu des posts.

Pour rappel, il suffit de vous rendre dans une page professionnelle puis de cliquer sur "Paramètres", "Informations sur la page" puis "Identifiant de page Facebook" pour récupérer l'ID qui nous sera utile pour faire fonctionner le parseur (voir illustration ci-dessous).

récupération Id page Facebook

Parser en PHP sur Facebook avec cURL et simpleXML

La base du parseur PHP est fondée sur l'URL des flux de Facebook, qui ressemble à ceci : https://www.facebook.com/feeds/page.php?id=xxxxxxxxxxxxx&format=rss20 (les formats tolérés sont "json", "atom10" et "rss20", c'est ce dernier qui nous intéresse ici !).

Pour faire fonctionner le système, cURL nous permet de lire le flux RSS ou Atom et de récupérer les contenus avec la méthode que nous préférons, que ce soit simpleXML ou JSON. J'ai opté pour simpleXML ici mais j'aurais très bien pu obtenir un résultat équivalent avec JSON.

L'avantage de cURL est de permettre d'une part d'opter pour l'un ou l'autre des deux systèmes mais aussi d'ajouter plusieurs options de crawl non négligeables afin d'être "discret" auprès de Facebook. Par exemple, nous pouvons passer par un proxy, cacher notre URL referer, suivre les redirections, ajouter des entêtes... Au final, ces quelques atouts permettent d'être plus transparents auprès de Facebook, c'est pourquoi j'ai choisi cette technique, bien qu'elle rajoute quelques lignes de code.

Sans plus attendre, passons au code et entrons dans le vif du sujet. La fonction parserFacebook() prend trois paramètres :

  1. ID de la page Facebook.
  2. Nombre de publications à afficher (de 1 à 25 normalement mais souvent de 1 à 10 maximum), fixé à 5 par défaut.
  3. Affichage des illustrations (true) ou non (false) dans les publications, fixé sur "false" par défaut. Ainsi, nous pouvons afficher uniquement les textes et les liens ou choisir d'afficher les contenus complets tels qu'affichés dans les flux RSS et Atom de Facebook.
Voici la fonction PHP complète avec cURL et simpleXML :
function parserFacebook($idPage = '', $nb = 5, $keepImg = false) {
	// URL de Facebook
	$url = "https://www.facebook.com/feeds/page.php?id=";
	$url.= $idPage;
	$url.= "&format=rss20"; // ou "json" ou "atom10"

	// Lancement de cURL
	$curl = curl_init($url);

	// Ajout d'entêtes pour se faire passer pour un robot
	$header = array(
		"Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
		"Cache-Control: max-age=0",
		"Accept-Charset: UTF-8;q=0.7,*;q=0.7",
		"Pragma: " // Pas de cache par défaut
	);
	
	// User-agent automatique (au pire, en choisir un précis)
	$ua = $_SERVER['HTTP_USER_AGENT'];
	
	// URL referer à renvoyer à Facebook (vide recommandé !)
	$referer = "";
	
	// Timeout de cURL
	$timeout = 30;
	
	// Options de cURL
	curl_setopt($curl, CURLOPT_USERAGENT, $ua);
	curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
	curl_setopt($curl, CURLOPT_REFERER, $referer);
	curl_setopt($curl, CURLOPT_AUTOREFERER, true);
	curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
	curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
	curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, $timeout);
	curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
	curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);

	// Exécution de cURL
	$cURLxml = curl_exec($curl);

	// Fermeture de cURL
	curl_close($curl);

	// Récupération des données XML avec simpleXML
	$simpleXML = simplexml_load_string($cURLxml);
	$simpleXML = $simpleXML->channel->item;

	// Conservation uniquement des posts réels
	foreach($simpleXML as $item) {
		$verif = preg_match("#(/posts/|/photos/|permalink)#iU", $item->link);
		if($verif == true) {
			$tabItem[] = $item;
		}
	}

	// Instanciation des variables par défaut
	$resultat = '';
	$i = 0;
	
	// Boucle de récupération des résultats
	foreach($tabItem as $item) {
		// Instanciation des variables
		$urlPage= "https://www.facebook.com/".$idPage;
		$date	= date("d/m/Y à h:i:s", strtotime($item->pubDate));
		$auteur	= $item->author;
		$lien	= $item->link;
		$titre	= trim($item->title);
		$texte	= trim($item->description);
		
		// Tant que le nombre de résultats correspond à nos souhaits
		if($i < $nb) {
			// Supprime les sauts de ligne inutiles
			$regex = '#(<br(/?)>)+(<a(.*)>(.*)</a>)(<br(/?)>)?#iU';
			$texte = preg_replace($regex, '$3', $texte);
			$regex = '#(<br(/?)>){2,}#iU';
			$texte = preg_replace($regex, '<br/>', $texte);

			// On supprime les images si on ne veut garder que le texte
			if($keepImg == false) {
				$regex = '#(<a(.*)><img(.*)></a>)#iU';
				$texte = preg_replace($regex, '', $texte);
			} else {
				$regex = '#(<a(.*)><img(.*)></a>)#iU';
				$texte = preg_replace($regex, '<p>$1<p>', $texte);
			}

			// Suppression du titre répété dans le texte...
			$texte = str_ireplace($titre, '', $texte);

			// Formatage du résultat
			$resultat .= '<div class="block">';
			$resultat .= '<h3 class="titre"><a href="'.$lien.'" target="_blank">'.$titre.'</a></h3>';
			$resultat .= '<div class="meta">Publié le '.$date.' par <a href="'.$urlPage.'" target="_blank">'.$auteur.'</a></div>';
			$resultat .= '<div class="contenu">'.$texte.'</div>';
			$resultat .= '</div>';
		} else {
			break;
		}

		// Incrémentation
		$i++;
	}
	
	// Retourne le résultat final
	return $resultat;
}
?>

Parser PHP avec cURL, simpleXML et JSON pour Facebook

Si ce parseur PHP vous a plu, n'hésitez pas à m'en demander pour d'autres réseaux ou sous d'autres, cela pourra faire l'objet d'autres articles à l'avenir, il m'arrive parfois de manquer d'idée mais vous êtes ma source d'inspiration alors je jette cette bouteille à la mer... :D

28 commentaires

  • Parser facebook peut-il éventuellement être une action envisageable pour augmenter le nombre d'interaction sur cette plateforme?

  • Tom13c dit :

    Il a l'air bien pratique ce parseur, je vais regarder de plus près. Merci

    Au passage il y a un moyen encore plus rapide pour récupérer les id's de pages Facebook:
    -clic sur le logo de la page
    -on regarde l'url du logo affiché ex https://www.facebook.com/XXXX/photos/a.536358959753235.1073765245.528643891007112/558994890820155/?type=1&theater
    -l'id est la dernière série de chiffre de la chaîne de caractères a.536358959753235.1073765245.528643891007112 donc ici 528643891007112

    Et enfin la même chose pour Twitter serait top :-)

  • Menozzi Sebastien dit :

    Bonjour, il y a un problème au niveau du foreach: ligne 68 . La variable n'est pas définit et le il y a un invalide argument au niveau du foreach. Seriez-vous me dire ce qu'il ne va pas? Merci ;)

    • Bonsoir,
      Vous m'avez mis le doute alors j'ai testé mon code à nouveau pour voir si j'avais une erreur mais je n'en ai aucune... Etes-vous en PHP 5 dans vos paramétrages ? Avez-vous activé cURL et simpleXML sur votre serveur (local ou non) ? Si vous avez une erreur "invalid argument supplied for foreach" au niveau du foreachn cela signifie que le premier argument ($tabItem ici) n'est pas un tableau alors que c'est ce qui est attendu... Sauf que dans notre cas, ça ne peut être qu'un tableau (même d'une seule donnée ou vide), sauf si vous êtes en PHP 4 ou que cURL ou SimpleXML n'est pas actif... Je ne vois que ça ! ^^

  • Menozzi Sebastien dit :

    Bonjour, ma version de php est 5.4.16, et php_curl est activé. Je me suis rebdu compte qu'enfaite, seul l'id que vous utilisez dans l'exemple marche et affiche sans erreurs. Quand je rentre un autre id existant de n'importe qu'elle autre page. Cela affiche l'erreur. Je ne comprend pas.

    • Bien vu !
      En fait, il y avait une différence d'URL (pour parser) entre les pages Facebook initiales et celles qui ont un nom particulier du genre https://www.facebook.com/NOM_PAGE. Pour réparer le souci, il suffit de modifier la ligne $verif = preg_match("#/posts/#iU", $item->link); par ce qui suit :
      $verif = preg_match("#(/posts/|permalink)#iU", $item->link);.
      Après, ça marche parfaitement. J'ai remis à jour le fichier ici et le code de l'article ! ^^

  • Menozzi Sebastien dit :

    J'ai toujours la même erreur avec le changement, je suis sûr qu'il n'y a pas de rapport avec ma configuration. Pouvez-vous m'envoyer le code que vous avez testé à mon adresse mail s'il vous plaît?

  • Menozzi Sebastien dit :

    Je ne sais pas du tout, je ne connais pas bcp les expressions régulières regex, les foreach... Si vous arrivez à trouver la solution, faites moi signe ;) , cependant, je vais qd mm rechercher la cause de ce problème.

    • Si vous téléchargez la nouvelle version du script dans l'article, cela devrait être réglé... J'ai refait des tests à l'instant avec 7 pages Facebook différentes (certaines à moi qui étaient renommées ou non, certaines de sociétés externes avec ID apparent), tous ont fonctionné. Au pire, passez par email pour m'indiquer l'ID de page Facebook que vous testez et qui plante, peut-être qu'il y a une subtilité que je n'ai pas encore vu...

  • Fred dit :

    Bonjour,

    Tout d'abord je tenais à vous remercier pour ce script qui m'a appris beaucoup sur curl que je ne connaissais pas. J'ai cependant un problème je tente désespérément d'utiliser ce script avec JSON. J'ai essayé tout type de modifications mais rien n'y fait le mieux que j'ai pu obtenir c'est d'afficher le rss JSON tel qu'il apparaît sur la page web. Je n'ai pas réussi à récupérer chaque donnée individuellement. Je sais le faire avec file_get_contents() mais ça ne marche pas avec curl enfin je n'y suis pas parvenue. Pourriez-vous m'aider?

    • Bonjour,
      Pour être honnête, j'ai un peu galéré avec JSON aussi car je pense que les flux RSS récupérés via cURL ne donnent pas une entière satisfaction pour se transformer dans ce format, c'est d'ailleurs pour ça que je suis passé par simpleXML à la place. Je pense qu'il faudrait plutôt passer par l'API de Facebook pour parser les flux en JSON, mais je n'ai pas eu le temps de me pencher plus en détail sur la question, donc je ne veux pas vous dire de bêtises...

  • Fred dit :

    Dans un sens ça me rassure je commençais à me demander si c'était moi ou Json qui avait un problème. :) En tous cas merci encore et bonne continuation.

  • Fred dit :

    Bon ben j'ai finalement réussi en faisant un mix de ton script et d'un autre. Si ça t'intéresse le voici:
    // Url à parcourir
    $url = 'https://www.facebook.com/feeds/page.php?id=313498825493667&format=json';

    // Initialisation de cURL
    $ch = curl_init($url);

    // User-agent automatique (au pire, en choisir un précis)
    $ua = $_SERVER['HTTP_USER_AGENT'];
    // URL referer à renvoyer à Facebook (vide recommandé !)
    $referer = "";
    // Timeout de cURL
    $timeout = 30;

    // Options
    $options = array(
    CURLOPT_USERAGENT => $ua,
    CURLOPT_HTTPHEADER => array('Content-type: application/json'),
    CURLOPT_REFERER => $referer,
    CURLOPT_AUTOREFERER => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_TIMEOUT => $timeout,
    CURLOPT_SSL_VERIFYPEER => false,
    CURLOPT_SSL_VERIFYHOST => false,
    );

    // Bind des options et de l'objet cURL que l'on va utiliser
    curl_setopt_array($ch, $options);

    // Récupération du résultat JSON
    $json = json_decode(curl_exec($ch));

    // Affichage du nom de l'employé 1
    echo $json->link;

    curl_close($ch);

  • nakwada dit :

    Salut Mathieu !

    Ton script m'a été utile et m'a permis d'apprendre des choses.

    Utile au départ, mais par la suite, en l'utilisant avec d'autres pages, j'ai constaté des problèmes notamment dans le style css de mes 'block' de news.
    En effet, le contenu des posts extraits du flux contient du code css mélangé avec le texte et en particulier sur les liens.

    Je me suis (largement) inspiré de ton script pour coder le miens, qui non seulement récupère le flux au format JSON, mais en plus supprime toutes les balises dont le css perturbait mon css sur les 'block'.

    Ma version dispo ici si besoin : http://akwanet.olympe.in/

    Merci :)

    • Merci et bravo surtout pour l'évolution de ton script. Mon code n'était qu'un début donc je suis fier que ça ait pu te servir à en faire quelque chose de plus costaud et poussé ! Merci pour le lien aussi, ça devrait aider certaines personnes.

  • Loru Fabrice dit :

    Bonjour,

    Merci surtout pour ce script que j'utilise depuis un moment et qui fonctionne très bien. Aujourd'hui en allant sur un site que j'utilise avec ce code je me suis aperçu que les posts de Facebook ne remonte plus. J'ai testé l'url dans un navigateur et la page est introuvable : "Cette page n’est malheureusement pas disponible." ???? Une évolution de Facebook ?

    • Bonjour,
      J'avoue que vous me posez une colle, mais c'est fort probable que l'URL ait changé récemment (Facebook change sans arrêt...). Si j'ai un peu de temps, je regarderai à ça et je mettrai le code à jour si une modification est à apporter. :D

  • Sebastien Menozzi dit :

    Salut !
    En effet, je viens de tester et ça ne marche plus depuis hier matin je crois. Je me renseigné et j'ai pu voir que l'api est maintenant en v2.2. C'est très chiant car dans certain endroit , la syntaxe change et en plus, la récupération feed ne se fait maintenant qu'avec l'api avec un token.
    Donc, c'est maintenant impossible de récupérer les posts Facebook sans être connecté à l'api :/ .
    Quel dommage...

    • Pour information, le parseur fonctionne encore chez moi, sauf en format JSON (il fonctionne avec rss20 et atom10). Je ne constate donc aucun changement pour le moment, sans passer par l'API. :S

  • nakwada dit :

    Bonjour à tous,

    Oui, la récupération des posts via JSON ne fonctionne plus, Facebook l'avait annoncé il y a environ 3 mois (fermeture le 28 Janvier), soit disant que c'était trop peu utilisé pour être maintenu.
    C'est aussi et surtout pour nous forcer à utiliser le Graph API, c'est regrettable :(

  • Nicolas Roehm dit :

    Bonjour,

    J'utilise le parserFacebook et j'ai ajouté une condition permettant d'identifier si la page Facebook est privée ou ne contient pas d'articles.

    Pour ce faire, il faut ajouter : if(isset($tabItem)) au dessus de la boucle de récupération des résultats : foreach($tabItem as $item){}

  • Mohamed dit :

    Bonjour,
    le tuto est très intéressant.
    je suis entraine de réaliser une application qui donne la permission de gérer plusieurs compte Facebook (comme le hootsuit), mais j'ai un male compréhension des api Facebook, est ce que vous pouvez m'aider svp.

  • brunet dit :

    Bonjour,
    Merci pour ce tuto,
    Y a t'il une restriction à l'utilisation de ce script pour récupérer les contenus de pages évènement sur Facebook en nombre ?
    Merci

    • Bonjour,
      En théorie si mais dans tous mes tests non, ce script "scrape" les contenus donc ça semble fonctionner sans trop de limite à ce jour. Toutefois, le script n'est plus aussi bon qu'à l'époque où je l'ai écrit, je tiens à le préciser, il faudra peut-être le remanier un peu...

  • weno dit :

    bonjour a tous.
    qui aurait la version actuelle du parseur?

  • Déposer un commentaire

    Répondre à Sebastien Menozzi Annuler la réponse

    L'adresse de messagerie ne sera pas publiée.* Champs obligatoires