はてなブログ記事DBを作る
SQLite3で。
成果物
Hatena.Blog.API.Database.Create.Blog.Entries.201703011629
開発環境
- Linux Mint 17.3 MATE 32bit
- SQLite 3.8.2
はてなブログAtomPub - Hatena Developer Center
前回まで
http://ytyaru.hatenablog.com/entry/2017/06/26
http://ytyaru.hatenablog.com/entry/2017/06/29
http://ytyaru.hatenablog.com/entry/2017/06/30
データベース
- Hatena.Hatena.Blog.Entries.{BlogId}.sqlite3
テーブル
Accounts
create table Entries( Id integer primary key, EntryId text unique not null, Url text unique not null, Title text, Summary text, ContentType text, Content text, HtmlContent text, Categories text, IsDraft integer default 0 check(IsDraft = 0 or IsDraft = 1), Edited text, Published text, Updated text );
EntryId
サービス文書内では<id>tag:blog.hatena.ne.jp,2013:blog-{HatenaId}-{HatenaBlogId}-{EntryId}</id>
という書式。このうち{EntryId}の部分をDBのEntryId
列値として保存する。
値はすべて数値である。はてなの仕様書によるとepoch値らしい。たぶん1970/01/01 00:00:00からの経過秒数。にもかかわらずDBを数値でなくテキスト型にしたのはオーバーフロー対策。
Python3は上限がなくなった。SQLite3は最大で符号付き8byte(64bit)まで。しかし、PythonはDBに数値を挿入するとき、64bit数値をサポートしていないらしい。32bit値までしか正常に扱えない。以下のようなエラーが出る。
OverflowError: Python int too large to convert to SQLite INTEGER
DBにはテキストとして保存し、Pythonで数値として復元して利用するしかない。 そうなると、DB値だけで大小比較すると文字列としての大小比較になってしまう。 数値としての比較とはまったく結果が異なるため、注意が必要である。
EditURL
DB列にはない。各種IDから作成できる
<link rel="edit" href="https://blog.hatena.ne.jp/{HatenaId}/{BlogId}/atom/entry/{EntryId}"/>
。
Url
はてなブログの設定によって違うと思われる。
- 日時形式:http://ytyaru.hatenablog.com/entry/YYYY/mm/dd/HHMMSS
- タイトル形式:http://ytyaru.hatenablog.com/entry/{記事のタイトル}
予約投稿したときURLは予約投稿されるURLになっていない。保存したときの日時URLになっているのか。よくわからない。そのURLを指定しても存在しないからアクセスできない。
<link rel="alternate" type="text/html" ...>
のhref
属性値をDBのUrl
に保存する。
ContentType
記事を編集するときのテキストデータ形式。「見たまま」「Markdown」「はてな記法」の3種類のどれかと思われる。
編集形式 | Content要素のtype属性値 |
---|---|
見たまま | ? |
Markdown | text/x-markdown |
はてな記法 | text/x-hatena-syntax |
<content type="text/x-markdown">
,<content type="text/x-hatena-syntax">
。type属性値をContentType
列に保存する。「見たまま」だと何の値なのか不明。
Content
記事を編集するときのテキストデータ。たとえばMarkdownならそのデータ。
<content>
のテキストノード値をContent
列に保存する。
HtmlContent
<content>
をHTMLに変換したときのテキストデータ。
<hatena:formatted-content type="text/html" ...>
のテキストノード値をHtmlContent列に保存する。
Category
記事のカテゴリ。
<category term="">
のterm属性値をCategory列に保存する。
ただし、複数の<category term="">
が存在しうる。すべての値を取得し、それらをカンマ区切りにして保存する。
IsDraft
<app:control><app:draft>no</app:draft></app:control>
。no
またはyes
のどちらか。
状態 | draft |
---|---|
下書き | yes |
公開 | no |
ちなみに予約投稿の場合、draft=yesかつ<updated>
が未来の日時になっている。
日時
日時はyyyy-MM-ddTHH:mm:ss+09:00
形式。
悩んだこと
HTMLテキストは必要か
Markdownデータさえあればあとはツールで変換できると思う。
でもツールによって結果が変わりうるし、毎回変換せずに済むなら保存したほうが早い。
Draft
はてな内部での扱い方に従った。
実際は、公開、下書き、予約投稿、の3種類ある気がする。でも、下書きと予約投稿の区別は<updated>
が未来の日付かどうかで判断すると思われる。いまいちそのへんの仕様を理解していない。
EditURL
将来変更されてキーだけでは自動生成できなくなる懸念もある。途中からベースURLが変更されることも考えられる。でも、ほとんど重複しているから省いた。Contentさえ保存できれば大体OKだし。
URL
URL形式
URL形式が日時なら、日時さえあればURLを作成できる気がする。でも、カスタムURLもできるのでそのままURL値を保存するほうが安全か。
予約投稿
予約投稿で下書き中のURLは公開予定のURLではない。作成時か最終更新日かわからないが、そのへんのURLになっている。そのURLは存在しない。はてなブログ内部で、予約投稿の日時がくると、その日時でURLを作成すると思われる。それ以降では公開URLが取得できると思われる。
つまり、予約投稿記事のURLは存在しないものになってしまう。公開後にURLを取得し直すべきだが、今はその問題は放置しておく。とにかくContentさえ保存できればOKとする。
所感
予約投稿まわりが不自然に思える。振り回されないよう、Contentの保存にだけ集中する。とりあえずXML値をそのまま保存するくらいの軽い気持ちで。