NodeJS PhantomJS screenshot via Express

In my first blog post about NodeJS, I thought it would neat to utilize PhantomJS to fetch a URL, take a screenshot, and serve it back to the user as a static asset.

Install NodeJS & PhantomJS via brew, if you haven't already:

brew install node
brew install phantomjs

Create a new directory, and define a new file: package.json, contents:

{
  "name": "phantomjs_screenshot",
  "description": "phantomjs screeshot",
  "version": "0.0.1",
  "private": true,
  "dependencies": {
    "express": "3.x",
    "phantom": "*",
    "jade": "*"
  }
}

Install dependencies:

npm install

I used Express to handle the routes and serve static assets, and Jade as the HTML middleware.

I create a views subdirectory for Jade with a new layout, file: views/layout.jade

doctype html
html(lang="en")
  head
    title #{title}
  body
    header
      h1 #{title}
    .container
      block content

And another view file for the index page, which creates a form with an input element for URL. file: views/index.jade.

extend layout
block content
  form(name="process_url", action="/process_url", method="post")
    input(type="text", name="url")
    input(type="submit", value="Submit")

I then created the main app file "app.js" to run the server.

var express = require('express');
var app = express();

// define the public directory for static assets
var public_dir = __dirname + '/public';

// setup express
app.use(express.compress());
app.use(express.static(public_dir));
app.use(express.json());
app.use(express.urlencoded());

// setup jade
app.set('views', __dirname + '/views')
app.set('view engine', 'jade')

// route: get: /
app.get('/', function (req, res) {
  res.render('index',
    { title : 'NodeJS PhantomJS Screenshot' }
  )
});

// route: post: /process_url
app.post('/process_url', function (req, res) {

  // get url to process
  var url_to_process = req.body.url;
  if (url_to_process === undefined || url_to_process == '') {
    res.writeHead(404, {'Content-Type': 'text/plain'});
    res.end("404 Not Found");
  }

  // phantomjs screenshot
  var phantom = require('phantom');
  phantom.create(function(ph){
    ph.createPage(function(page){
      page.open(url_to_process, function(status){
        if (status == "success") {
          // put images in public directory
          var image_file_name = url_to_process.replace(/\W/g, '_') + ".png"
          var image_path = public_dir + "/" + image_file_name
          page.render(image_path, function(){
            // redirect to static image
            res.redirect('/'+image_file_name);
          });
        }
        else {
          res.writeHead(404, {'Content-Type': 'text/plain'});
          res.end("404 Not Found");
        }
        page.close();
        ph.exit();
      });
    });
  });

});

// start server
var server = app.listen(3000, function() {
  console.log('Listening on port %d', server.address().port);
});

Start the app. Browse to http://localhost:3000 and submit a URL.

node app.js