Binary Diary

誰かに会ったり 話しかけたり 街行く人に優しくね

GASではてなブログAPIから情報取得!ファイル保存までやっちゃうよ。

どうもこたにんです。

久々に技術記事!

今回は、はてなブログAtomPubというAPIをGASで呼び出してレスポンスをファイル保存、ということをやってみます。

はい、目次どんっ!

 

今回やること

とある記事を書く際に、ブログに投稿した全ての記事の内容が欲しくなりました。

そのために、全ての記事情報をはてなブログAtomPubから取得する。
また、サーバ立てたりしたくないのでGASでサクッと実装する。
最終的に欲しいのはテキストファイルだったのでGASでテキストファイル生成まで行う。

はてなブログAtomPubとは?

はてなブログAtomPub - Hatena Developer Center

Atom Publishing Protocol(以下 AtomPub) はウェブリソースを公開、編集するためのアプリケーション・プロトコル仕様です。はてなブログのAtomPubと通じて、開発者ははてなブログのエントリを参照、投稿、編集、削除するようなオリジナルのアプリケーションを作成できます。

AtomPubプロトコルに準じたはてなブログ専用のXML仕様のこと、AtomAPI
自身のはてなブログの情報を取得したり投稿したりなどができるものです。

はてなブログAtomPubでは以下の操作が可能とのことです。

  • ブログの操作 (コレクション)
    • ブログエントリ一覧の取得 (コレクションURI への GET)
    • ブログエントリの新規投稿 (コレクションURIへの POST)
  • ブログエントリの操作 (メンバ)
    • ブログエントリの取得 (メンバURI の GET)
    • ブログエントリの更新 (メンバURI への PUT)
    • ブログエントリの削除 (メンバURI への DELETE)
  • サービスの操作 (サービス文書)
    • コレクション一覧の取得 (サービス文書URI の GET)
  • カテゴリの操作 (カテゴリ文書)
    • カテゴリ一覧の取得 (カテゴリ文書URI の GET)

今回の記事では、やることを「ブログエントリの取得」に限定していきます。
ので、必要最低限の方法の展開になります。
はてなブログAtomPubの全容が知りたい方はリファレンスを読みましょう。

GASではてなブログAtomPubから情報を取得する

AtomPubに必要な情報の確認

はてなブログ側の設定画面にて、AtomPubの接続に必要な情報を確認します。
[設定] → [詳細設定] → [AtomPub] の項目を確認しましょう。

f:id:Kotanin0:20191226010541p:plain

ここにあるルートエンドポイントAPIキーが必要となります。
後で使いますので控えておきましょう。

GASでAtomPubの呼び出し

続いてGAS側で、はてなブログAtomPubを呼び出すコードを書きましょう。
コードは至ってシンプル。

// ルートエンドポイント
const
url = 'https://blog.hatena.ne.jp/Kotanin0/kotanin0.hatenablog.com/atom/entry';
// はてなのユーザID、APIキー
const user = 'Kotanin0';
const apiKey = 'xxxxxxxxxx';
// リクエストヘッダの準備 const options = { 'method' : 'GET', 'headers' : {'Authorization' : 'Basic ' + Utilities.base64Encode(user + ':' + apiKey)} }
// xml形式で返却される var xml = UrlFetchApp.fetch(url, options).getContentText();

UrlFetchAppでHTTP通信します。

url引数に、AtomPubのルートエンドポイントを指定。
ただし今回は記事一覧を取得したいので、末尾に /entry を追加しています。

options引数に、リクエストヘッダを指定。
リクエストヘッダには、はてなIDとAPIキーをエンコードした値をセットします。


認証形式についての説明は省略しますが、今回はBasic認証で行います。
自分のブログの情報が欲しいだけなのでオレオレ認証してしまうわけです。
何かしら一般化して作るときはOAuthなどで実装しなきゃですね。

もとい。
これで、はてなブログAtomPubから情報を取得できました。

XMLパースして必要な部分のみファイル出力する

ParserライブラリでXMLをパースする

先のUrlFetchApp.fetchによって取得されたXMLをパースして必要な情報を切り出します。
記事一覧のXMLは以下のような階層を持っています。

<feed>
 :
  <entry>
    <id></id>
    <link rel="edit"/>
    <link rel="alternate"/>
    <author><name></name></author>
    <title></title>
    <updated></updated>
    <published></published>
    <app:edited></app:edited>
    <summary type="text"></summary>
    <content type="text/html"></content>
    <hatena:formatted-content type="text/html" xmlns:hatena="http://www.hatena.ne.jp/info/xmlns#"></hatena:formatted-content>
    <category />
    <app:control>
      <app:draft></app:draft>
    </app:control>
  </entry>
  <entry>

<entry> というタグごとに、記事一覧が入っているかたちです。
XMLパーサはGAS標準で用意されているものがあります。

XML Service  |  Apps Script  |  Google Developers

ただ、階層潜るとかいちいち考えたくないなあって思ってしまいました。
ので、GASでHTMLパースできるライブラリParserを使ってパースします。

Parserのこまかい使い方はこちらの記事を参考ください。

ParserはHTMLのためのライブラリですが、中身は実際はただの文字列抽出なのです。
なのでXML形式でも同様に使うことができます、のでさくっとメソッドを書きます。
記事本文は <entry> タグ内の <content> に入っているので抽出しましょう。

// Parserでentryからcontentのリストを抽出し返却する
function getContents(xml) {
  var entries = Parser.data(xml).from('<entry>').to('</entry>').iterate();
  var contentList = [];
  for each(var entry in entries) {
    var content = Parser.data(entry).from('<content').to('</content>').build();
    contentList.push(content);
  }
  return contentList;
}

 

Google Drive上にファイル保存する

抽出された記事一覧の文字列配列を、ファイル保存したいです。
自身のGoogle Driveにファイルを保存してしまいましょう。

Google Driveにアクセスし、フォルダを作ります。
URLは以下のようになっているかと思います。

https://drive.google.com/drive/u/0/folders/{IDっぽい文字列}

このIDっぽい文字列部分を控えておきます。

あとは、Google Drive上にファイル出力するGASコードを書きましょう。

function createFile(fileName, content) {  
  var folder = DriveApp.getFolderById('IDっぽい文字列');
  var file = Utilities.newBlob('', 'text/plain', fileName).setDataFromString(content, 'utf-8');
  folder.createFile(file);
}

DriveApp.getFolderByIdの引数に、先ほどのIDっぽい文字列を指定します。
Utilities.newBlobで、保存したいデータを文字コード指定で準備します。
そして、フォルダにファイルをcreateFile。
 

これでGoogle Driveにテキストファイルが保存されます。

f:id:Kotanin0:20191226224216p:plain

目的達成!おわり!!

 

まとめ

今回、これだけのことがさくっとできるようになりました

  • はてなブログAtomPubでブログエントリの情報を取得
  • GASでHTTPリクエストするときはUrlFetchApp
  • GASでGoogle Driveにファイル保存するときはUtilities.newBlob

GASメインでHTTP通信からパース、ファイル保存までできる引き出しが手に入った!
これでスクレイピングから先の幅が広がるね!!

ちなみに、本ブログの全記事のwc -mは約189万文字ありました、壮大。