はてなカウンターから,1年分のリンク元情報を取得してCalcのシート上に記録するバッチ。 ====
@if(0)==(0) ECHO OFF echo 処理開始時刻: %date% %time% > log.txt rem WSHコードに,第一引数としてカレントフォルダを渡す cscript.exe //nologo //E:JScript "%~f0" "%~dp0" rem cscript.exe //nologo //E:JScript "%~f0" "%~dp0" > log.txt rem 環境変数から「パス名」(フォルダ名)を取り出すには %~pX とする。 rem http://orangeclover.hatenablog.com/entry/20101004/1286120668 echo 終了しました。 echo 処理終了時刻: %date% %time% >> log.txt @pause GOTO :EOF @end /* はてなカウンターから,対象年内のリンク元URLを抽出してExcelに記録するバッチ ・該当はてなIDにログイン済みであること ・バッチ内の設定事項を調整すること */ // ---- 設定事項 // 自分のはてな情報 var hatena_id = "〜〜〜〜〜〜"; var counter_id = "1"; // 対象年 var target_year = "2014"; // はてなカウンターの基本的なURL。 // 表示情報のページングに関する情報は除外してある var counter_url_base = "http://counter.hatena.ne.jp/" + hatena_id + "/report?cid=" + counter_id + "&date=" + target_year + "-12-01&mode=summary&target=link&type=yearly&" ; // 実際にはこの後ろに page=4 などが付与される // 情報を記録するExcelファイル名 var xls_filename = "link_report_" + hatena_id + "_" + counter_id + "_" + target_year + ".odt" ; // このバッチでページングを行なう際の最高ページ,リミット var max_page = 1000; // リンク元からアクセスされた回数の下限として認める範囲 var min_cnt = 5; // 1ページあたりに表示されるリンクの上限 var links_num_in_page = 50; // ページングの開始ページ var first_page_num = 1; // 通常は1からだが,実験用に変更することも可能 function log(s){ WScript.Echo(s); } // ---- IEではてなカウンターから情報を抽出 // IEがビジー状態の間待ちます function ie_wait_while_busy( ie, _url ) { var timeout_ms = 45 * 1000; var step_ms = 100; var total_waited_ms = 0; while( ( ie.Busy ) || ( ie.readystate != 4 ) ) { WScript.Sleep( step_ms ); // タイムアウトか? total_waited_ms += step_ms; if( total_waited_ms >= timeout_ms ) { log( "警告:タイムアウトのため,リロードします。(" + ie.LocationURL // http://blog.livedoor.jp/programlog/archives/298228.html + ")" ); // どこかに移動中なら,そこへの移動を再試行 if( _url ) { log( _url + "への遷移を再試行"); ie_goto_url( ie, _url ); } else { log( "リロード中"); // 移動先が明示されていなければリロード ie.document.location.reload( true ); ie_wait_while_busy( ie ); } break; } } WScript.Sleep( 1000 ) } // http://d.hatena.ne.jp/language_and_engineering/20100310/p1 // http://d.hatena.ne.jp/language_and_engineering/20100403/p1 // ページを移動 function ie_goto_url( ie, url ){ ie.Navigate( url ); ie_wait_while_busy( ie, url ); } // ---- MS ExcelとOOo Calcを共通して取り扱うためのライブラリ ---- // 要件: // Excelで組んだロジックをOOcで使いまわし,その逆も可としたい。 // 設計方針: // Decorator・factoryパターンあたりを参考に, // オフィス製品の差異を内部にコンポジットで隠蔽して切り替え,外側のAPIは統一する。 // 表計算ソフトのラッパーオブジェクト var IExcel = function(){ // 初期化 this.defineExcelType(); }; IExcel.prototype = { // 内部で使うオフィス製品のタイプ isMS : false, isKS : false, isOO : false, type_code : null, // どれを使うか調査して決める defineExcelType : function(){ try{ // MS製のオフィスがインストールされていれば最優先する this._excel = WScript.CreateObject("Excel.Application"); // http://d.hatena.ne.jp/language_and_engineering/20140214/p1 this.isMS = true; this.type_code = "ms"; }catch(e){ // MSが無かったら try{ // KingSoftがあれば,Excelと同一のAPIなのでこれを使う this._excel = WScript.CreateObject("ET.Application"); // http://d.hatena.ne.jp/language_and_engineering/20121218/p1 this.isKS = true; this.type_code = "ks"; }catch(e2){ // Kingsoftも無かったら try{ // 最後の手段として,OpenOffice.org Calcを使う var service_manager = WScript.CreateObject("com.sun.star.ServiceManager"); this._ooo_desktop = service_manager.createInstance("com.sun.star.frame.Desktop") // http://d.hatena.ne.jp/language_and_engineering/20141227/OOoCalcByWSHJScript this.isOO = true; this.type_code = "oo"; }catch(e3){ WScript.Echo("オフィス製品を何か一つインストールしてください。"); } } } this._books = []; // 初期化完了 return; } , _excel : null, _ooo_desktop : null, // Visible setVisible : function( b ){ if( this.isMS || this.isKS ){ this._excel.Visible = b; }else{ // TODO: } } , // 新規ブックを開く getNewBook : function(){ var ibook; if( this.isMS || this.isKS ){ this._excel.Workbooks.Add(); var book = this._excel.Workbooks( this._excel.Workbooks.Count ); // インタフェースに変換 ibook = new IExcel.IBook( this, book ); return ibook; }else{ var doc = this._ooo_desktop.loadComponentFromURL( "private:factory/scalc", "_blank", 0, [] ); // インタフェースに変換 ibook = new IExcel.IBook( this, doc ); return ibook; } } }; // ブックを表すラッパオブジェクト IExcel.IBook = function( parent, real_book ){ this._parent = parent; this._book = real_book; this.type_code = parent.type_code; this._sheets = []; }; IExcel.IBook.prototype = { _parent : null, _book : null, type_code : null, // ファイルパスを指定して保存 saveAs : function( file_path ){ if( this.type_code == "ms" || this.type_code == "ks" ){ this._parent.DisplayAlerts = false; this._book.SaveAs( file_path ); }else{ var file_url = "file:///" + file_path.replace(/\\/g, "/") ; this._book.storeAsURL( file_url, [] ); } }, // 番号でシートを取得(1始まり) getSheetByIndex : function( index ){ log("現在のシートの個数:" + this.getSheetsCount() ); log("index: " + index); var sheet, isheet; if( this.type_code == "ms" || this.type_code == "ks" ){ sheet = this._book.Worksheets( index ); isheet = new IExcel.ISheet( this._parent, sheet ); return isheet; }else{ sheet = this._book.Sheets.getByIndex( index - 1 ); // 0始まり // http://blog.livedoor.jp/addinbox/archives/51243622.html // http://itref.fc2web.com/openoffice/basic/calc.html //sheet = this._book.Sheets( index - 1 ); // 0始まり //REM: これだとシートがうまく取れなかった log( "取得したシートの名称は" + sheet.Name ); isheet = new IExcel.ISheet( this._parent, sheet ); return isheet; } } , // シートの個数 getSheetsCount : function(){ if( this.type_code == "ms" || this.type_code == "ks" ){ return this._book.Sheets.Count; }else{ return this._book.Sheets.getCount(); } } // TODO:他のブック操作メソッド }; // シートを表すラッパ IExcel.ISheet = function( parent, real_sheet ){ this._parent = parent; this._sheet = real_sheet; this.type_code = parent.type_code; }; IExcel.ISheet.prototype = { _parent : null, _sheet : null, type_code : null, // セル参照(番号は一始まり) getCell : function( y, x ){ log( y + "行" + x + "列目に書き込み" ); if( this.type_code == "ms" || this.type_code == "ks" ){ var cell = this._sheet.Cells( y, x ); // 1始まり var icell = new IExcel.ICell( this._parent, cell ); return icell; }else{ var cell = this._sheet.getCellByPosition( x - 1, y - 1 ); // 0始まりでMSと逆 var icell = new IExcel.ICell( this._parent, cell ); return icell; } } // TODO:他のシート操作メソッド }; // セルのラッパ IExcel.ICell = function( parent, real_cell ){ this._parent = parent; this._cell = real_cell; this.type_code = parent.type_code; }; IExcel.ICell.prototype = { _parent : null, _cell : null, type_code : null, // 値を書き込み setValue : function( v ){ if( this.type_code == "ms" || this.type_code == "ks" ){ this._cell.Value = v; }else{ this._cell.String = v; } } // TODO:他のセル操作メソッド }; // ------------------------ メイン処理 // ---- カレントフォルダにExcelを新規生成 var curr_dir = WScript.Arguments.Unnamed(0); var file_path = curr_dir + xls_filename; var fso = WScript.CreateObject("Scripting.FileSystemObject"); // ファイルが存在するか if( fso.FileExists( file_path ) ) { log( "既にファイルが存在します。実行停止"); WScript.Quit(); } else { log( "記録対象:" + file_path ); } // Excel起動 var excel = new IExcel(); excel.setVisible( true ); // 新規ブック var book = excel.getNewBook(); // 新規ブックを保存 book.saveAs( file_path ); log("とりあえずブックを保存しました"); // 先頭のシートを情報の記録場所とする var sheet = book.getSheetByIndex(1); // IE起動 var ie = WScript.CreateObject("InternetExplorer.Application") ie.Visible = true; ie_goto_url( ie, "http://www.google.co.jp/" ); log("ブラウザでのアクセスを開始します。"); // ページが存在する限り抽出を続行 var page_num = first_page_num; var continue_flag = true; while( continue_flag ) { var target_url = counter_url_base + "page=" + page_num ; // IEで開く log("[" + page_num + " ページ目] " + target_url + " を開きます"); ie_goto_url( ie, target_url ); // tableを取得 var table = ie.document .getElementById("hourlyreport") .getElementsByTagName("table")[0] ; var trs = table.getElementsByTagName("tr"); // trが51行あるので情報抽出。先頭のタイトル行はスキップ for( var i = 1; i < links_num_in_page + 1; i ++ ) { // 行があるか? var tr = trs[ i ]; if( tr ) { var y = ( page_num - 1 ) * links_num_in_page + i; log( y + "番目の情報を抽出"); var tds = tr.getElementsByTagName("td"); // URLを認識 var elem_as = tds[0].getElementsByTagName("a"); if( elem_as.length > 0 ) { var elem_a = elem_as[0]; //var link_url = elem_a.getAttribute("href"); // エラーになる場合がある //var link_url = elem_a.href; // エラーになる場合がある var link_url = elem_a.getAttribute("href", 2); // http://might1976.doorblog.jp/archives/51159843.html } else { // 「不明」などの文言の場合もある var link_url = tds[0].innerText; } // アクセス回数 var cnt = parseInt( tds[1].innerText.replace( /,/g, "" ), 10); if( cnt < min_cnt ) { continue_flag = false; log( "アクセス回数が下限に達したので抽出を終了" ); } else { log( i + " 行目からリンクを抽出:「" + link_url + "」, " + cnt ); // 書き込み sheet.getCell( y, 1 ).setValue( link_url ); sheet.getCell( y, 2 ).setValue( cnt ); } } else { // 行が途切れたらそこで終わり continue_flag = false; // ページが終わる場合もtable自体と先頭行は表示され, // 下部に「アクセスが記録されておりませんでした。」と出る。 } } // 次のページへ page_num ++; if( page_num > max_page ) { continue_flag = false; } } log("全ページのリンク抽出が完了"); // IEの制御を破棄 ie.Quit(); ie = null; // ---- 終了 // ブックを保存 excel.DisplayAlerts = false; book.saveAs( file_path ); log( "ブックを保存しました。" ); // Excelを閉じて終了 //excel.Quit(); //excel = null; log("全処理が終了");
今後の課題: