ツナワタリマイライフ

日常ネタから技術ネタ、音楽ネタまで何でも書きます。

node.jsでクローリングしてことわざの使用例をつぶやくbotを作った

はじめに

以前語彙力に関する本を読んだんですが、そこに出てくる例があまりよく知らない故事成語やことわざが多く、本当に教養人はこういう言葉を日常で使うのかしら、と思っていた。そのとき書いた記事がこれ。

take-she12.hatenablog.com

ところがどっこい、この記事を書いた直後の勉強会で、同期氏がとあるプロジェクトに関して「まぁ、あれは砂上の楼閣でしょうがw」と言っていて、キャー!教養!となったのでありました。

また、node.jsのクローラーに関する本を買っていたので、ことわざの使用例をクローリングしてつぶやいたら面白いのでは?と思い今に至ります。この本とってもいいですよ。

プログラムの流れ

まずことわざはことわざ.bizさんから使わせていただこうと思います。

xn--28jg7cui.biz

最終更新2013年で止まってますが、ポリシーが明記されてるわけでもないし、出展をちゃんと出せばいいかと思って使わせてもらってます。

  1. クローリングする
    node.jsを使ってことわざサイトからページをダウンロードします。
  2. 正規表現抽出する
    ことわざ名と使用例を抽出します。
  3. つぶやく
    twitterにつぶやきます。

では1つずつ見ていきましょう。

クローリングする

ここはnode.jsでやりました。早速ソースコード

MacBook-Air:kotowaza take$ cat get_kotowaza.js 
for(var i=26;i<=68;i++){
  console.log(i+"回目");
  download(
    "http://xn--28jg7cui.biz/cat"+i+"/",
    "cat"+i+".html",
    function(num){console.log("ok, cat"+num);},
    i
    );
}

function download(url, savepath, callback, num){
  var http = require('http')
  var fs = require('fs')
  var outfile = fs.createWriteStream(savepath);
  var req = http.get(url, function(res){
    res.pipe(outfile);
    res.on('end', function(){
      outfile.close();
      callback(num);
    });
  });
}

これを実行した結果が以下。

26回目
27回目
28回目
29回目
途中省略、順に表示)
66回目
67回目
68回目
ok, cat32
ok, cat27
ok, cat31
ok, cat26
ok, cat30
ok, cat29
ok, cat33
ok, cat41
ok, cat38
ok, cat28
ok, cat36
ok, cat34
ok, cat35
ok, cat40
ok, cat42
ok, cat44
ok, cat37
ok, cat39
ok, cat45
ok, cat48
ok, cat51
ok, cat55
ok, cat47
ok, cat43
ok, cat53
ok, cat46
ok, cat60
ok, cat62
ok, cat50
ok, cat54
ok, cat66
ok, cat52
ok, cat57
ok, cat56
ok, cat68
ok, cat58
ok, cat49
ok, cat63
ok, cat61
ok, cat59
ok, cat64
ok, cat65
ok, cat67

キャーちゃんと非同期!抱いて!

ちゃんと説明します。
ことわざ.bizさんのページはファイルパスがcat26.html〜cat68.htmlになっていたので、ここをfor loopでまわしました。
downloadのfuntionを下で定義しています。実行時に何番目のDLを実行しているかっていうのを4つめの引数で渡していて、callback関数で受け取っています。
結果、ちゃんとバラバラに帰ってきてキャー非同期抱いて!ってなるわけですね!

正規表現抽出する

すみません最近同じようなことしかしてないですがシェルスクリプトです。だって何回もダウンロードする必要ないし。。。

MacBook-Air:kotowaza take$ cat extract_kotowaza.sh 
for i in `seq 26 68`
do
  grep 読み cat${i}.html | while read line
  do
    title=`echo $line | sed -e 's/^<p>\(.*\)<br \/><br \/>◆読み\(.*\)/\1/g'`
    exam=`echo $line | sed -e 's/\(.*\)<br \/><br \/>◆使用例<br \/>\(.*\)<br \/><br \/>◆一言メモ\(.*\)/\2/g'`
    echo "${title},${exam}" | grep -v 読み | grep -v 類似ことわざ >> kotowaza_result.txt
  done
done

シェルスクリプトのforではseqコマンドが便利ですね。連続した数値をとるために。
sed正規表現の後方参照をしていますが、ことわざbizさんあまりhtmlが構造化されてなくて普通にゴリゴリ書かれてたんで愚直に抽出しました。ハハ。。。元のhtmlは以下です。

 <p>痘痕も笑窪<br /><br />◆読み<br />あばたもえくぼ<br /><br />◆意味<br />好きになってしまうと、相手も欠点もまで好きになってしまうこと。<br /><    br />◆使用例<br />恋をすると「痘痕も笑窪」だからね。<br /><br />◆一言メモ<br />恋をするだけでなく、何かに傾倒してしまうと「痘痕も笑窪」になっ>    てしまうものです。<br />他人から見ると信じられないような物に、高い評価をしているような場合。「痘痕も笑窪」と言います。</p> 

ちなみに改行されてるやつとされてないやつがあったのでされてるやつは無視しました。2,3個、使用例と一言メモの間に類似ことわざがあるやつがあったのでそれは削りました。(笑)

outputされたファイルはこんな感じで出ます。

MacBook-Air:kotowaza take$ head kotowaza_result.txt 
痘痕も笑窪,恋をすると「痘痕も笑窪」だからね。
案ずるより産むが易し,色々受験について心配しているけど「案ずるより産むが易し」だから。
ああ言えばこう言う,○○さんは「ああ言えばこう言う」人だから。<br />ああ言えばこう言わないで<br /><br />◆類似ことわざ<br />右と言えば左
医者の不養生,人に注意しておきながら失敗するなんて「医者の不養生」だよ。
石の上にも三年,今は耐えろ。石の上にも三年というじゃないか。
言うは易く行うは難し,毎日10キロ走るって事は「言うは易く行うは難し」だったよ。
後ろ指を指される,後ろ指を指されるようなことをしたんじゃないか?
うどの大木,あいつは体がでかい割りに、強くないな。「うどの大木」だな。
魚心あれば水心(魚心あれば水心あり),丁寧に接すればお客様も「魚心あれば水心」でご理解いただけるはずだ。
海老で鯛を釣る,あの投資は「海老で鯛を釣る」ような物だったよ。

つぶやく

いや、全部node.jsでやれよって話はごもっともなんですがまずは慣れた手法で実現したいじゃない。rubyです。(笑)

MacBook-Air:kotowaza take$ cat kyoyo-daite.rb 
require 'rubygems'
require 'twitter'

# initialize
@array = []

# open file
File.open('kotowaza_result.txt') do |file|
  file.each_line do |line|
    @array << line.split(",")
  end                                 
end

# element extraction at random
kotowaza = @array.sample
title = kotowaza[0]
exam = kotowaza[1]

# authentication
client = Twitter::REST::Client.new do |config|
  config.consumer_key = (省略)
  config.consumer_secret = (省略)
  config.access_token = (省略)
  config.access_token_secret = (省略)
end

# tweet
client.update("教養人「#{exam}」わたし「キャー教養!抱いて!」#{title} from http://xn--28jg7cui.biz/")

splitで配列に分けられるのでそれを配列にぶち込んで配列の配列に。
sampleメソッドで簡単にrandomで取り出せるのrubyちゃんすごい。

結果

https://twitter.com/take_she11/status/704242248406343680

おわりに

rubyをcronでまわせばbot化できるんですけど誰得だよって話なので週1ぐらいにしときます。(笑)

もっとクローラーでやりたいこと思いついたらちゃんとxml解析とかもしたいな。ネタが思い浮かばん。

slideshare

同期とのskype勉強会でLTした。ただフォントの問題かプレビューだと日本語が表示されないのがめっちゃつまらん。ちゃんと拡大すると見えるのに。Azusaやめるか。

www.slideshare.net