ぼくのかんがえたさいきょうのどうじんしかんりそふと

さて、ComicInfoEditorだが、思ったより開発が早く進んでいるので付加機能をつけることにした。
当初の予定では同人誌のメタデータをLexiconから取得する方法は該当作品の詳細ページのURLを入力してボタンをおすとそのURLの示すページからメタデータを抽出してXMLに書き込むというものであった。
しかし、これではComicInfoEditorを使うときにはブラウザの補助が必要になる。情報源となるページをブラウザで探しだして、URLをコピー、ソフトにペースト…。
できればソフト一個で完結して欲しい…。

というわけで、タイトルの一部を入れて検索をかけるとポップアップで候補が出てきて、どれかを選択するとそのデータが入るというものをつけることにした。。

ブラウザからLexiconにアクセスして、タイトルで検索すると以下の様な画面になる。実はAdblock系の何かが悪さをしており、下のスクショは正しく表示されていないんだけれども、本当は原題・タイトル・サークル・著者・原作・発行日とほしい情報はすべてこの画面に表示されているはずなのだ。
(ちなみに、この画面のHTMLサンプルはこれ

「おいしい桃姦2」のほうはほぼ正しく表示できてる。
ちなみにLexiconの仕様は前方一致なので、「桃姦」と入れてもこの結果は返ってこない。
ただ、「東方浮世絵巻 火焔猫の飼い方地獄鴉の育て方 」の場合は「火焔猫」でもヒットする。
スペースで区切られたトークンのいずれかに前方一致していればOK


  

で、バックのロジック部分を作ってみた。結果付きでのせてみるとこんなかんじになる。


ComicInfo.xmlとのやりとりに使ってるのと同じ形式で取得したメタデータをdictに格納し、それをリストに入れて返すというものである。
これはブラウザで検索した場合の一画面目からしか情報をとっていない。検索結果全てから結果を返すのもできると思うけれども、それを実装すると一番のボトルネックであるLexiconへのアクセス時間が膨大になってしまうので実装しないつもり。タイトル検索の場合はこれで困ることは滅多にないだろう。

HTML全文から、ある一冊の情報が入っている部分だけを切り出してみると、こんな感じである。この部分を格納したTagオブジェクトが以下に出てくる関数の引数divである。

これで原題を取得するためのコードは

def get_series(div):
     raw_series = div.find('span', text='原題:').next_sibling.next_sibling
     series = raw_series.string
     return series

となっている。
なぜ div.find('span', text='原題:').next_sibling.next_siblingと2つ後の要素を取得しないといけないか。それは div.find('span', text='原題:').next_siblingが'\n'だからである。
原題:のつぎに改行があるというところに注目して欲しいのだけれども、これはつまり弟要素として「タグで挟まれていない平文の\n」が隠れているということなのだ。なので.next_siblingを2つ重ねて\nの更に一個先の要素をみる必要がある。(このことはBeautifulSoup4のドキュメントにも書かれている。)
サークルや著者情報、パロディ元も同じように取れる。ただ、こいつらはリスト形式で取らないといけないんだけれども検索画面では'hoge,  fuga'とカンマ区切りの一文になってるので注意。

また、発行日: 2006-12-31から'2006-12-31'を切り出すのも実は一筋縄ではいかない。
最初は発行日:をとってきて、その.parentをとれば発行日: 2006-12-31、つまり発行日:の.parent.stringが'2006-12-31'となるんだろうと思っていたが実はこれはうまくいかない。
の子要素に発行日:と平文の'2006-12-31'と2つ含まれていることになるのだが、BeautifulSoup4における.stringは「子要素が1つしかないとき」しか使うことができない。(2つ以上あるときはNoneになる)
この解決をするには、 発行日:を削除しての子要素に'2006-12-31'しかない状態にしてから.stringを取る。コードはこんなかんじだ。
おそらくこれがベストな解決だろう。

def get_date(div):
     raw_date = div.find('b', text='発行日:').parent
     raw_date.b.extract()
     date = raw_date.string.split('-')
     return date

あとはこれをGUIから利用するコードを書けば終わりな気がする。
意外と早く堕ちたな~(嬉しい誤算)


ちなみに、今日また別の東方厨の人に「最近、八坂神奈子と星熊勇儀がいいと思うんですよ。でもこの二人がでてくる薄い本は探しても全然無くて困る」という話をしたら、「ちっちゃい子が好きだから東方好きになるのであって、東方好きにおばさん好きはいません」という答えが返ってきた。
確かに僕は東方原作のことはほとんど知らないんだけれども、そういうものなのだろうか。