情報アイランド

「情報を制する者は世界を制す」をモットーに様々な情報を提供することを目指すブログです。現在はプログラミング関連情報が多めですが、投資関連情報も取り扱っていきたいです。

Node.jsでWordPressブログの記事をバックアップするには?

WordPressブログの記事をバックアップするにはWordPressブログの全ての記事を取得し、ファイルに保存します。

ただし、毎回全ての記事を取得して保存するのは非効率なので、既に保存されている記事はできるだけ再び取得することのないようにしたいです。

また、既に保存されている記事であっても、保存された後に記事が更新され、バックアップが古いものになっていることもあるため、記事が更新されたかどうかも考慮するようにしなければなりません。

そのためには、記事を10件ずつ更新日時の降順に取得します(必ず10件ずつでなければならない訳ではありません。要は一度に全部取得するのではなく、少しずつ取得するということです。一度に取得する件数は状況に応じて適切な数字を選んでください)。

そして、更新日時の新しいものからバックアップが存在するかを調べます。存在しないならバックアップを取り、次の記事を処理します。存在するなら取得したデータの更新日時とバックアップの更新日時を比較します。バックアップの更新日時の方が古いならバックアップを取り直し、次の記事を処理します。更新日時が一致するなら既にバックアップが取られているということなので、バックアップを取り直す必要はありません。また、これ以降の記事も全て最新のバックアップが取られているということになるので、ここで処理は完了ということになります。

このようにして、毎回全ての記事を取得することなくバックアップを行うことができます。


WordPressブログから記事を取得する方法に関しては下の記事を参照してください。

また、テキストファイルのデータを読み書きする方法に関しては下の記事を参照してください。

サンプルコード1

コマンドライン引数として与えられたフォルダにあるsettings.jsonをWordPressブログの設定として読み込み、このフォルダにブログのバックアップを格納します。

バックアップは記事毎に<id>.jsonという名称で保存します(<id>に記事のIDが入ります)。

wordpress-backup.js

var wordpress = require('wordpress');
var fs = require('fs');
var path = require('path');

if (process.argv.length < 3) {
    console.error('lack argument.');
    process.exit(1);
}

var settingsFile = path.join(process.argv[2], 'settings.json');
fs.readFile(settingsFile, 'utf-8', function (err, data) {
    if (err) {
        console.error('failed load settings file.');
        console.error(err);
        process.exit(1);
    }
    else {
        var json = {};
        try {
            json = JSON.parse(data);
        }
        catch (err) {
            console.error('failed parse settings file.');
            console.error(err);
            process.exit(1);
        }
        var client = wordpress.createClient(json);
        processPosts(client, 0);
    }
});

function processPosts(client, offset) {
    client.getPosts({
        orderby: 'modified', 
        offset: offset
    }, function (err, posts) {
        if (err) {
            console.error('failed get posts.');
            console.error(err);
            process.exit(1);
        }
        else {
            processPost(client, offset, posts, 0);
        }
    });
}

function processPost(client, offset, posts, i) {
    if (i >= posts.length) {
        if (posts.length == 10) {
            processPosts(client, offset + 10);
        }
        else {
            console.log('finished at end.');
        }
    }
    else {
        if (!posts[i].id) {
            console.error('does not exist id.');
            processPost(client, offset, posts, ++i);
        }
        var file = path.join(process.argv[2], posts[i].id + '.json');
        fs.readFile(file, 'utf-8', function (err, data) {
            var oldDate = new Date(0);
            if (!err) {
                var json = {};
                try {
                    json = JSON.parse(data);
                }
                catch (err) {
                    console.error('failed parse backup file.');
                    console.error(err);
                }
                if (json.modified) {
                    oldDate = Date.parse(json.modified);
                }
                else {
                    console.error('does not exist modified field in backup file.');
                }
            }
            var newDate = new Date(0);
            if (posts[i].modified) {
                newDate = Date.parse(posts[i].modified);
            }
            else {
                console.error('does not exist modified field.');
            }
            if (oldDate < newDate) {
                fs.writeFile(file, JSON.stringify(posts[i]), 'utf-8', function (err) {
                    if (err) {
                        console.error('failed save backup file.');
                        console.error(err);
                    }
                    else {
                        console.log('backuped ' + posts[i].id + ': ' + posts[i].title);
                    }
                    processPost(client, offset, posts, ++i);
                });
            }
            else {
                console.log('finished at ' + posts[i].id + ': ' + posts[i].title);
            }
        });
    }
}

使用パッケージ

  • node-wordpress
    npm install wordpressでインストールします。

実行結果

blogフォルダにはsettings.jsonのみが保存されています。

C:\work\node>dir blog
 Volume in drive C is TI31035600A
 Volume Serial Number is 1CBD-3C48

 Directory of C:\work\node\blog

2016/03/23  21:23    <DIR>          .
2016/03/23  21:23    <DIR>          ..
2016/03/23  21:38                91 settings.json
               1 File(s)             91 bytes
               2 Dir(s)   6,703,988,736 bytes free

settings.jsonの内容は下のようになっています。

C:\work\node>type blog\settings.json
{
        "url": "http://info-i.net/",
        "username": "user",
        "password": "pass"
}

フォルダとしてblogを指定してコードを実行すると、全ての記事のバックアップがblogフォルダに保存されます。

C:\work\node>node wordpress-backup.js blog
backuped 110: Node.jsでWordPressブログから記事を取得するには?
backuped 118: Node.jsでフォルダの直下にあるファイルやフォルダのリストを取得する
backuped 116: Node.jsでパスがフォルダを示しているかチェックする
backuped 114: Node.jsでパスがファイルを示しているかチェックする
backuped 298: Node.jsで標準出力にオブジェクトを出力する
backuped 107: Node.jsでオブジェクトを文字列に変換する
backuped 52: Node.jsで書式指定により文字列を生成する
backuped 99: Node.jsでパスから拡張子部分を取得する
backuped 97: Node.jsでパスからフォルダ部分を取得する
backuped 95: Node.jsでパスからベース部分を取得する
backuped 67: Node.jsでパスを結合する
backuped 64: Node.jsでプログラムを終了する
backuped 61: Node.jsでコマンドライン引数を取得する
backuped 58: Node.jsでタイムスタンプ付きで標準出力に文字列を出力する
backuped 268: Node.jsでdateformatを使って日時をフォーマットする
backuped 279: Node.jsでMoment.jsを使って日時をフォーマットする
backuped 276: Node.jsでDate-Utilsを使って日時をフォーマットする
backuped 273: 初めて投稿します ~作文が下手糞な私~
backuped 49: Node.jsで経過時間を測定する
backuped 36: Node.jsで標準出力に文字列を出力する
backuped 42: Node.jsで標準エラー出力に文字列を出力する
backuped 39: Node.jsで標準出力や標準エラー出力に色付きの文字列を出力する
backuped 258: Node.jsのストリームの使い方
backuped 186: Node.jsでファイルをコピーする
backuped 251: ディクテーションの実例1 CPIについて
backuped 249: Node.jsでmustache.jsテンプレートエンジンを使う
backuped 243: Node.jsでECTテンプレートエンジンを使う
backuped 226: Node.jsでEJSテンプレートエンジンを使う
backuped 239: Node.jsでパスからファイルやフォルダの名前を取得する
backuped 235: Node.jsでCSVファイルやTSVファイルを読み込む
backuped 230: Javascriptで改行コードを変換
backuped 218: Node.jsでストリームからBOM(バイトオーダーマーク)を取り除く
backuped 191: Node.jsで文字列からBOM(バイトオーダーマーク)を取り除く
backuped 181: Node.jsでテキストファイルの行数を数える
backuped 172: Node.jsでストリームを使ってテキストファイルに非同期的に書き込む
backuped 164: Node.jsでストリームを使ってテキストファイルを非同期的に読み込む
backuped 162: Node.jsでテキストファイルに非同期的に追記する
backuped 152: Node.jsでテキストファイルに非同期的に書き込む
backuped 146: Node.jsでテキストファイルを非同期的に読み込む
backuped 128: Node.jsでテキストファイルを同期的に読み込む
backuped 126: Node.jsでフォルダの直下にある特定の拡張子のファイルのリストを非同期的に取得する
backuped 122: Node.jsでフォルダの直下にあるフォルダのリストを非同期的に取得する
backuped 120: Node.jsでフォルダの直下にあるファイルのリストを非同期的に取得する
backuped 183: そうだ!ローグライクゲームを作ろう!その1
backuped 130: Node.jsでテキストファイルに同期的に書き込む
backuped 168: 暗号通貨開発日誌 3日目
backuped 159: 暗号通貨開発日誌 2日目
backuped 140: 暗号通貨開発日誌 1日目
backuped 137: JavaでBigIntegerをバイト配列として扱う
backuped 133: JavaのBigIntergerをバイト配列に変換した結果
backuped 101: 暗号通貨の採掘方式
backuped 44: これだけは押さえておきたいテクニカル分析6個のポイント
backuped 24: cURLのインストール
backuped 13: Node.jsのインストール
finished at end.

C:\work\node>dir blog
 Volume in drive C is TI31035600A
 Volume Serial Number is 1CBD-3C48

 Directory of C:\work\node\blog

2016/03/23  21:43    <DIR>          .
2016/03/23  21:43    <DIR>          ..
2016/03/23  21:43             9,948 101.json
2016/03/23  21:43             4,859 107.json
2016/03/23  21:43            17,354 110.json
2016/03/23  21:43             6,330 114.json
2016/03/23  21:43             6,421 116.json
2016/03/23  21:43             7,009 118.json
2016/03/23  21:43             5,473 120.json
2016/03/23  21:43             5,064 122.json
2016/03/23  21:43             5,906 126.json
2016/03/23  21:43             5,626 128.json
2016/03/23  21:43             2,837 13.json
2016/03/23  21:43             4,658 130.json
2016/03/23  21:43             3,884 133.json
2016/03/23  21:43             5,045 137.json
2016/03/23  21:43             7,257 140.json
2016/03/23  21:43             5,343 146.json
2016/03/23  21:43             4,495 152.json
2016/03/23  21:43             6,000 159.json
2016/03/23  21:43             4,697 162.json
2016/03/23  21:43             6,271 164.json
2016/03/23  21:43             9,353 168.json
2016/03/23  21:43             4,914 172.json
2016/03/23  21:43             4,554 181.json
2016/03/23  21:43            11,735 183.json
2016/03/23  21:43             5,762 186.json
2016/03/23  21:43             4,960 191.json
2016/03/23  21:43             8,207 218.json
2016/03/23  21:43             9,796 226.json
2016/03/23  21:43             2,161 230.json
2016/03/23  21:43            11,154 235.json
2016/03/23  21:43             3,856 239.json
2016/03/23  21:43             4,232 24.json
2016/03/23  21:43            10,868 243.json
2016/03/23  21:43            10,082 249.json
2016/03/23  21:43             7,185 251.json
2016/03/23  21:43            15,923 258.json
2016/03/23  21:43             5,666 268.json
2016/03/23  21:43             3,302 273.json
2016/03/23  21:43             4,491 276.json
2016/03/23  21:43             4,578 279.json
2016/03/23  21:43             3,205 298.json
2016/03/23  21:43             4,912 36.json
2016/03/23  21:43             4,906 39.json
2016/03/23  21:43             4,977 42.json
2016/03/23  21:43             6,955 44.json
2016/03/23  21:43             2,862 49.json
2016/03/23  21:43             4,081 52.json
2016/03/23  21:43             5,412 58.json
2016/03/23  21:43             3,479 61.json
2016/03/23  21:43             2,746 64.json
2016/03/23  21:43             2,602 67.json
2016/03/23  21:43             2,771 95.json
2016/03/23  21:43             2,794 97.json
2016/03/23  21:43             2,731 99.json
2016/03/23  21:38                91 settings.json
              55 File(s)        321,780 bytes
               2 Dir(s)   6,703,083,520 bytes free

バックアップが正しく保存されていることが分かります。

C:\work\node>type blog\99.json
{"id":"99","title":"Node.jsでパスから拡張子部分を取得する","date":"2016-02-07T22:02:16.000Z","modified":"2016-03-21T06:26:11.000Z","status":"publish","type":"post","name":"path-extname","author":"1","password":"","excerpt":"","content":"パスから拡張子部分を取得するには`path.extname`関数を使用します。\r\n\r\n第1引数にパスを指定します。\r\n\r\n返り値としてパスの拡張子部分が得られます。\r\n\r\n### サンプルコード1\r\n\r\nコマン���ライン引数として与えられたパスから拡張子部分を取得し、標準出力に出力します。\r\n\r\n**<span style=\"color:blue\">▼</span>path-extname.js**\r\n\r\n```js\r\nvar path = require(&#039;path&#039;);\r\n\r\nif (process.argv.length &lt; 3) {\r\n\tconsole.error(&#039;lack argument.&#039;);\r\n\tprocess.exit(1);\r\n}\r\n\r\nconsole.log(path.extname(process.argv[2]));\r\n```\r\n\r\n**<span style=\"color:blue\">▼</span>実行結果**\r\n\r\nフォルダのパスを指定す��と、空の文字列が返ってくることが分かります。\r\n\r\n```\r\nC:\\work\\node&gt;node path-extname.js C:\\\r\n\r\n\r\nC:\\work\\node&gt;node path-extname.js C:\\work\r\n\r\n\r\nC:\\work\\node&gt;node path-extname.js C:\\work\\node\r\n\r\n\r\nC:\\work\\node&gt;node path-extname.js C:\\work\\node\\path-extname.js\r\n.js\r\n```\r\n\r\n### 関連\r\n\r\n* [Node.jsに関する記事一覧](http://info-i.net/nodejs-articles)","parent":"0","link":"http://info-i.net/path-extname","menuOrder":0,"commentStatus":"open","pingStatus":"open","sticky":false,"thumbnail":{"attachment_id":"17","date_created_gmt":"2016-01-20T05:58:23.000Z","parent":13,"link":"http://info-i.net/wp-content/uploads/2016/01/screenshot.1.jpg","title":"screenshot.1","caption":"","description":"","metadata":{"width":480,"height":270,"file":"2016/01/screenshot.1.jpg","sizes":{"thumbnail":{"file":"screenshot.1-150x150.jpg","width":150,"height":150,"mime-type":"image/jpeg"},"medium":{"file":"screenshot.1-300x169.jpg","width":300,"height":169,"mime-type":"image/jpeg"},"post-thumbnail":{"file":"screenshot.1-480x198.jpg","width":480,"height":198,"mime-type":"image/jpeg"}},"image_meta":{"aperture":0,"credit":"","camera":"","caption":"","created_timestamp":0,"copyright":"","focal_length":0,"iso":0,"shutter_speed":0,"title":"","orientation":1,"keywords":[]}},"type":"image/jpeg","thumbnail":"http://info-i.net/wp-content/uploads/2016/01/screenshot.1-150x150.jpg"},"format":"standard","terms":[{"term_id":"4","name":"Node.js","slug":"nodejs","term_group":"0","term_taxonomy_id":"4","taxonomy":"category","description":"","parent":"0","count":42,"filter":"raw"}],"customFields":[{"id":"875","key":"views","value":"30"}]}

もう1度フォルダとしてblogを指定してコードを実行すると、全ての記事の最新のバックアップがblogフォルダに既に保存されているため、追加で保存されるバックアップはありません。

C:\work\node>node wordpress-backup.js blog
finished at 110: Node.jsでWordPressブログから記事を取得するには?

1つの記事を更新後、もう1度フォルダとしてblogを指定してコードを実行すると、更新した1記事のバックアップが更新されます。

backuped 110: Node.jsでWordPressブログから記事を取得するには?
finished at 118: Node.jsでフォルダの直下にあるファイルやフォルダのリストを取得する

関連

pizyumi
プログラミング歴19年のベテランプログラマー。業務システム全般何でも作れます。現在はWeb系の技術を勉強中。
スポンサーリンク

-Node.js