I’m a (script driven) robot

Vous l’avez sans doute compris, j’aime beaucoup le scraping.  Pour des cas compliqués, l’émulation d’un véritable browser devient de plus difficile. Certaines protections vont tellement loin dans construction des requêtes successives pour obtenir un résultat que cela devient pénible et aussi instable.

Je suis donc parti, pour ces cas, dans l’approche Selenium, c’est à dire un véritable navigateur sans tête piloté par script. 

Au final je suis parti parti la sous-branche qui procède à cette construction en utilisant google-chrome (c’est fallacieux et amusant à la fois, sachant que je n’utilise jamais ce navigateur).

Il y a des exemples dans beaucoup de langages, mais finalement assez peu sur les bindings en perl.

Grâce à cet article, https://www.perl.com/article/spidering-websites-with-headless-chrome-and-selenium/ la lumière m’est apparue et j’ai gagné beaucoup. It’s more fun to compute en perl. https://en.perlzemi.com/blog/20211119124656.html est aussi très sympa.

J’ai suivi sa procédure, avec quelques adaptations pour mon Ubuntu server. J’ai pris une version plus récente du chrome driver, installation chrome et module Selenium::Remote::Driver sans problèmes. J’avais sur mon système une version de java (pour mon solr) pas compatible semble t’il avec le serveur selenium standalone. J’ai donc mis un openjdk 11 et tout s’est bien emboité.

C’est assez tranquille mais j’ai pas mal erré pour ce qui est de cacher le caractère headless de mon chrome en écrasant la chaîne user-agent d’origine car sinon c’est pas du jeu. Pour une chaîne 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être virtuelle:

$sx = sprintf("%d",1600 + ((rand() - rand()) * 303 ));
$sy = sprintf("%d",900 + ((rand() - rand()) * 256 ));
my $driver;
eval {
$driver = Selenium::Remote::Driver->new(
  browser_name => $ua,
  extra_capabilities => {
    chromeSwitches => [ "--user-agent= '$ua'" ],
    chromeOptions => {
      args => [
        'window-size='.$sx.','.$sy,
        'headless',
        'user-agent='.$ua,
      ],
    },
  },
  );
};

A partir de là, j’ai pu réellement jouer. Le driver Selenium permet pas mal de choses, mais, pour le moment, je récupère surtout la source de la page que je passe ensuite à une XML::LibXML comme à mes habitudes des dernières années. Il est possible de jouer avec des XPaths, des screenshots, des evals de javascript donc plein de choses très amusantes en perspective. Cela permet notamment d’obtenir le DOM interprété plutôt que la source de la page $driver->execute_script("return document.documentElement.outerHTML");

Ne pas oublier à la fin de faire un $driver->quit() pour libérer de la mémoire

Samesite cookies & rails & clueless monkey patch

Une vieille application Ruby on Rails 3. C’était par tourisme de dev et j’aime bien, malgré les particularités de ruby (typage et scope) . Des browsers qui commencent à se plaindre du mauvais voir du manque d’attribut same site sur les cookies (dans mon cas des cookies de session).

https://developer.mozilla.org/fr/docs/Web/HTTP/Headers/Set-Cookie/SameSite

Je commence par bien flipper. Entre toutes les versions de rails, des heures de recherche, j’étais presque résolu à monkey-patcher les libraires mais, étant bien incapable de localiser où frapper, je commençais à désespérer.

Le site étant service par un apache2 sous mod_passenger, la lumière la plus évidente m’est enfin apparue. J’installe et j’active le mod headers d’apache2 puis je rajoute ce segment dans la section qui vas bien de la config apache du site en question:

<ifmodule mod_headers.c>
Header always edit Set-Cookie (.*) "$1; SameSite=strict"
</ifmodule> 

Je redémarre mon apache et mon firefox ne se plaint plus. Magique !!