masalibの日記

システム開発、運用と猫の写真ブログです

node.jsで「はてなブログ」の記事データを取得する

http://masalib.hatenablog.com/entry/2016/10/27/022048
を昔に作ったのですが
初心者が環境を用意するのが難しいので
今回はnode.jsでダウンロードするプログラムで作りなおした
はてなブログ記事はxmlで取得できるのですが
再帰プログラムにしないといけない所がめんどくさい所です

なぜnode.jsなのか

環境のインストールがwindows7以外が簡単!!

node.jsはインストールさえ終わってしまえば
環境依存がすくない言語です
そちらの言語ではてなブログの記事データを取得しました

環境を用意する

プロジェクトのフォルダを作成する

mkdir sitedownload
cd sitedownload

cheerio-httpcliのモジュールをインストールする

npm install cheerio-httpcli

はてなの記事のURLやIDとパスワードを用意する


1・APIキーを確認する

はてなブログのダッシュボード
 => 設定
 => 詳細設定
 => AtomPub
   ルートエンドポイントAPIキーをメモる

f:id:masalib:20161026224357p:plain 

f:id:masalib:20161026224406p:plain


2・はてなIDを取得する

はてなブログのダッシュボード
 => 設定
http://blog.hatena.ne.jp/masalib/masalib.hatenablog.com/config
             ↑ここ    
またはアカウト設定
f:id:masalib:20161026224829p:plain



プログラム

// モジュールの読込
var client  = require('cheerio-httpcli');
var request = require('request');
var URL     = require('url');
var fs      = require('fs');
var path    = require('path');

//共通の設定
//階層の指定()
var LINK_LEVEL = 99;

//基準となるページURL
var TARGET_URL = "https://blog.hatena.ne.jp/masalib/masalib.hatenablog.com/atom/entry"

//既出のサイトを定義する。(既出のサイトは無視をする機能があるため。)
var list       = {};

//メイン処理
downloadRec(TARGET_URL, 0);

//downloadRec( "a aa "+ TARGET_URL, 0); //indexOfの動作確認

//指定のurlを最大レベルlevelまでダウンロードする
function downloadRec(url, level){
   //最大レベルのチェックをする (最大レベルになるまでループさせるため)
   if (level >= LINK_LEVEL) return;

   //既出のサイトは虫をする。
   if (list[url]) return;

   //基準ページ以外なら無視をする
  //-----------------------------------------------------------
   var us  = TARGET_URL.split("/");

  //  console.log(us);  //出力::[ 'http:', '', 'nodejs.jp', 'nodejs.org_ja', 'docs', 'v0.10', 'api' ]

   us.pop();  //popメソッドを使用して、配列の最後の要素を削除します。
   //console.log(us.pop()); //出力::api

  //  console.log(us);  //出力::[ 'http:', '', 'nodejs.jp', 'nodejs.org_ja', 'docs', 'v0.10' ]

   var base = us.join("/");  //joinメソッドは配列の各要素を指定の文字列で連結し、結果の文字列を返します。
  //  console.log(base);  //出力::http://nodejs.jp/nodejs.org_ja/docs/v0.10

   if (url.indexOf(base) < 0 ) return;
  //hatenaのidとpasswordを入力する
  var user = 'masalib';
  var password = 'password';

  client.set('headers', {
    Authorization: 'Basic ' + new Buffer(user + ':' + password).toString('base64')
  });


 // HTMLを取得する
 client.fetch(url, {}, function( err, $, res){
   //リンクされているページを取得
   $("link").each(function(idx){

    //  タグのリンク先を得る
    var href = $(this).attr('href');
    if (!href) return; //href属性を取得できない時の処理

    //  タグのリンク先を得る
    var href = $(this).attr('href');

    if ($(this).attr('rel') == 'next'){
      console.log($(this).attr('rel'));
      console.log($(this).attr('href'));
    } else {
      return;
    }


    // 絶対パスを相対パスに変更
    href = URL.resolve(url, href);

    //'#' 以降を無視する(a.html#aa と a.html#bb は同じものとする)
    href = href.replace(/\#.+$/, "") //末尾の#を消す

    downloadRec(href, level + 1);
  });

  // ページを保存 (ファイル名を決定する)
  if ( url.substr(url.length - 1, 1) == '/'){
    url += "index.html"; //インデックスを自動追加する。
  }

  //var savepath = url.split("/").slice(2).join("/");
  var savepath = url.split("/").slice(6).join("/"); //slice::配列の一部を取り出して新しい配列を返します。
  savepath = "./xml/" + savepath; 
  savepath = savepath.replace( /\?/g , "_" ) ;
  savepath = savepath.replace( /\=/g , "_" ) ;
  savepath =  savepath + ".xml"; 
  console.log(savepath); //nodejs.jp/nodejs.org_ja/docs/v0.10/download



  //保存先のディレクトリが存在するか確認をする。
  checkSaveDir(savepath);
  console.log(savepath); //nodejs.jp/nodejs.org_ja/docs/v0.10/download

  fs.writeFileSync(savepath, $.html());

});
}

//保存先のディレクトリが存在するか確認をする。
function checkSaveDir(fname){
  //ディレクトリ部分だけ取り出す
  var dir = path.dirname(fname);

  //ディレクトリを再帰的に作成する。
  var dirlist = dir.split("/");
  var p = "";
  for ( var i in dirlist ) {
    p += dirlist[i] + "/";
    if (!fs.existsSync(p)) {
      fs.mkdirSync(p);
    }
  }
}

このプログラムでxmlがダウンロードができました
記事xmlのデータを解析して、imgのデータをダウンロードするのを作りたいです

このプログラムは以下を参考にした
サイトをまるごとダウンロードをする - it-tech-dm’s blog

2017/09/19追記
windowsだとファイル保存できないので保存ファイル名を変更

2017/09/26追記
SSl化で変わるかも・・・orz