[Nodejs] APIを利用せずにWEBサービスを利用したい。 #1「Google検索をして初回ページをスクレイピングする」

2015年11月25日

Javascript Nodejs テクノロジー プログラミング 特集

Googleの検索エンジンがSSL対応してから、リファラも取得できないので、検索キーワードがWEBサイト側から取得できなくなり、非常に不便に感じていますが、YahooもGoogleエンジンを採用し、SSL対応もしてしまったので、マーケティング市場は大混乱していますね。

検索をAPI使わずに行いたい

最近、OpenIDやら、TwitterBotやら、SNSの情報取得やら、やたらとAPIで連携するサービスが増えてきました。 ログイン認証などは、新たにサービスにIDとパスワードを登録する手間がいらないので、便利っちゃ〜便利なんですが、連携サービス側としては、keyの取得をしたり、なんやらワケの分からない認証コードを登録したりして、非常に面倒くさい事この上ないです。 さらに、TwitterのAPIで言えば、たまにエラーが出てサーバーのBOT連動などがコケるパターンが増えてきたり、手動だったら問題ないがサーバーで自動化しているモノに関しては、「規定違反」とされて勝手にリジェクトされたりする始末です。 こういう面倒くさい感じであれば、むしろAPIなど利用せずに、こちらのサーバーからどうどうとサービスを利用しに行こうじゃないかと考えて、サーバースクレイピングを発展させてみました。

Googleの検索エンジンを取得しちゃえ

今回は第1弾としてGoogle検索を簡単に行なってみたいと思います。

モジュール構成

OS:CentOS 6.5 webアクセス:Apache WebSocket:NodeJS(port:3336)

サンプルサイト

http://bit.ly/1lIeGD7

使い方

検索キーワードを入力して「検索」ボタンを押すだけです。 検索結果のページから、「件数」「タイトル」「URL」「サンプル文章」などをJSON形式で画面下段に表示します。

解説

WEBページ側の解説は省いて、NodeJS側のソースコードを公開しておきます。 「QS」ライブラリは、Socket.IOがPOSTでデータを受け取る時に必要なライブラリです。 ちなみに、このコードはGoogleの2015/11/22現在における検索ページのスクレイピングなので、以後にこのページの構成が変わった場合はデータの取得ができません。 構成は大きく4つあり、
1、Googleの検索WEBサイトをspookyjsでアクセス。 2、POSTで受け取った検索キーワードを検索フォームに入力 3、Googleページにある検索フォームをSUBMITする。 4、検索結果のページから、各種情報を取得する。
このプログラムをnodeコマンドまたはforeverコマンドで起動しておくだけです。 ページをHUCKすれば、HTML、JS、CSSなどをぶっこぬいて、同じ構成のサーバーを立ち上げることは簡単にできますが、初心者の方でどうしてもプログラムが欲しい方はメールかメッセージでご依頼ください。 /** * Scenario **/ // Init----- var http = require('http'); var QS = require('querystring'); var saveDir = "data/index/sitemap/"; var accessPort = 3336; http.createServer(function(req,res){ res.writeHead(200,{ 'Content-Type':'text/plain', 'Access-Control-Allow-Origin':'*' }); //PostString var postData=''; req.on('data',function(data){ postData += unescape(data); }); req.on('end',function(){ var POST = QS.parse(postData); $$SPK(POST,res); }); }).listen(accessPort); console.log('Server running at http://***:'+accessPort+'/'); //----- //Library (function(){ var SPK = require('spooky'); var $$=function(data,res){ var dt = (+new Date()); var spooky = new SPK({ casper:{ logLevel:'debug', verbose:true, sslProtocol:'any' }, child:{ "ssl-protocol":"tlsv1", "ignore-ssl-errors":true } },function(){ var jsonData={ date:(+new Date()), searchWord:data.word }; spooky.userAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/601.2.7 (KHTML, like Gecko) Version/9.0.1 Safari/601.2.7"); spooky.start("https://google.com/"); //-- spooky.then([{data:data},function(){ var a = this.evaluate(function(data){ document.f.q.value = data.word; document.f.submit(); },data); }]); spooky.then(function(data){ //count var result = this.evaluate(function(){ return document.getElementById("resultStats").innerText; }); var google = this.evaluate(function(){ return location.href; }); var json = { google:google, resultStats:result }; this.emit("result","default",json); }); spooky.then(function(data){ //count var result = this.evaluate(function(){ var rc = document.getElementsByClassName("rc"); var json = []; for(var i=0;i<rc .length;i++){ var url = rc[i].getElementsByClassName("_Rm")[0].innerText; var title = rc[i].getElementsByClassName("r")[0].innerText; var doc = rc[i].getElementsByClassName("st")[0].innerText; json.push({title:title,url:url,doc:doc}); } return json; }); this.emit("result","cite",result); }); spooky.then(function(data){ this.capture("getGoogle.png"); this.emit("end"); }); //-- spooky.run(); spooky.on("result",function(key,msg){ jsonData[key] = msg; }); spooky.on("end",function(){ var json = JSON.stringify(jsonData,null," "); res.end(json); }); }); }; $$SPK = $$; })();