Tuesday, September 23, 2014

Web Scrapping con Haskell y PhantomJS

Hace un tiempo escribí un blog llamado Web scrapping con Julia y PhantomJS...hoy día...quería hacer lo mismo pero esta vez utilizándo Haskell...

El concepto es el mismo...creamos un script en PhantomJS que va a leer una página de un usuario de Twitter page y obtener los hashtags de las 5 primeras páginas...aquí está el script en PhantomJS...

Hashtags.js
var system = require('system');

var webpage = require('webpage').create();
webpage.viewportSize = { width: 1280, height: 800 };
webpage.scrollPosition = { top: 0, left: 0 };

var userid = system.args[1];
var profileUrl = "http://www.twitter.com/" + userid;

webpage.open(profileUrl, function(status) {
 if (status === 'fail') {
  console.error('webpage did not open successfully');
  phantom.exit(1);
 }
 var i = 0,
 top,
 queryFn = function() {
  return document.body.scrollHeight;
 };
 setInterval(function() {
  top = webpage.evaluate(queryFn);
  i++;
   
  webpage.scrollPosition = { top: top + 1, left: 0 };

  if (i >= 5) {
   var twitter = webpage.evaluate(function () {
    var twitter = [];
    forEach = Array.prototype.forEach;
    var tweets = document.querySelectorAll('[data-query-source="hashtag_click"]');
    forEach.call(tweets, function(el) {
     twitter.push(el.innerText);
    });
    return twitter;
   });

   twitter.forEach(function(t) {
    console.log(t);
   });

   phantom.exit();
  }
}, 3000);
});

Si lo ejecutamos, vamos a ver el siguiente resultado...


Ahora...lo que quiero hacer con esta información...es enviarla a Haskell...y obtener los hashtags más utilizados...así que voy a sumarizar los y luego eliminar los que son menores a 5...

Veamos el código en Haskell...

hashtags.hs
import System.Process
import Data.List

hashTags :: String -> IO()
hashTags(user) = do
 let x = readProcess "phantomjs" ["--ssl-protocol=any","Hashtags.js",user] []
 y <- x
 mapM_ print $ sortBy sortGT $ count y

count :: String -> [(String,Int)]
count xs = filter ((>=5).snd) $ 
     map(\ws -> (head ws, length ws)) $ 
           group $ sort $ words xs

sortGT :: (Ord a, Ord a1) => (a1, a) -> (a1, a) -> Ordering
sortGT (a1, b1) (a2, b2)
  | b1 < b2 = GT
  | b1 > b2 = LT
  | b1 == b2 = compare a1 a2

Si lo ejecutamos, vamos a ver el siguiente resultado


Lo bueno de esta aplicación es que podemos pasar cualquier nombre de usuario como parámetro y el resultado va a estar correctamente ordenado y filtrado...otra razón más para amar Haskell -;)

Saludos,

Blag.
Development Culture.

No comments: