{"id":371,"date":"2024-03-26T09:18:36","date_gmt":"2024-03-26T09:18:36","guid":{"rendered":"https:\/\/habett.fr\/blog\/?p=371"},"modified":"2024-03-26T09:46:08","modified_gmt":"2024-03-26T09:46:08","slug":"im-a-script-driven-robot","status":"publish","type":"post","link":"https:\/\/habett.fr\/blog\/2024\/03\/im-a-script-driven-robot\/","title":{"rendered":"I\u2019m a (script driven) robot"},"content":{"rendered":"\n<p>Vous l\u2019avez sans doute compris, j\u2019aime beaucoup le scraping.&nbsp; Pour des cas compliqu\u00e9s, l\u2019\u00e9mulation d\u2019un v\u00e9ritable browser devient de plus difficile. Certaines protections vont tellement loin dans construction des requ\u00eates successives pour obtenir un r\u00e9sultat que cela devient p\u00e9nible et aussi instable.<\/p>\n\n\n\n<p>Je suis donc parti, pour ces cas, dans l\u2019approche Selenium, c\u2019est \u00e0 dire un v\u00e9ritable navigateur sans t\u00eate pilot\u00e9 par script.&nbsp;<\/p>\n\n\n\n<p>Au final je suis parti parti la sous-branche qui proc\u00e8de \u00e0 cette construction en utilisant google-chrome (c\u2019est fallacieux et amusant \u00e0 la fois, sachant que je n\u2019utilise jamais ce navigateur).<\/p>\n\n\n\n<p>Il y a des exemples dans beaucoup de langages, mais finalement assez peu sur les bindings en perl.<\/p>\n\n\n\n<p>Gr\u00e2ce \u00e0 cet article, <a href=\"https:\/\/www.perl.com\/article\/spidering-websites-with-headless-chrome-and-selenium\/\">https:\/\/www.perl.com\/article\/spidering-websites-with-headless-chrome-and-selenium\/<\/a> la lumi\u00e8re m\u2019est apparue et j\u2019ai gagn\u00e9 beaucoup. It\u2019s more fun to compute en perl. <a href=\"https:\/\/en.perlzemi.com\/blog\/20211119124656.html\">https:\/\/en.perlzemi.com\/blog\/20211119124656.html<\/a> est aussi tr\u00e8s sympa.<\/p>\n\n\n\n<p>J\u2019ai suivi sa proc\u00e9dure, avec quelques adaptations pour mon Ubuntu server. J\u2019ai pris une version plus r\u00e9cente du chrome driver, installation chrome et module Selenium::Remote::Driver sans probl\u00e8mes. J\u2019avais sur mon syst\u00e8me une version de java (pour mon solr) pas compatible semble t\u2019il avec le serveur selenium standalone. J\u2019ai donc mis un openjdk 11 et tout s\u2019est bien emboit\u00e9.<\/p>\n\n\n\n<p>C\u2019est assez tranquille mais j\u2019ai pas mal err\u00e9 pour ce qui est de cacher le caract\u00e8re headless de mon chrome en \u00e9crasant la cha\u00eene user-agent d\u2019origine car sinon c\u2019est pas du jeu. Pour une cha\u00eene user-agent dans une variable $ua, je me retrouve avec le constructeur suivant, avec un peu de random en plus dans la taille de la fen\u00eatre virtuelle:<\/p>\n\n\n\n<div class=\"wp-block-group\"><div class=\"wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained\">\n<div class=\"wp-block-group\"><div class=\"wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained\">\n<p><code>$sx = sprintf(\"%d\",1600 + ((rand() - rand()) * 303 ));<br>$sy = sprintf(\"%d\",900 + ((rand() - rand()) * 256 ));<br>my $driver;<br>eval {<br>  $driver = Selenium::Remote::Driver-&gt;new(<br>&nbsp; browser_name =&gt; $ua,<br>&nbsp; extra_capabilities =&gt; {<br>&nbsp; &nbsp; chromeSwitches =&gt; [ \"--user-agent= '$ua'\" ],<br>&nbsp; &nbsp; chromeOptions =&gt; {<br>&nbsp; &nbsp; &nbsp; args =&gt; [<br>&nbsp; &nbsp; &nbsp; &nbsp; 'window-size='.$sx.','.$sy,<br>&nbsp; &nbsp; &nbsp; &nbsp; 'headless',<br>&nbsp; &nbsp; &nbsp; &nbsp; 'user-agent='.$ua,<br>&nbsp; &nbsp; &nbsp; ],<br>&nbsp; &nbsp; },<br>&nbsp; },<br>&nbsp; );<br>};<\/code><\/p>\n<\/div><\/div>\n<\/div><\/div>\n\n\n\n<p>A partir de l\u00e0, j\u2019ai pu r\u00e9ellement jouer. Le driver Selenium permet pas mal de choses, mais, pour le moment, je r\u00e9cup\u00e8re surtout la source de la page que je passe ensuite \u00e0 une XML::LibXML comme \u00e0 mes habitudes des derni\u00e8res ann\u00e9es. Il est possible de jouer avec des XPaths, des screenshots, des evals de javascript donc plein de choses tr\u00e8s amusantes en perspective. Cela permet notamment d\u2019obtenir le DOM interpr\u00e9t\u00e9 plut\u00f4t que la source de la page <code>$driver->execute_script(\"return document.documentElement.outerHTML\");<\/code><\/p>\n\n\n\n<p>Ne pas oublier \u00e0 la fin de faire un $driver-&gt;quit() pour lib\u00e9rer de la m\u00e9moire<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Vous l\u2019avez sans doute compris, j\u2019aime beaucoup le scraping.&nbsp; Pour des cas compliqu\u00e9s, l\u2019\u00e9mulation d\u2019un v\u00e9ritable browser devient de plus difficile. Certaines protections vont tellement loin dans construction des requ\u00eates successives pour obtenir un r\u00e9sultat que cela devient p\u00e9nible et aussi instable. Je suis donc parti, pour ces cas, dans l\u2019approche Selenium, c\u2019est \u00e0 dire &hellip; <a href=\"https:\/\/habett.fr\/blog\/2024\/03\/im-a-script-driven-robot\/\" class=\"more-link\">Continuer la lecture de <span class=\"screen-reader-text\">I\u2019m a (script driven) robot<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[25,36],"tags":[44,59],"class_list":["post-371","post","type-post","status-publish","format-standard","hentry","category-code","category-http","tag-browser","tag-scraping"],"_links":{"self":[{"href":"https:\/\/habett.fr\/blog\/wp-json\/wp\/v2\/posts\/371","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/habett.fr\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/habett.fr\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/habett.fr\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/habett.fr\/blog\/wp-json\/wp\/v2\/comments?post=371"}],"version-history":[{"count":2,"href":"https:\/\/habett.fr\/blog\/wp-json\/wp\/v2\/posts\/371\/revisions"}],"predecessor-version":[{"id":373,"href":"https:\/\/habett.fr\/blog\/wp-json\/wp\/v2\/posts\/371\/revisions\/373"}],"wp:attachment":[{"href":"https:\/\/habett.fr\/blog\/wp-json\/wp\/v2\/media?parent=371"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/habett.fr\/blog\/wp-json\/wp\/v2\/categories?post=371"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/habett.fr\/blog\/wp-json\/wp\/v2\/tags?post=371"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}