Controlling Firefox from Perl with MozRepl

On Friday I wrote my first program using AnyEvent and Coro, and it was so nifty that I decided to revive my moribund blog to describe it. This little program solved a whole raft of problems.

The problem involved determining certain properties of each of a list of URLs and updating a database. The rub is that some properties, such as redirects, are most reliably observed in the browser, and some, such whether the URL is hosted at $WORK, best determined using $WORK’s Perl modules. Now how can we put these two together to get all the info we need?

The approach I hit on involves using Perl to drive an instance of Firefox configured with some helpful extensions. MozRepl is a cool extension that lets you telnet into Firefox and program it from the inside, with access to the entire browser and the Mozilla API. NetExport is an extension to the extension Firebug which generates HAR (HTTP archive) files capturing all the data necessary for the analysis of front-end performance. HAR files serve as input to the command-line versions of PageSpeed and YSlow.

NetExport exports its results either to file or via HTTP POST. So in my program I start an embedded HTTP server, fire up Firefox, telnet into it, load a URL, and let the httpd capture and process the JSON posted by NetExport. Think of the setup as making Firefox puke into a bucket set out for that purpose. A bit imagé but you get the idea.

How do AnyEvent and Coro enter the picture? I use AnyEvent condition variables to coordinate the work between page loading with MozRepl and output handing with the web server, and a Coro thread to tell the web server to kindly stand over there while I continue with my main line of work. The hardest part is reorienting one’s brain towards the asynchronous way of thinking, not so easy after a lifetime of vanilla scripting.

So let’s see some code. The main script is delightfully short and sweet; the annotated version follows. The name of my employer has been changed to protect the innocent. And of course I use strict and warnings.


use AnyEvent;
use Coro;
use WORK::Config;
use WORK::AnyEvent::HTTPD; 
use WORK::AnyEvent::HTTPD::Handler::NetExport;  
use WORK::AnyEvent::MozRepl;
use Log::Log4perl qw(:easy);

my $cfg = WORK::Config::get_config();

# AnyEvent condition variable 

my $cv  = \$WORK::AnyEvent::HTTPD::Handler::NetExport::cv;

my @urls = qw(http://www.google.com http://www.yahoo.com);

# Tell NetExport where to post its results.
my $beacon = "http://localhost:9090/netexport";

# Handlers to process POSTed results.

my $h = WORK::AnyEvent::HTTPD::Handler::NetExport->new;

# Fire up a server and ask it to step out of the way.
async { 
    start_httpd($h);
}

# Fire up FF with good ol' system().

start_firefox();

# Connect to MozRepl with AnyEvent::Socket

mozrepl_connect();

# Set the POST URL and turn on auto export.

set_netexport_prefs($beacon);

while (@urls) {

    $$cv = AnyEvent->condvar; 

    my $url = shift @urls;

    load_page( $url ); #  Using MozRepl

    $$cv->recv;   # The POST handler will send().
    
    clear_cache(); 
}

kill_firefox();  # From within MozRepl.

Neat huh? There’s lots of blanks to fill in, but as this post is already getting a bit long, I will do that in posts to follow.

3 Responses to Controlling Firefox from Perl with MozRepl

  1. christophe says:

    Hello,
    I found this post very interesting about controling Firefox with MozRepl. I would like to try your code, but I can not find the modules WORKS::Config… Never heard about it.
    Could you tell me more about these modules.
    Thanks

    Christophe
    P.S.
    I’m french, so excuse me for my broken english !

    • perlgerl says:

      Bonjour Christophe,

      Par un beau hazard, je parle français. Je vois que le billet est mal écrite. Quand je dis WORK, je veux dire une module particulier à notre environnement au boulot avec les paramètres de configuration. WORK veut dire “Là où je travaille mais qui ne veut pas être identifié dans une communication non officielle”. Cette module n’existe pas en réalité sous ce nom. Quand j’aurai un moment je corrigerai le billet.

      Cordialement,

      Perlgerl

      • christophe says:

        Bonjour Perlgerl,

        Merci pour votre réponse, qui de surcroit est en français, alors je vais en profiter !
        Désolé de ne pas avoir compris la signification du mot-clé ‘WORK’ (je dois être beaucoup plus nul que le le pensais ;-) ), mais précédé du signe $, je pensais qu’il s’agissait d’une notation de Perl nouvelle pour moi.
        Cependant, comment faut-il traduire par exemple la ligne “use WORK::AnyEvent:HTTPD;”, puisque ce module s’utilise habituellement en écrivant :
        “use AnyEvent::HTTPD;” ?

        D’autre part, je voudrais savoir si je suis sur la bonne voie en essayant de mettre en oeuvre ce genre de code.

        Ce que je cherche à faire, c’est simplement, lancer Firefox par l’intermédiaire de l’Add-on MozRepl, ouvrir une page web, et récupérer le contenu de la page entière, ou seulement d’un élément du DOM, mais après que les instructions javascript ou ajax soient exécutées, et sauvegarder ce contenu dans un fichier, tout ça dans un script.

        En utilisant MozRepl directement dans une console avec Telnet, je n’y suis pas arrivé.

        Cela fait plusieurs semaines que je cherche à obtenir ce savoir faire, mais à chaque fois les informations que je trouve sont toujours des considérations très générales sur la manière théorique de faire fonctionner ensemble tous ces modules, avec beaucoup de notions ayant trait au fonctionnement du réseau, et que je n’ai pas.
        Je n’arrive pas à comprendre comment faire marcher un exemple simple.

        Si par hasard vous aviez un tel exemple à me montrer, je serai très intéressé (et aussi très reconnaissant).
        Encore merci pour toutes les infos que je peux trouver grâce à votre blog.
        Cordialement.
        Christophe

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: