初めての恋空文字数カウント

こんにちは。
みなさんは「恋空」の文字数が何文字か知る必要に迫られたことはありますか?僕はこの前初めてその状況に陥りました。その時のことを書いていきたいと思います。すでに「恋空」の文字数を知っている人は退屈かもしれませんが、そういう人のために「君空」の文字数も調べてあるので読んでいってくれると嬉しいです。

「恋空」こと「切ナイ恋物語f:id:baklajan:20170815012533p:plain恋空f:id:baklajan:20170815012527p:plain前」「切ナイ恋物語f:id:baklajan:20170815012540p:plain恋空f:id:baklajan:20170815012547p:plain後」は日本最大級のガールズポータルサービスである「魔法のiらんど」というサイトに掲載されているケータイ小説です。ケータイ小説ブームの火付け役とも言える作品で、ケータイ小説界に打ち立てられた金字塔であり、上下2巻、ヒロの視点から物語を描いた続編の「君空」も含めて書籍化されている大作です。読んだことがある人も多いと思います。


そもそもケータイ小説というはその名の通り携帯電話で打ち込まれた連載小説のことを主に示している(いた)と思います。この言葉ができたころはスマホはたぶん存在しておらず、パカパカケータイのテンキーがポチポチされて文章が生成されていました。さすがに今投稿されている作品はスマホやパソコンからのものが多いと思います。ケータイ小説(特に恋愛もの)の特徴としては「地の文が一人称視点」「女子学生っぽさをふんだんに漂わせる大量の改行」「原稿用紙の枚数の呪縛から解き放たれたことによる冗長な文章」「作品の主軸は登場人物の感情」などがあげられると思います。
ケータイ小説は専用のサイトに投稿されていて、サイトをチェックしている全国の思春期女子たちに読まれていました。彼女らは夜な夜なお気に入りの連載小説が更新されていないだろうかと明かりを消した自分の部屋のベッドの上で家族にバレないようにひっそりとチェックしていたことと思います。何があっても主人公を守ってくれる喧嘩最強暴走族総長の彼氏たちに胸キュンして彼らが交通事故で帰らぬ人となれば涙を流したり、他人に甘えずに育ってきた美少女だけど友達が少ない主人公が性格に難がある5歳以上年上のハイスペックなイケメンに振り回される日常生活を送りながら一途な愛情を注がれているところに、ある時その男と同じぐらいの年齢でその男を狙う別の女が出現して浮気疑惑に動揺して心が離れそうになり、そのタイミングで同級生男子から告白されてちょっといい感じになるも、やっぱり自分にはあの男しかいないと気づき、男子を振り、今まであまり口に出せなかった想いを男に伝えて、浮気疑惑も女が一方的に迫っているだけで男は何もしていないという形で決着がつき、そのまま勢いで二人は結ばれ、主人公の閉じた心もある程度改善され、早く高校卒業して結婚しよう、愛してる、私も、つないだ手のひらは心地よくあったかくて空の青は清澄、心からこみ上げ口から漏れ出る幸せな笑い、恋って素敵だね、そういうシチュエーションに胸を躍らせていたりしたのではないでしょうか。

話がそれました。ケータイ小説は連載小説であるという特性からかページが割と細かく区切られていて、それぞれのページに書かれている文字数は大体の場合600字ぐらいです。つまり大作になればなるほどページ数は多くなっていき、恋空の前編は484ページにもなります。文字数をカウントするために484ページをいちいち開いてコピペするのはさすがにやってられないので、プログラミングの力で自動でやろうと思います。

使う言語ですが、なんかpythonって使いやすいらしいよという噂を聞いたのでpython3を使うことにしました。統合開発環境のPyCharmを使用してやっていきます。僕は「プログラミングのプの字」のプの字をかじったことがあるぐらいのプログラミング経験しかなく、pythonを扱うのは初めてです。いろんなwebサイトを検索してつぎはぎしながらやっていったので余分なことや効率が悪いことをいくつかしているかと思います。でも僕の中でのpythonの初仕事は恋空です。これだけは変わりません。

自動化の方針
恋空が掲載されている魔法のiらんどの恋空の1ページ目に自動でアクセス

ページのソースコードを自動で取得

ソースコードから恋空本文だけを抜き出す

抜き出した文章を保存&文字数カウント

2ページ目以降も484ページ目まで同様にやる

恋空前編の文字数とついでにシームレスな本文が手に入る

恋空後編と君空でも同様にやる

こんな感じでいきます

ページのソースの取得
pythonにurllibというパッケージがあり、その中のurllib.requestというライブラリがあります。

import urllib.request
request = urllib.request.Request(url)
response = urllib.request.urlopen(request)
source= response.read().decode("utf-8", "ignore")

こうやってやると文字列urlが表すURLのソースをいい感じに取得できます。
全ページに渡ってソースを取得するために、文字列urlの部分には恋空の全ページのURLが順番に入るようにしなければいけません。幸いなことにURLの末尾の数字がページのページ番号を表していました。具体的に言うと、恋空前編の1ページ目のURLはhttp://s.maho.jp/book/af5770e0601598ef/6960568627/1/であり、2ページ目のURLはhttp://s.maho.jp/book/af5770e0601598ef/6960568627/2/で、末尾の数字だけが異なります。こういう都合のいい形をしていてくれたので、

for i in range(1, 485):
    site = "http://s.maho.jp/book/af5770e0601598ef/6960568627/"
    url = site + str(i)+"/"

このようにfor分でページ数の分だけ繰り返しながら文字列の結合をすることで全ページのURLを網羅することができました。

上記の二つを組み合わせることで恋空の本文が載っている全ページのソースコードを取得することができました。

本文を抜き出す
ソースコードはhtmlで書かれていて、文章がそのまま入っているわけではありません。抜き出したいものの前後にある余計なものは切り取るだけでいいのですが、本文中にある要らないものは何とか処理する必要があります。具体的には改行に使われる<br />です。これをreplaceという関数を使って取り除きました。

bun = source.replace('<br />', '')

次にソースコードのうち本文が書かれている部分をなんとかして抜き出します。幸運なことに本文を挟んでいる inner row"< と <span style="display:none"> という文字列はどのページのソースコード中にもそれぞれ一回しか登場しなかったので、複雑なことを考えなくて大丈夫でした。ソースコードの文字列からこれらを検索し、それぞれ何文字目にあるか把握し、間の部分だけを取り出します。

forward = bun.find('inner row">')
forward = forward + 44
back = bun.find('<span style="display:none">')
back = back - 38
koi = bun[forward:back]

1行目と3行目でそれぞれ本文を挟む文字列を検索しています。forwardにはinner row"<の初めのiが0オリジンで何文字目に来るか、backには <span style="display:none">の初めの<が何文字目に来るかの情報が入ります。
2行目と4行目の数字を増減させているのは、検索に使った文字列と実際の文章の間に空白や</p>などの文字が存在しているからです。それらの分だけずらすことでforwardとbackがそれぞれ本文の初めと終わりの番号を示すことになります。
初めと終わりが何文字目にあるか知ることができれば、終わりからはじめを引き算することで本文の文字数がわかることになります。やったね。
文字列koiは文字列bunからforwardとbackの値を使って恋空の本文だけを抜き出したものになっています

文字数カウント
文字数は各ページごとにカウントして、それらを順次足していきます。

ind=0
for i in range(1, 485):
    上述のやつら
    ind = ind + forward - back

こうすることで新しいページを読み込むたびにそのページの文字数をindに追加することができます。

テキストファイルへの出力
codecsというパッケージを使いながら保持している文字列をテキストファイルへ出力できました。文字コードの都合とかがあるようでいろいろやってみたところ、次のようにやったらうまくいきました。

import codecs
out = codecs.open('honbun.txt', 'a', 'utf-8')
out.write(koi)
out.close()

honbun.txtを開き(無かったらつくり)、文字コードとしてutf-8を用いてテキストファイルの末尾に文字列koiを追加する、ということをやっています。これで新しいページを読み込むごとにその本文を1つのテキストファイルに移していく、ということができました。


以上のことをまとめたコードは次の通りです。

# 魔法のiらんどに掲載されているケータイ小説の文字数をカウントする&本文をまとめてテキストに出力する
import codecs
import urllib.request
yagi=0  #カウンターのリセット
for uma in range(1, 485):  #rangeは1,ページ数+1
    ushi = "http://s.maho.jp/book/af5770e0601598ef/6960568627/"  #表紙のアドレス
    gumi = ushi + str(uma)+"/"  #ページ番号を含めた完全なURLを作る
    request = urllib.request.Request(gumi)  #ここから3行でページにアクセスしてそのソースを読み込む
    response = urllib.request.urlopen(request)
    sosu= response.read().decode("utf-8", "ignore")
    bun = sosu.replace('<br />', '')  #htmlで改行を示すために使われる<br />を消す
    kai = bun.find('inner row">')  #ソースコードで本文が始まるところの直前だけにあるやつの位置
    kai = kai + 44  #その他空白などの文字数調整
    hei = bun.find('<span style="display:none">')  #本文が終わった後にだけあるやつの位置
    hei = hei - 38  #文字数調整

    # テキストデータ取得
    # print(bun[kai:hei])  # 本文を表示(取得には不要)
    # hon = bun[kai:hei] + '\n'  # 本文の後に改行を加える
    # shika = codecs.open('honbun.txt', 'a', 'utf-8')  # ここから3行でそのページの文章をテキストファイルに書き足しする
    # shika.write(hon)
    # shika.close()

    yagi = yagi + hei - kai+1  # 文字数カウント
    # print(yagi)  # その時点での文字数を表示
print(yagi - 1)  # 最終的な文字数を表示


結果

恋空の文字数 411106字(前編247844字、後編163262字)
君空の文字数 21582


変数名は先ほどの説明と違いますが、上のコードをコピペしてpythonで実行すれば動くはずです。テキストファイル作成の部分はコメントアウトしていますが、冒頭の#を消せばそれもちゃんと動くはずです。

注意点として、このカウント方式では改行とページ区切りを1文字としてカウントしています。
また恋空前編と後編の切れ目は文字数や改ページとしてカウントしていません。


振り返り

無事に恋空前編と恋空後編と君空の文字数をカウントすることができ、副産物としてシームレスな恋空と君空のデータを手に入れることができました。前編のページ数が一番多いので前編に一番時間がかかりました。前編の実行時間は5分ぐらいだったと思います。

皆さんわかっていると思いますが、このプログラムは恋空系列の作品だけでなくて魔法のiらんどで公開されている小説で文章中に大きさの異なる文字や絵文字や画像が挿入されてないものに対してならどれでも使えると思います。for分のところにあるページ数の項目とソースを取得するための部分にあるURLを変えればいけるはずです。絵文字や画像に対応させる(そういうのは無視するようにする)のはそんなに難しくないと思います。



恋空を読んだことない人は読んでみてはどうでしょうか。411106文字あるんですけど。リンクを貼っておきます

恋空

前編 後編

君空


おまけ

副産物として得られた恋空のテキストデータを使うと恋空中の文字列検索ができます。

f:id:baklajan:20170815013028p:plain

めちゃ長い


恋空の前編後編を合わせた中に
「なんでやねん」という文字列は2回登場します。
「オタク」という文字列は1度も登場しません。
「…」は4362回登場します。
PHS」は51回登場します。
「好き」は357回、「妊娠」は31回、「空」は88回登場します。
「美嘉」は2335回、「ヒロ」は2115回登場します。
この結果ではひらがなとカタカナは区別していないので、ヒロの名前が出てきた回数はもう少し少ないと予想されます。

以上です。