{"id":1905,"date":"2011-08-31T23:06:00","date_gmt":"2011-08-31T23:06:00","guid":{"rendered":"http:\/\/svay.com\/blog\/?p=1905"},"modified":"2011-11-04T10:31:27","modified_gmt":"2011-11-04T09:31:27","slug":"paris-js-10-introduction-a-phantomjs-un-navigateur-webkit-headless","status":"publish","type":"post","link":"https:\/\/svay.com\/blog\/paris-js-10-introduction-a-phantomjs-un-navigateur-webkit-headless\/","title":{"rendered":"Paris JS #10 : Introduction \u00e0 PhantomJS, un navigateur webkit headless"},"content":{"rendered":"<p><strong>Mise \u00e0 jour<\/strong>\u00a0: la vid\u00e9o est disponible sur <a href=\"http:\/\/lacantine.ubicast.eu\/videos\/parisjs-10\/\">http:\/\/lacantine.ubicast.eu\/videos\/parisjs-10\/<\/a><\/p>\n<p>Pour le dixi\u00e8me meetup ParisJS, j&#8217;ai pr\u00e9sent\u00e9 le projet <a href=\"http:\/\/www.phantomjs.org\/\" hreflang=\"en\">PhantomJS<\/a>. Pour r\u00e9sumer rapidement, PhantomJS est un navigateur Webkit sans interface graphique, qui se pilote en Javascript (ou Coffeescript).<\/p>\n<p>Voil\u00e0 les diapos de ma pr\u00e9sentation (la captation vid\u00e9o sera peut \u00eatre disponible plus tard):<\/p>\n<div id=\"__ss_9080590\" style=\"width: 510px;\"><strong style=\"display: block; margin: 12px 0 4px;\"><a title=\"ParisJS #10 : PhantomJs \" href=\"http:\/\/www.slideshare.net\/mauricesvay\/parisjs-10-phantomjs\" target=\"_blank\">ParisJS #10 : PhantomJs <\/a><\/strong> <iframe loading=\"lazy\" src=\"http:\/\/www.slideshare.net\/slideshow\/embed_code\/9080590\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\" width=\"510\" height=\"426\"><\/iframe><\/p>\n<div style=\"padding: 5px 0 12px;\">View more <a href=\"http:\/\/www.slideshare.net\/\" target=\"_blank\">presentations<\/a> from <a href=\"http:\/\/www.slideshare.net\/mauricesvay\" target=\"_blank\">Maurice Svay<\/a><\/div>\n<\/div>\n<p>Dans les choses que j&#8217;ai oubli\u00e9 de mentionner\u00a0:<\/p>\n<ul>\n<li>PhantomJS fonctionne sous Windows, Mac et Linux<\/li>\n<li>il existe une version en Python, qui permet de cr\u00e9er des plugins pour \u00e9tendre l&#8217;API standard<\/li>\n<\/ul>\n<h2>Les exemples de scripts<\/h2>\n<p>J&#8217;avais pr\u00e9vu des d\u00e9mos, mais je n&#8217;ai pas pu toutes les montrer. Je vais donc les publier ici, dans la suite de l&#8217;article. Certains exemples sont inspir\u00e9s de ceux publi\u00e9s par Nicolas Perriault dans son article <a href=\"http:\/\/blog.akei.com\/javascript\/2011\/scrape-and-test-any-webpage-using-phantomjs.html#disqus_thread\" hreflang=\"en\">Scrape and test any webpage using PhantomJS<\/a>.<\/p>\n<p><!--more--><\/p>\n<h3>Exemple 0\u00a0: Hello world<\/h3>\n<p>Commen\u00e7ons par un exemple simple, afficher &#8220;Hello, world!&#8221; dans la console:<\/p>\n<pre>\/\/exemple pour PhantomJS 1.2\r\nconsole.log(\"Hello, world!\"); phantom.exit();<\/pre>\n<h3>Exemple 1\u00a0: Charger une page Web<\/h3>\n<p>On cr\u00e9e un nouvel objet WebPage qui va permettre de charger le site parisjs.org. Lorsque la page est charg\u00e9e, on affiche le code source de la page.<\/p>\n<pre>\/\/exemple pour PhantomJS 1.2\r\nvar page = new WebPage();\r\npage.open('http:\/\/parisjs.org\/', function (status) {\r\n    if ('success' !== status) {\r\n        console.log(\"Error\");\r\n    } else {\r\n        console.log(page.content);\r\n        phantom.exit();\r\n    }\r\n});<\/pre>\n<h3>Exemple 2\u00a0: Faire un screenshot<\/h3>\n<p>Quasiment la m\u00eame chose, sauf qu&#8217;on fait un screenshot de la page cette fois, qui sera sauvegard\u00e9 dans le fichier parisjs.png. \u00c0 noter qu&#8217;on peut d\u00e9finir le viewport. L&#8217;extension du fichier d\u00e9termine le type de fichier sauvegard\u00e9 (PNG, JPG, ou PDF).<\/p>\n<pre>\/\/Exemple pour PhantomJS 1.2\r\nvar page = new WebPage();\r\npage.viewportSize = {\r\n    width: 1280,\r\n    height: 800\r\n};\r\npage.open(\"http:\/\/parisjs.org\", function (status) {\r\n    if ('success' !== status) {\r\n        console.log(\"Error\");\r\n    } else {\r\n        page.render(\"parisjs.png\");\r\n        phantom.exit();\r\n    }\r\n});<\/pre>\n<h3>Exemple 3\u00a0: Ex\u00e9cuter du code dans le contexte de la page Web<\/h3>\n<p>Cet exemple charge le site parisjs.org. Une fois la page charg\u00e9e, on va ex\u00e9cuter une fonction dans le contexte de cette page. Comme jQuery est dispo sur cette page, on peut directement utiliser <code>$<\/code>. Ici, on va simplement retourner la liste des pr\u00e9sentations pass\u00e9es qui sont list\u00e9es sur la page d&#8217;accueil.<\/p>\n<pre>\/\/Exemple pour PhantomJS 1.2\r\nvar page = new WebPage();\r\nvar result;\r\npage.open('http:\/\/parisjs.org\/', function (status) {\r\n    if ('success' !== status) {\r\n        console.log(\"Error\");\r\n    } else {\r\n        result = page.evaluate(function () {\r\n            var talks = $('ul[data-eventnumber] li');\r\n            var out = [];\r\n            talks.each(function () {\r\n                out.push($(this).text());\r\n            });\r\n            return out.join(\"\\n\");\r\n        });\r\n        console.log(result);\r\n        phantom.exit();\r\n    }\r\n});<\/pre>\n<h3>Exemples 4 et 5\u00a0: &#8220;Scraper&#8221; des sites Web<\/h3>\n<p>Les exemples qui suivent reprennent les concepts des exemples pr\u00e9c\u00e9dents. Le premier extrait la liste des films qui vont sortir sur Allocine.fr. Le second va r\u00e9cup\u00e9rer la carte m\u00e9t\u00e9o sur MeteoFrance.com. Potentiellement, ces exemples violent les conditions g\u00e9n\u00e9rales de ces deux sites, donc ils ne sont l\u00e0 qu&#8217;\u00e0 titre \u00e9ducatif.<\/p>\n<p>Allocin\u00e9\u00a0:<\/p>\n<pre>\/\/Exemple pour PhantomJS 1.2\r\nvar page = new WebPage();\r\nvar result;\r\npage.open('http:\/\/www.allocine.fr\/film\/cettesemaine.html', function (status) {\r\n    if ('success' !== status) {\r\n        console.log(\"Error\");\r\n    } else {\r\n        result = page.evaluate(function () {\r\n            var titles = $('.titlebar h2 a');\r\n            var out = [];\r\n            titles.each(function () {\r\n                out.push($(this).text());\r\n            });\r\n            return out.join(\"\\n\");\r\n        });\r\n        console.log(result);\r\n        phantom.exit();\r\n    }\r\n});<\/pre>\n<p>M\u00e9t\u00e9o France\u00a0:<\/p>\n<pre>\/\/Exemple pour PhantomJS 1.2\r\nvar page = new WebPage();\r\nvar result;\r\npage.viewportSize = {\r\n    width: 1280,\r\n    height: 800\r\n};\r\npage.clipRect = {\r\n    top: 381,\r\n    left: 175,\r\n    width: 452,\r\n    height: 381\r\n};\r\npage.open('http:\/\/france.meteofrance.com\/france\/accueil', function (status) {\r\n    if ('success' !== status) {\r\n        console.log(\"Error\");\r\n    } else {\r\n        page.render(\"meteo.png\");\r\n        phantom.exit();\r\n    }\r\n});<\/pre>\n<h3>Exemple 6\u00a0: R\u00e9cup\u00e9rer les articles link\u00e9s depuis Hacker News, au format PDF pour les sauvegarder dans une Dropbox<\/h3>\n<p>Cet exemple est un peu alambiqu\u00e9, mais montre qu&#8217;il peut y avoir des utilisations cr\u00e9atives de PhantomJS. Dans ce dernier exemple, on va scraper la page d&#8217;accueil de Hacker News pour r\u00e9cup\u00e9rer les liens vers les articles les plus int\u00e9ressants. On va alors r\u00e9cup\u00e9rer le contenu de ces articles via ViewText.org qui va se charger d&#8217;\u00e9liminer tout ce qui n&#8217;est pas int\u00e9ressant (header, navigation, footer, etc.). Ce contenu va \u00eatre sauvegard\u00e9 en PDF dans le dossier Dropbox.<\/p>\n<pre>\/\/Exemple pour PhantomJS 1.2\r\nvar page = new WebPage();\r\nvar dropboxPath = '\/Users\/mauricesvay\/Dropbox\/hackernews';\r\n\r\n\/**\r\n * Get all links from Hacker News front page\r\n *\/\r\nfunction getLinks() {\r\n    var json = page.evaluate(function () {\r\n        var links = $('td.title &gt; a');\r\n        var url = [];\r\n        links.each(function () {\r\n            url.push(this.href);\r\n        }); \/\/can only return simple data structures\r\n        return JSON.stringify(url);\r\n    });\r\n    return JSON.parse(json);\r\n}\r\n\r\n\/**\r\n * Recursively open content-only articles, save as PDF in Dropbox\r\n *\/\r\nfunction saveToDropbox(links) {\r\n    if (links.length == 0) {\r\n        phantom.exit();\r\n        return;\r\n    }\r\n    var url = links.shift();\r\n    var readableUrl = 'http:\/\/viewtext.org\/api\/text?url=' + url; \/\/filesystem friendly filenames\r\n    var filename = [dropboxPath, '\/', url.replace(\/[^a-zA-Z0-9]\/g, '_'), '.pdf'].join('');\r\n    var page = new WebPage();\r\n    page.open(readableUrl, function (status) {\r\n        if (status === 'success') {\r\n            console.log(\"Saving \" + filename); \/\/ Fry says : Not sure if async or buggy\r\n            page.render(filename);\r\n            saveToDropbox(links);\r\n        }\r\n        delete page;\r\n    });\r\n}\r\n\/\/Here we go...\r\npage.open('http:\/\/news.ycombinator.com\/', function (status) {\r\n    if ('success' !== status) {\r\n        console.log(\"Error\");\r\n    } else {\r\n        \/\/inject jQuery into Hacker News\r\n        page.includeJs(\"https:\/\/ajax.googleapis.com\/ajax\/libs\/jquery\/1.6.2\/jquery.min.js\", function () {\r\n            var links = getLinks();\r\n            saveToDropbox(links);\r\n        });\r\n    }\r\n});<\/pre>\n<p>J&#8217;esp\u00e8re que cela vous inspirera et que vous trouverez plein d&#8217;autres utilisations cr\u00e9atives. Pour plus d&#8217;exemples, consultez la <a href=\"http:\/\/code.google.com\/p\/phantomjs\/wiki\/QuickStart\" hreflang=\"en\">documentation officielle<\/a> et <a href=\"https:\/\/github.com\/ariya\/phantomjs\/tree\/master\/examples\" hreflang=\"en\">le projet Github<\/a> qui regorge d&#8217;exemples. N&#8217;h\u00e9sitez pas \u00e0 me poser des questions sur twitter ou dans les commentaires.<\/p>\n","protected":false},"excerpt":{"rendered":"<p><strong>Mise \u00e0 jour<\/strong>&nbsp;: la vid\u00e9o est disponible sur <a href=\"http:\/\/lacantine.ubicast.eu\/videos\/parisjs-10\/\">http:\/\/lacantine.ubicast.eu\/videos\/parisjs-10\/<\/a><\/p>\n<p>Pour le dixi\u00e8me meetup ParisJS, j&#8217;ai pr\u00e9sent\u00e9 le projet <a href=\"http:\/\/www.phantomjs.org\/\" hreflang=\"en\">PhantomJS<\/a>. Pour r\u00e9sumer rapidement, PhantomJS est un navigateur Webkit sans interface graphique, qui se pilote en Javascript (ou Coffeescript).<\/p>\n<p>Voil\u00e0 les diapos de ma pr\u00e9sentation (la captation vid\u00e9o sera peut \u00eatre disponible plus tard):<\/p>\n<div style=\"width:510px\" id=\"__ss_9080590\"> <strong style=\"display:block;margin:12px 0 4px\"><a href=\"http:\/\/www.slideshare.net\/mauricesvay\/parisjs-10-phantomjs\" title=\"ParisJS #10 : PhantomJs \" target=\"_blank\">ParisJS #10 : PhantomJs <\/a><\/strong> <iframe loading=\"lazy\" src=\"http:\/\/www.slideshare.net\/slideshow\/embed_code\/9080590\" width=\"510\" height=\"426\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"><\/iframe> <\/p>\n<div style=\"padding:5px 0 12px\"> View more <a href=\"http:\/\/www.slideshare.net\/\" target=\"_blank\">presentations<\/a> from <a href=\"http:\/\/www.slideshare.net\/mauricesvay\" target=\"_blank\">Maurice Svay<\/a> <\/div>\n<\/p><\/div>\n<p>Dans les choses que j&#8217;ai oubli\u00e9 de mentionner&nbsp;:<\/p>\n<ul>\n<li>PhantomJS fonctionne sous Windows, Mac et Linux<\/li>\n<li>il existe une version en Python, qui permet de cr\u00e9er des plugins pour \u00e9tendre l&#8217;API standard<\/li>\n<\/ul>\n<h2>Les exemples de scripts<\/h2>\n<p>J&#8217;avais pr\u00e9vu des d\u00e9mos, mais je n&#8217;ai pas pu toutes les montrer. Je vais donc les publier ici, dans la suite de l&#8217;article. Certains exemples sont inspir\u00e9s de ceux publi\u00e9s par Nicolas Perriault dans son article <a href=\"http:\/\/blog.akei.com\/javascript\/2011\/scrape-and-test-any-webpage-using-phantomjs.html#disqus_thread\" hreflang=\"en\">Scrape and test any webpage using PhantomJS<\/a>.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[29],"tags":[],"_links":{"self":[{"href":"https:\/\/svay.com\/blog\/wp-json\/wp\/v2\/posts\/1905"}],"collection":[{"href":"https:\/\/svay.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/svay.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/svay.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/svay.com\/blog\/wp-json\/wp\/v2\/comments?post=1905"}],"version-history":[{"count":4,"href":"https:\/\/svay.com\/blog\/wp-json\/wp\/v2\/posts\/1905\/revisions"}],"predecessor-version":[{"id":2191,"href":"https:\/\/svay.com\/blog\/wp-json\/wp\/v2\/posts\/1905\/revisions\/2191"}],"wp:attachment":[{"href":"https:\/\/svay.com\/blog\/wp-json\/wp\/v2\/media?parent=1905"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/svay.com\/blog\/wp-json\/wp\/v2\/categories?post=1905"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/svay.com\/blog\/wp-json\/wp\/v2\/tags?post=1905"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}