rails 独学して軽くにちゃんまとめつくる

読者です 読者をやめる 読者になる 読者になる

rails独学して軽く2ちゃんまとめビルダーをつくる。

rails tutorial読破→2chまとめビルダー作成→アメリカでインターンシップ→恋活SNSを作成・・・・・→音で感触をつくり感触をあつめたライブラリをつくる

mecab に単語を追加するユーザー辞書を追加する

csv 形態素解析

まずは動作確認をして追加できることを確かめて安心しよう。

コマンドラインでシステム辞書のディレクトリを探すために

find / -name "mecab-dict-index"  と入力し、 mecab-dict-index のある場所を探す ぼくの環境では /usr/lib/mecab/mecab-dict-index だった。

コマンドラインでユーザー辞書のディレクトリを探すために

find / -name "dicrc" として `dicrc がある場所を探す。 ぼくの環境では/var/lib/mecab/dic/ipadic/dicrcとなった。ここからdicrcを外した /usr/share/mecab/dic/ipadic/` を使う。

③ユーザー辞書をつくる。場所はどこでもいいが、①に近い場所がいいですのでこういう場所にするのが理想だと思う。

mkdir /usr/lib/mecab/dic/userdic

でもなぜかできなかったので

mkdir userdic としてフォルダをつくり、その中に user.dic という空のファイルをつくる。

よってあらわすディレクトリは userdic/user.dic となる

csv 形式で辞書をつくる。 foo.csv という名前にしておいて以下の内容をコピペしよう。

フォロワー,0,0,1,名詞,固有名詞,*,*,*,*,ふぉろわー,ふぉろわー,ふぉろわー 保存する場所はここではルートディレクトリにした。

/usr/lib/mecab/mecab-dict-index -d /usr/share/mecab/dic/ipadic/ -u dic/user.dic foo.csv

として追加。構成は (①で得たディレクトリ) -d (②で得たディレクトリ) -u (③のディレクトリ) (④のディレクトリ) とする。

⑤完了。 echo 'フォローよろしく!' | mecab -u userdic/user.dic と入力してたしかめてくれ。

 $ find / -name "mecab-ipadic"

find: `/root': Permission denied
find: `/lost+found': Permission denied
find: `/nix/.cache': Permission denied
/usr/share/doc/mecab-ipadic

辞書ファイルを作ろう。サンプルとしてルートディレクトリに foo.csv という名前をつけた。「フォロー」という単語をつけたそう。

フォロワー,0,0,1,名詞,固有名詞,*,*,*,*,ふぉろわー,ふぉろわー,ふぉろわー

これをコピペすればいい。そんで、

$ /usr/lib/mecab/mecab-dict-index -d /usr/share/doc/mecab-ipadic -u foo.csv -f utf-8 -t utf-8 foo.csv

dictionary_compiler.cpp(82) [param.load(DCONF(DICRC))] no such file or directory: /usr/share/doc/mecab-ipadic/dicrc

サイトに書かれていた通りするとこんなエラーがでた。よくわからんが、 dicrc がないといわれたので $ find / -name "dicrc" とすると

$ find / -name "dicrc"

/var/lib/mecab/dic/ipadic-utf8/dicrc
/var/lib/mecab/dic/ipadic/dicrc
/usr/share/mecab/dic/ipadic/dicrc

とかいてあった。複数あるがどうやら /var/lib/mecab/dic/ipadic/dicrc というのが正しいかんじ。で次に -d だけをいれてみると

$ /usr/lib/mecab/mecab-dict-index -d /usr/share/mecab/dic/ipadic/dicrc 
dictionary_compiler.cpp(82) [param.load(DCONF(DICRC))] no such file or directory: /usr/share/mecab/dic/ipadic/dicrc/dicrc

ありゃりゃ。 dicrc というのは不要だったようだ。ということで dicrc をはずしてもう一度実行すると

$ /usr/lib/mecab/mecab-dict-index -d /usr/share/mecab
/dic/ipadic/

reading /usr/share/mecab/dic/ipadic/unk.def ... 40
emitting double-array: 100% |###########################################| 
/usr/share/mecab/dic/ipadic/model.def is not found. skipped.
reading /usr/share/mecab/dic/ipadic/Others.csv ... 2
reading /usr/share/mecab/dic/ipadic/Interjection.csv ... 252
reading /usr/share/mecab/dic/ipadic/Symbol.csv ... 208
reading /usr/share/mecab/dic/ipadic/Adverb.csv ... 3032
reading /usr/share/mecab/dic/ipadic/Noun.name.csv ... 34202
(中略)

reading /usr/share/mecab/dic/ipadic/Adnominal.csv ... 135
reading /usr/share/mecab/dic/ipadic/Filler.csv ... 19
reading /usr/share/mecab/dic/ipadic/Noun.number.csv ... 42
reading /usr/share/mecab/dic/ipadic/Noun.adjv.csv ... 3328
emitting double-array: 100% |###########################################| 
reading /usr/share/mecab/dic/ipadic/matrix.def ... 1316x1316
emitting matrix      : 100% |###########################################| 

done!

ん?なんかダウンロードしてしまった。。。それと同時にルートディレクトリに char.binmatrix.binunk.dicsys.dic というのができた。

次にのこるフラグの -u を追加して実行する。

 $ /usr/lib/mecab/mecab-dict-index -d /usr/share/mecab/dic/ipadic/ -u foo.csv  foo.csv


reading foo.csv ... 1
emitting double-array: 100% |###########################################| 

done!

ふむふむ。どうやら完了したらしい。動作確認をしよう。わざわざ .rb を作成せずともコマンドラインで実行できる。

 $ echo 'フォローよろしくれ!' | mecab


フォロー        名詞,サ変接続,*,*,*,*,フォロー,フォロー,フォロー
よろしく        形容詞,自立,*,*,形容詞・イ段,連用テ接続,よろしい, ヨロシク,ヨロシク
れ      動詞,接尾,*,*,一段,連用形,れる,レ,レ
!       名詞,サ変接続,*,*,*,*,*
EOS

よし。完成した。。。。のか?

たしか活用は「サ変接続」ではなくて 「固有名詞」にしたはずだぞ。ユーザー辞書がうまく機能してないので反映されてないじゃないか。

そうおもって調べてみたら設定をし忘れた。

echo のときにユーザー辞書の指定をしなきゃならないらしい。 気を取り直してやってみる。

$ echo 'フォローよろしく!' | mecab -u  userdic/user.dic
フォロー        名詞,固有名詞,*,*,*,*,フォロー,フォロー,フォロー
よろしく        副詞,一般,*,*,*,*,よろしく,ヨロシク,ヨロシク
!      記号,一般,*,*,*,*,!,!,!
EOS

よし、できた。

おつかれさま。これで完了です。あとは単語を収集してついかするだけ~~

&& や || に否定の条件を挟みたい

結論から言えば 条件 && 条件 && (! 条件) というように(! ) を挿入します。

&& や || は「かつ」「または」という意味なので、条件には true となるものを置く必要があると勘違いしていた。しかし否定の条件も挟むことができる。

「日本人でかつ 東京都民でかつ 23区にすんでない人」 みたいな。

`

ruby 特定の文字が含まれていない配列だけとりだす

配列・ハッシュ

言い換えれば配列と配列の比較をしたい人のための記事だ。完全一致と部分一致で比較したい人が見るべき。

配列は結局は文字の集まりだから、文字同士の比較と考えよう。

禁止ワードを取り除くとでもいうのか。rubyクローラーで取り合えずデータ収集したのだが、邪魔なワードが含まれているものははじきたかったので調べてみた。

どらえもんのキャラで例える。

ary = [["のびた", "野比家の子供"], ["スネ夫", "金持ちのボンボン"], 
        ["ジャイアン", "雑貨屋の息子"], ["静香", "中流階級"], ["どらえもん", "居候"]]

という多次元配列があるとする。これで「のびた」と「どらえもん」だけを除いた配列がほしいときはinclude? メソッドと、邪魔なワードの配列をつくればいい。

ary = [["のびた", "野比家の子供"], ["スネ夫", "金持ちのボンボン"], 
        ["ジャイアン", "雑貨屋の息子"], ["静香", "中流階級"], ["どらえもん", "居候"]]
damenahito = ["のびた", "どらえもん"]

ary.each do |hito|
  p hito unless damenahito.include?(hito[0])
end

############
$ ruby sample.rb
["スネ夫", "金持ちのボンボン"]
["ジャイアン", "雑貨屋の息子"]
["静香", "中流階級"]

となり、のびたとどらえもんのいない配列を取得することができた。ここでは配列と文字の比較をしたのだ。

ary.include?(string)

(配列).include? (文字) 

とすることで、文字を配列にある禁止ワードリストと比較してくれる。存在すれば true でなければ false をかえしてくれる。

配列の2つめのように、文章を検索して禁止ワードと中間一致しているのも検出したい場合を考える。やることは同じで、上のコードをもう少し拡張する。

こうすればいい

ary = [["のびた", "野比家の子供"], ["スネ夫", "金持ちのボンボン"], 
        ["ジャイアン", "雑貨屋の息子"], ["静香", "中流階級"], ["どらえもん", "青い居候"]]
damekeyword = ["ボンボン", "居候"]


ary.each do |hito|
  damekeyword.each do |dame|
   p hito if  hito[1].include?(dame)
  end
end

###############

 $ ruby sample.rb
["スネ夫", "金持ちのボンボン"]
["ジャイアン", "雑貨屋の息子"]
["静香", "中流階級"]
------------------
["スネ夫", "金持ちのボンボン"]
["どらえもん", "青い居候"]

「ボンボン」「居候」という文字が含まれているものだけを検出したいときはこうする。ary と damekeyword の両方に対して each をするのは配列をバラバラにして文字同士の比較にまで次元を落とすためである。最初のは配列と文字の比較だったが、どうやらその場合は完全一致にするひつようがあり中間一致はうまくいかなかったのだ。

文字の検索(中間一致)

str1.include?(str2)
(文字1).include?(文字2)


※ただし中間一致なのだから(文字1)に長いほうの文字を、(文字2)にキーワードを入れよう

これで終わり。おつかれさん。

rubyのTwitter::Stream使いツイッターでエクセルで使える名簿を作成する

twitterAPI csv

悪用厳禁でおねがいします。また、今回は Twitter::Streaming を使うため、質よりも量を重視しています。フォロワー○○人以上!とかアニメが好きな人とか東京在住の女子大生なんてコアな層の名簿を作りたいひとは対象外です。あくまで悪用はしないけど、twitter::Streaming の応用や rubycsv 使いたいなーと思う人がためしてください。

とりあえずこれがソース。

require 'tweetstream'
require 'csv'


config = {
  :consumer_key      => 'じぶんの',
  :consumer_secret   => 'じぶんの',
  :access_token      => 'じぶんの',
  :access_token_secret => "じぶんの"
}

meibo_list = Array.new 
meibo_ary = Array.new
list_tweets = Array.new
count = 0

client = Twitter::Streaming::Client.new(config)
CSV.open('tweet_meibo.csv', 'w') do |meibo|
  client.sample do |tweet|
    tmp_ary = Array.new
    puts count + ""
    if tweet.is_a?(Twitter::Tweet) && tweet.lang == "ja"
      tmp_ary << "@" + tweet.user.screen_name
      tmp_ary << tweet.user.name
      tmp_ary << tweet.user.description
      meibo << tmp_ary
      break if count >= 100 #ほしい名簿の件数をお書き
      count += 1
    end
  end
end

これでツイッターアカウントのIDと名前と自己紹介文を取得することができる。現在つぶやいている人ツイートを介しているのでアクティブユーザーである可能性がたかいといえます。

ポイントを説明しておきます。 まず config で設定されているコードは自分で取得してください。検索すればたくさん出てきます。ツイッターの登録と電話番号の登録をして、数クリックするだけで取得できます。10分でできます。

twitter api 登録 - Google 検索

CSV.open('tweet_meibo.csv', 'w') do |meibo| この部分で CSV を開けてます。中の tweet_meibo.csv というのは CSV ファイル名で、なければ自動で作成してくれるのでそのままでいいでしょう。

CSV ファイルはエクセルで使える形式のファイルで

名前,食べ物,飲み物
もり,マック,コーラ
かみ,はす,ファンタ

みたいにコンマと改行とデータから成り立ってます。これはエクセルのように碁盤状のデータ構造なのでエクセルで開けます。

if tweet.lang == "ja"

これはツイッターが日本語であることを要請しています。

tmp_ary << "@" + tweet.user.screen_name
tmp_ary << tweet.user.name
tmp_ary << tweet.user.description

tmp_ary という配列にデータを入れています。 CSV ファイルを扱うとき、Ruby では2次元配列として処理するので、1人のユーザーの情報を配列として扱ってます。

tweet.user で流れているツイッターのユーザー情報を取得することができます。 tweet.user.screen_name で @で始まるあのIDを取得することができます。この状態では@ がついてないのでつけておきます。

tweet.user.name は文字通り名前を取得できます。

tweet.user.descriptionでそのユーザーの自己紹介文を取得することができます。

https://www.google.co.jp/search?q=twitter+api+%E7%99%BB%E9%8C%B2&ie=utf-8&oe=utf-8&client=firefox-b-ab&gfe_rd=cr&ei=6yvVWLvxM8OQ8Qfao6rABA

meibo << tmp_ary でmeibo という配列に先ほどユーザーの名前、ID、自己紹介文の配列をいれます。先ほども書きましたが、RubyCSV ファイルの書き込み読み込みをするときは2次元配列として扱うことに注意してください。

break if count >= 100 で100人分の名簿を集めることができます。ここの数字を変えることで取得できる人数を変えることができます。

Ubuntu や Cloud9ruby で natto をインストールがやっとできた。

パス 形態素解析

・natto 使えばmecab いらんやんけ、と思ってる人は間違い。 ・ libmecab.so が入ってない(´;ω;`)って人はgem の前に sudo でいれろ。

まとめ ーーーーーーーーーーーーーーーーーーーーー ①gem install natto でgem のインストール

sudo apt-get update でsude のアップデート

sudo apt-get install libmecab2 libmecab-dev mecab mecab-ipadic mecab-ipadic-utf8 mecab-utilsmecab を内部にいれる

sudo find / -name libmecab.so*mecab 入ってるか確認。

export MECAB_PATH=/usr/lib/libmecab.so.2 でパスの指定

require 'natto'

text = 'すもももももももものうち'

natto = Natto::MeCab.new
natto.parse(text) do |n|
  puts "#{n.surface}\t#{n.feature}"
end

サンプルコードを mecab.rb にかく。

ruby mecab.rb で実行

 ruby mecab.rb
すもも  名詞,一般,*,*,*,*,すもも,スモモ,スモモ
も      助詞,係助詞,*,*,*,*,も,モ,モ
もも    名詞,一般,*,*,*,*,もも,モモ,モモ
も      助詞,係助詞,*,*,*,*,も,モ,モ
もも    名詞,一般,*,*,*,*,もも,モモ,モモ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
うち    名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ
        BOS/EOS,*,*,*,*,*,*,*,*

ーーーーーーーーーーーーーーーーーーーーー おそらくここにたどり着くまでに何度もほかのサイトに行って、投げ出したくなる気持ちを抑え、やっとのもいでここにたどりついたとおもう。おつかれさま。これできみは natto を使うことができるぞ。え? windows 環境でやりたい?しらん知らん。Cloud9 でもググってもう一回きてくれ。

ちなみにここでたどり着いた人の中に

sudo find / -name libmecab.so*

で探しても lbmecab.so が見つからないという人がいることを想定している。よかったね。君はついに解決できるよ。もしかして君は Ubuntu や Cloud9 に mecab をインストールするまえに gem install mecabをしたに違いない。そりゃ失敗するわな。まずは mecab を実機にインスト―ルするところからはじまるんだよ。早速解決にはいろう。

まず natto をインストールしたはずだ。そしてそこではエラーがでない。

$ sudo gem install natto
Fetching: ffi-1.9.18.gem (100%)
Building native extensions.  This could take a while...
Successfully installed ffi-1.9.18
Fetching: natto-1.1.1.gem (100%)
Successfully installed natto-1.1.1
2 gems installed

つぎに君はサンプルコードを実行したはず。たとえばこんなコードかな?

require 'natto'

text = 'すもももももももものうち'

natto = Natto::MeCab.new
natto.parse(text) do |n|
  puts "#{n.surface}\t#{n.feature}"
end

そして実行するとこんなエラーがでる。

$ ruby mecab.rb 
/usr/local/rvm/gems/ruby-2.2.1@global/gems/natto-1.0.1/lib/natto/binding.rb:58:in `rescue in find_library': Please set MECAB_PATH to the full path to libmecab.so (LoadError)
        from /usr/local/rvm/gems/ruby-2.2.1@global/gems/natto-1.0.1/lib/natto/binding.rb:48:in `find_library'
        from /usr/local/rvm/gems/ruby-2.2.1@global/gems/natto-1.0.1/lib/natto/binding.rb:64:in `<module:Binding>'
        from /usr/local/rvm/gems/ruby-2.2.1@global/gems/natto-1.0.1/lib/natto/binding.rb:6:in `<module:Natto>'
        from /usr/local/rvm/gems/ruby-2.2.1@global/gems/natto-1.0.1/lib/natto/binding.rb:2:in `<top (required)>'
        from /usr/local/rvm/rubies/ruby-2.2.1/lib/ruby/site_ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require'
        from /usr/local/rvm/rubies/ruby-2.2.1/lib/ruby/site_ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require'
        from /usr/local/rvm/gems/ruby-2.2.1@global/gems/natto-1.0.1/lib/natto/natto.rb:2:in `<top (required)>'
        from /usr/local/rvm/rubies/ruby-2.2.1/lib/ruby/site_ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require'
        from /usr/local/rvm/rubies/ruby-2.2.1/lib/ruby/site_ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require'
        from /usr/local/rvm/gems/ruby-2.2.1@global/gems/natto-1.0.1/lib/natto.rb:2:in `<top (required)>'
        from /usr/local/rvm/rubies/ruby-2.2.1/lib/ruby/site_ruby/2.2.0/rubygems/core_ext/kernel_require.rb:128:in `require'
        from /usr/local/rvm/rubies/ruby-2.2.1/lib/ruby/site_ruby/2.2.0/rubygems/core_ext/kernel_require.rb:128:in `rescue in require'
        from /usr/local/rvm/rubies/ruby-2.2.1/lib/ruby/site_ruby/2.2.0/rubygems/core_ext/kernel_require.rb:39:in `require'

なんだかパスを通せと言われる。。 いわれた通りパスをとおし、

$ export MECAB_PATH=/usr/local/lib/libmecab.so

実行してみると・・・

$ ruby test.rb
/usr/local/rvm/gems/ruby-2.3.0@global/gems/ffi-1.9.18/lib/ffi/library.rb:147
:in `block in ffi_lib'
: Could not open library '/usr/local/lib/libmecab.so'
: /usr/local/lib/libmecab.so: cannot open shared object file
: No such file or directory (LoadError)


        from /usr/local/rvm/gems/ruby-2.3.0@global/gems/ffi-1.9.18/lib/ffi/library.rb:100:in `map'
        from /usr/local/rvm/gems/ruby-2.3.0@global/gems/ffi-1.9.18/lib/ffi/library.rb:100:in `ffi_lib'
        from /usr/local/rvm/gems/ruby-2.3.0@global/gems/natto-1.1.1/lib/natto/binding.rb:64:in `<module:Binding>'
        from /usr/local/rvm/gems/ruby-2.3.0@global/gems/natto-1.1.1/lib/natto/binding.rb:6:in `<module:Natto>'
        from /usr/local/rvm/gems/ruby-2.3.0@global/gems/natto-1.1.1/lib/natto/binding.rb:2:in `<top (required)>'
        from /usr/local/rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'
        from /usr/local/rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'
        from /usr/local/rvm/gems/ruby-2.3.0@global/gems/natto-1.1.1/lib/natto/natto.rb:2:in `<top (required)>'
        from /usr/local/rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'
        from /usr/local/rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'
        from /usr/local/rvm/gems/ruby-2.3.0@global/gems/natto-1.1.1/lib/natto.rb:2:in `<top (required)>'
        from /usr/local/rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:127:in `require'
        from /usr/local/rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:127:in `rescue in require'
        from /usr/local/rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:40:in `require'
        from test.rb:1:in `<main>'

/usr/local/lib/libmecab.so これがないと怒られる。だから探してみると

 sudo find / -name libmecab.so*

反応なし。。。 ということはそもそも libmecab 入ってへんということやんけ。ほかのサイトではnatto いれたら入ってるようなこと書いてたのに・・・

そんで3時間くらい経つとやっとみつけた。 MacでRubyを使ってMeCabを利用する準備 - 別館 子子子子子子(ねこのここねこ) このサイトの人に感謝感謝。タイトルに Mac とかいてあったから避けてたがよく見てみたら回答があった。ということでここの人の言う通り Ubuntu 本体にダウンロードしてわすれていたのだ。

このサイトを参考にして、

UbuntuでのMeCabの利用 - Qiita

$ sudo apt-get update
$ sudo apt-get install libmecab1 libmecab-dev mecab mecab-ipadic mecab-ipadic-utf8 mecab-utils

ん?なんか言われたぞ。

$ sudo apt-get install libmecab1 libmecab-dev mecab mecab-ipadic mecab-ipadic-utf8 mecab-utils
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Package libmecab1 is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source
However the following packages replace it:
  libmecab2:i386 libmecab2

よくわからんが、 libmecab2 にしろってことか?

$ sudo apt-get install libmecab2 libmecab-dev mecab mecab-ipadic mecab-ipadic-utf8 mecab-utils                                                         
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following NEW packages will be installed:
  libmecab-dev libmecab2 mecab mecab-ipadic mecab-ipadic-utf8 mecab-utils
0 upgraded, 6 newly installed, 0 to remove and 34 not upgraded.
Need to get 12.7 MB of archives.

おっ、いけたわ!ホンマにはいっとるかちゃんと確認してみよや

$ sudo find / -name libmecab.so*
/usr/lib/libmecab.so.2
/usr/lib/libmecab.so.2.0.0
/usr/lib/libmecab.so

はいっとることがわかった。よっしゃ起動してみよや。。。。とおもったらまたエラー

$ ruby mecab.rb
/usr/local/rvm/gems/ruby-2.3.0@global/gems/ffi-1.9.18/lib/ffi/library.rb:147:in `block in ffi_lib': Could not open library '/home/ubuntu/workspace/libmecab.so': /home/ubuntu/workspace/libmecab.so: cannot open shared object file: No such file or directory (LoadError)
        from /usr/local/rvm/gems/ruby-2.

このサイトを参考に、もう一度パスの設定をしなおした。 mecabをRubyから使おうとしたらエラーが・・・・ - /var/www/yatta47.log

$ export MECAB_PATH=/usr/lib/libmecab.so.2  

としてやってみると・・・・

 $ ruby mecab.rb
すもも  名詞,一般,*,*,*,*,すもも,スモモ,スモモ
も      助詞,係助詞,*,*,*,*,も,モ,モ
もも    名詞,一般,*,*,*,*,もも,モモ,モモ
も      助詞,係助詞,*,*,*,*,も,モ,モ
もも    名詞,一般,*,*,*,*,もも,モモ,モモ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
うち    名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ
        BOS/EOS,*,*,*,*,*,*,*,*

よっしゃ!!いけたで!!!!!

やれやれ、やっと終わったわ。なんかするとき、 gem だけでなく本体にもいれなあかんといういい教訓と、パスの入れ方を勉強したわ。まあまあよかった。

まとめとこ。

いきなり gem や bundle が使えなくなった。パスの通し方について。

 $ export PATH=/usr/local/mecab/bin
$ gem install mecab -v '0.996'
bash: gem: command not found 

$ gem install mecab
bash: gem: command not found
 
$ find PATH
bash: find: command not found
 
$ echo $PATH 
 /usr/local/mecab/bin

$ gem install
bash: gem: command not found

$ rails new Kanjo_sec
bash: rails: command not found

うーん、なにげなくパスを追加しようとして export PATH=としたのがすべての根幹。gem も rails も何もできなくなってしまった。問題は明らかにパスの設定を変にしてしまったからだ。

新しく cloud9 のプロジェクトを作ってみて確認したらあった。

$ echo $PATH
/home/ubuntu/.nvm/versions/node/v4.7.3/bin
:/usr/local/rvm/gems/ruby-2.3.0/bin
:/usr/local/rvm/gems/ruby-2.3.0@global/bin
:/usr/local/rvm/rubies/ruby-2.3.0/bin
:/mnt/shared/bin
:/home/ubuntu/workspace/node_modules/.bin
:/home/ubuntu/bin
:/usr/local/sbin
:/usr/local/bin
:/usr/sbin
:/usr/bin
:/sbin
:/bin
:/mnt/shared/sbin
:/opt/gitl
:/opt/go/bin
:/mnt/shared/c9/app.nw/bin
:/usr/local/rvm/bin

こんなにもあった。。。今度は消さずに追加だけする方法を探そう。 消さずに追加する方法はわからないが、復活させる方法はわかった。 これと同じことをかけばいいのだからこれをコピペしてくれ

$ export  PATH=/home/ubuntu/.nvm/versions/node/v4.7.3/bin:/usr/local/rvm/gems/ruby-2.3.0/bin:/usr/local/rvm/gems/ruby-2.3.0@global/bin:/usr/local/rvm/rubies/ruby-2.3.0/bin:/mnt/shared/bin:/home/ubuntu/workspace/node_modules/.bin:/home/ubuntu/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/mnt/shared/sbin:/opt/gitl:/opt/go/bin:/mnt/shared/c9/app.nw/bin:/usr/local/rvm/bin

そしたら gem も rails も動くようになったぞ!

$ echo $PATH
/home/ubuntu/.nvm/versions/node/v4.7.3/bin:/usr/local/rvm/gems/ruby-2.3.0/bin:/usr/local/rvm/gems/ruby-2.3.0@global/bin:/usr/local/rvm/rubies/ruby-2.3.0/bin:/mnt/shared/bin:/home/ubuntu/workspace/node_modules/.bin:/home/ubuntu/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/mnt/shared/sbin:/opt/gitl:/opt/go/bin:/mnt/shared/c9/app.nw/bin:/usr/local/rvm/bin

うまく追加されている。

 gem 
RubyGems is a sophisticated package manager for Ruby.  This is a
basic help message containing pointers to more information.

  Usage:
    gem -h/--help
    gem -v/--version
    gem command [arguments...] [options...]

  Examples:
    gem install rake
    gem list --local
    gem build package.gemspec
    gem help install

gem も使える。

nokogiri を使って Youtube の動画とサムネイル画像を拾ってきて。

Nokogiri というrails の gem を使うとインターネット上からテキストやデータや画像を拾ってくれるようになります。今回は youtube の動画を拾ってきて、説明欄や

まずはnogogiri という gem をインストールしましょう。 gem install nokogiri

その後以下のコードを入力して起動してください。

require 'nokogiri'
require 'open-uri'
require 'uri'

urls = []
search_term = URI.encode("アカギ")
url = "https://www.youtube.com/results?search_query=#{search_term}"


doc = Nokogiri::HTML(open(url))
elements = doc.xpath("//h3['yt-lockup-title']/a")
elements.each do |a|
  code = a.attributes['href'].value
  urls << "https://www.youtube.com" + code if code.include?("watch")
end



urls.each do |url|
  puts url
  doc = Nokogiri::HTML(open(url), nil, "UTF-8")
  title = doc.xpath("//h1[@class = 'watch-title-container']/span").text.gsub(/\n/, '')

  desc = doc.xpath("//p[@id = 'eow-description']").text
  puts title
  puts desc
end

すると

 $ ruby test_youtube.rb
https://www.youtube.com/watch?v=mpCKle9hhbk&list=PLTP-72gM0GB0uvu1zNut6kaunzPXfpExk
    Kaiji episode 1  

https://www.youtube.com/watch?v=y5pyPBTdNXQ
    カイジ Ultimate Survivor ①  
カイジ Ultimate Survivor ①https://goo.gl/KDMdJ6
https://www.youtube.com/watch?v=2jH2BNIeKEE
    Kaiji   #2 sub español  

https://www.youtube.com/watch?v=c0liPtuQbp0
    Kaiji 2 Life Reversal Game - Dublado  
Kaiji 2 Life Reversal Game - Dublado  em Português
https://www.youtube.com/watch?v=kZ53jVdhXE8
    CR弾球黙示録カイジ沼3 パチンコ新台実践『初打ち!』圧倒的怪物への挑戦!20173月新台【たぬパチ!】  

こんなかんじに URL とタイトルと説明欄をひろってくるようになります。

search_term = URI.encode("カイジ")

これについて、youtube では検索するとき日本語そのままで検索するのではなく、いったん文字をエンコードしてから検索しています。検索結果では日本語表記されてますが、再生したときはこうなってます。だから文字をエンコードするためにこれが必要です。

f:id:mooooooooooriiiiii:20170323010213p:plain

elements = doc.xpath("//h3['yt-lockup-title']/a")

これについて、h3['yt-lockup-title'] というのはクラス名が yt-lockup-title である h3 を指しています。本では h3[@class='yt-lockup-title'] と書かれているはずです。

たまになのですが、 @class= という書き方では認識されないときがあります。ちゃんと xpath を書いているのに nokogiri で表示されないというときは @class= や @id= の表記をうたがってください。

また、この xpath はユーチューブのここを指しています。

f:id:mooooooooooriiiiii:20170323011019p:plain

つぎにcode = a.attributes['href'].valueこのコードについて詳しく見ていきましょう。

これについて知るためには Nokogiri がどのようなデータになっているのか知る必要があります。最初のコードをちょこっと変えてみて、こんなコードを作ります。

require 'nokogiri'
require 'open-uri'
require 'uri'

urls = []
search_term = URI.encode("アカギ")
url = "https://www.youtube.com/results?search_query=#{search_term}"


doc = Nokogiri::HTML(open(url))
elements = doc.xpath("//h3['yt-lockup-title']/a")
elements.each do |a|
  
  p a
  code = a.attributes['href'].value
  puts "------------------------"
  p code
  puts "------------------------"
  urls << "https://www.youtube.com" + code if code.include?("watch")
end

p を使うことで、each で取り出した変数 a の内部構造をみることができます。puts "-------" で区切り線をつけて見やすくしてます。最終的にでてきたコードの一部をとりだしてみるとこういうコードになります。

#<Nokogiri::XML::Element:0xe9a3cc name="a" attributes=
  [  #<Nokogiri::XML::Attr:0xe9a304 name="href" value="/watch?v=gnx3W8Q3nuE">,
     #<Nokogiri::XML::Attr:0xe9a2f0 name="class" value="yt-uix-tile-link yt-ui-ellipsis yt-ui-ellipsis-2 yt-uix-sessionlink      spf-link ">,
     #<Nokogiri::XML::Attr:0xe9a2dc name="data-sessionlink" value="itct=CEIQ3DAYAiITCMX05rjC6tICFdQWWAod3d8I_yj0JFIJ44Ki44Kr44Ku">, 
     #<Nokogiri::XML::Attr:0xe9a2c8 name="title" value="ã\u0082¢ã\u0082«ã\u0082®ã\u0080\u0080第9話ã\u0080\u0080天æ\u0089\u008Dã\u0081®ç\u009C\u009Fè´\u008B">, 
     #<Nokogiri::XML::Attr:0xe9a2a0 name="aria-describedby" value="description-id-531595">,
     #<Nokogiri::XML::Attr:0xe9a278 name="rel" value="spf-prefetch">, 
     #<Nokogiri::XML::Attr:0xe9a23c name="dir" value="ltr">] children=[#<Nokogiri::XML::Text:0x10d30e4 "ã\u0082¢ã\u0082«ã\u0082®ã\u0080\u0080第9話ã\u0080\u0080天æ\u0089\u008Dã\u0081®ç\u009C\u009Fè´\u008B">
  ]>
----------------------
"/watch?v=gnx3W8Q3nuE"
------------------------

コードをみればなんとなくわかるように、code = a.attributes['href'].value の attributes[‘href’] とは Nokogiri の attributes = “” のなかの name=“href” を指しています。value はまさにその中に value=“ ” の中にある文字をさしています。 どうように a.attributes['class'].class もできます。

doc = Nokogiri::HTML(open(url), nil, "UTF-8")

これはurl を開くためのコードです。少しうえのコードで作成した URL を今度は開いてます。ということはこの時点で検索結果一覧ページではなく、個々の動画のページに移動していることになります。

title = doc.xpath("//h1[@class = 'watch-title-container']/span").text.gsub(/\n/, '')

これはタイトルを表してます。画像で言えばここ。

f:id:mooooooooooriiiiii:20170323014217p:plain

//h1[@class= 'watch-headline-title'] とはどこか奥深くの watch-headline-title というクラス名をもった h1 を意味します。 // を使うと位置を厳密に指定する必要がなくて便利です。その分重複してしまう可能性があり、このようにクラス名を指定しておくのは重要です。

.text はタグで囲まれた文字を返します。この場合 にかこまれた文字です。

.gsub(/(正規表現)/, "(置き換える文字)") について。これはまあまあ使うめそっどです。このばあい \n(改行)を``に置き換えてる、つまり削除してます。 便利なのでおぼえておきましょう。

こんなもんですね。

Ruby によるクローラー開発技法』のままやるとエラーがでます。 どうやらYoutube のURL を http ではなく https ではじめる必要があります。だからそのまま打ち込むと

 $ ruby test_youtube.rb
http://www.youtube.com/watch?v=DFJh9vFixHs&list=PLyJjW5KES8Q0waiG5eF7RuFIqaA-SIxKN
/usr/local/rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/open-uri.rb:225:in `open_loop': redirection forbidden: http://www.youtube.com/watch?v=DFJh9vFixHs&list=PLyJjW5KES8Q0waiG5eF7RuFIqaA-SIxKN -> https://www.youtube.com/watch?v=DFJh9vFixHs&list=PLyJjW5KES8Q0waiG5eF7RuFIqaA-SIxKN (RuntimeError)
        from /usr/local/rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/open-uri.rb:151:in `open_uri'
        from /usr/local/rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/open-uri.rb:717:in `open'
        from /usr/local/rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/open-uri.rb:35:in `open'
        from test_youtube.rb:21:in `block in <main>'
        from test_youtube.rb:19:in `each'
        from test_youtube.rb:19:in `<main>'

こんなエラーがでて一件しか取得できません。注意。

ーーーーーーーーーーーーーーー 追記。

ここからはもう少しあそんでいきます。リンクを持ってくるだけではつまらないので、サムネイル画像を拾ってこうと思います。基本的にこのような流れでやっていきます。

①ターゲット(画像)のxpath を解析 ②取得したリンクを見て、都合のいいように変形 ③出力

まずは①の画像のxpath 解析から。

画像の xpath を観察してみると 1 ばんめから順に li の数字が変化していることに気付きます。

//li[2]/ol/li[1]/div/div/div[1]/a/div/span/img

//li[2]/ol/li[2]/div/div/div[1]/a/div/span/img

//li[2]/ol/li[3]/div/div/div[1]/a/div/span/img

//li[2]/ol/li[4]/div/div/div[1]/a/div/span/img

よって

//li[2]/ol/li/div/div/div[1]/a/div/span/img

この状態でのコードと結果を書いておきます。

require 'nokogiri'
require 'open-uri'
require 'uri'

urls = []
search_term = URI.encode("カイジ")
url = "https://www.youtube.com/results?search_query=#{search_term}"

cleaned_pics = []
doc = Nokogiri::HTML(open(url))
pics = doc.xpath("//li[2]/ol/li/div/div/div[1]/a/div/span/img").each{|pic| puts pic.attributes['src']}

end
:~/workspace $ ruby test_youtube.rb
https://i.ytimg.com/vi/mpCKle9hhbk/hqdefault.jpg?custom=true&w=246&h=138&stc=true&jpg444=true&jpgq=90&sp=68&sigh=04JeuJ4O29aIHreWcinFA2-wisI
https://i.ytimg.com/vi/y5pyPBTdNXQ/hqdefault.jpg?custom=true&w=246&h=138&stc=true&jpg444=true&jpgq=90&sp=68&sigh=_1YnIM0G4hCOb4NMEm5woZaeP-E
https://i.ytimg.com/vi/2jH2BNIeKEE/hqdefault.jpg?custom=true&w=246&h=138&stc=true&jpg444=true&jpgq=90&sp=68&sigh=xo_SW7brtUDDCF-Q6HJ2TCVJlpI
https://i.ytimg.com/vi/c0liPtuQbp0/hqdefault.jpg?custom=true&w=246&h=138&stc=true&jpg444=true&jpgq=90&sp=68&sigh=P-4H62loznfh9iwthKjkDCj7XYw
https://i.ytimg.com/vi/Kp9Ed2LCSio/hqdefault.jpg?custom=true&w=246&h=138&stc=true&jpg444=true&jpgq=90&sp=68&sigh=jNEVG6isk5Lmt2XLmEzalEHrdh8
https://i.ytimg.com/vi/kZ53jVdhXE8/hqdefault.jpg?custom=true&w=246&h=138&stc=true&jpg444=true&jpgq=90&sp=68&sigh=8BcivPyS899L2BmPQoPXfrPDbqU
/yts/img/pixel-vfl3z5WfW.gif
/yts/img/pixel-vfl3z5WfW.gif
/yts/img/pixel-vfl3z5WfW.gif
/yts/img/pixel-vfl3z5WfW.gif
/yts/img/pixel-vfl3z5WfW.gif
/yts/img/pixel-vfl3z5WfW.gif

ここで問題は gif ファイルが入っているのと、 jpg 画像のサイズ指定があり邪魔だということです。 ②ではgif を解き除き、jpg のリンクの後ろのサイズ指定などのオプションを取り除きましょう。

② 取得したリンクを見て、都合のいいように変形

まず gif から取り除きます。ほしい jpg といらない gif 画像の違いは jpg という文字があるか否かです。 ということで include?('jpg') を使って jpg という文字があるものだけを取り出しましょう。 さらに pic.attributes['src'] はこの時点では #<Nokogiri::XML::Attr….> という形なので文字列に直しておくために .to_s を使って文字に直しておきます。すると、

require 'nokogiri'
require 'open-uri'
require 'uri'
urls = []
search_term = URI.encode("カイジ")
url = "https://www.youtube.com/results?search_query=#{search_term}"

cleaned_pics = []
doc = Nokogiri::HTML(open(url))
pics = doc.xpath("//li[2]/ol/li/div/div/div[1]/a/div/span/img")
            .each{|pic| puts pic.attributes['src'] if pic.attributes['src'].to_s.include?('jpg')}

となり、出力結果は

$ ruby test_youtube.rb
https://i.ytimg.com/vi/mpCKle9hhbk/hqdefault.jpg?custom=true&w=246&h=138&stc=true&jpg444=true&jpgq=90&sp=68&sigh=04JeuJ4O29aIHreWcinFA2-wisI

https://i.ytimg.com/vi/y5pyPBTdNXQ/hqdefault.jpg?custom=true&w=246&h=138&stc=true&jpg444=true&jpgq=90&sp=68&sigh=_1YnIM0G4hCOb4NMEm5woZaeP-E

https://i.ytimg.com/vi/2jH2BNIeKEE/hqdefault.jpg?custom=true&w=246&h=138&stc=true&jpg444=true&jpgq=90&sp=68&sigh=xo_SW7brtUDDCF-Q6HJ2TCVJlpI

こんな感じになってます。cleaned_pics という変数にいれておきます。よってこうなります。

pics = doc.xpath("//li[2]/ol/li/div/div/div[1]/a/div/span/img")
        .each{|pic| cleaned_pics << pic.attributes['src'] if pic.attributes['src'].to_s.include?('jpg')}

でも後ろのオプションがじゃまですねえ。これを取り除いていきます。 どの部分がオプションなのかはじっくり見続けるしかないです。よくみると .jpg?を境にオプションであることがわかります。

https://i.ytimg.com/vi/mpCKle9hhbk/hqdefault.jpg?custom=true&w=246&h=138&stc=true&jpg444=true&jpgq=90&sp=68&
sigh=04JeuJ4O29aIHreWcinFA2-wisI
は
https://i.ytimg.com/vi/mpCKle9hhbk/hqdefault.jpg
これと
?custom=true&w=246&h=138&stc=true&jpg444=true&jpgq=90&sp=68&sigh=04JeuJ4O29aIHreWcinFA2-wisI
これにわかれてる

扱うのはリンクだからある程度形式に従って成立していてかつ、それを取り出したいから正規表現を使うのが吉。 よってこんな正規表現を書きます。

/(.+\.jpg)\?.+/

これで jpg を境に左右に分けられ、()に囲まれた左側のみキャプチャをすることができます。 キャプチャしたもののみを取り出す場合は $1 を打てばいいですから結果的には

cleaned_pics.each do |pic|
  pic.to_s =~ /(.+\.jpg)\?.+/
  puts $1
end

となります。これらを統合すると

require 'nokogiri'
require 'open-uri'
require 'uri'

urls = []
search_term = URI.encode("カイジ")
url = "https://www.youtube.com/results?search_query=#{search_term}"

cleaned_pics = []
doc = Nokogiri::HTML(open(url))
pics = doc.xpath("//li[2]/ol/li/div/div/div[1]/a/div/span/img")
        .each{|pic| cleaned_pics << pic.attributes['src'] if pic.attributes['src'].to_s.include?('jpg')}

cleaned_pics.each do |pic|
  pic.to_s =~ /(.+\.jpg)\?.+/
  puts $1
end
=end

こうなりました。 よし、お疲れさまです。これでこの記事は終わりです。頑張ってね。