とよぶ

歌いながらコード書いてます

MechanizeとNokogiriでらくらくWebスクレイピング

知り合いの頼みで、某オレンジのSNSサイトに自動で写真付きコメントを投稿するスクリプトを書いていてみたので、ハマリポイントなどをメモっておこうと思う。
え?なんの言語でやったかって?
そんなのRubyに決まっとるwww

使用するGem

jimweirich/rake · GitHub

mechanizeは簡単なWebブラウジングを自動化できるやつで、nokogiriはxmlなどを簡単にパースできるお馴染みスクレイピングツール。
あとはちょっとしたIDとかの管理をDB管理にしたかったのでActiveRecordとRakeをそのまま使ってsqlite3で管理した。

作ったものの仕様

某SNSにログイン

投稿したいページに遷移

写真付きでコメントを投稿

ハマリポイント

なかなかログイン出来ない

pとかで出力してもあまり頼りになる情報が出てないと思っていたら、単にリダイレクトされているだけだった。
デフォルトではmeta refreshなどのリダイレクトに追随しないようだ。
そこでMechanizeの初期化時に以下の様な設定を入れる

def initialize
      @mecha = Mechanize.new { |agent|
        agent.user_agent_alias = 'Mac Safari'
        agent.follow_meta_refresh = true
        agent.default_encoding = 'EUC-JP'
        agent.force_default_encoding = true
      }
end

follow_meta_refreshをtrueにしてやる。
他の設定は必要なときに追加していった。
エンコーディングがEUC-JPでびっくりした。

ブラウザではコメントフォームが出ているのにスクリプトで見たらコメントフォームがない!!!

単にブラウザで見ているユーザーとスクレイピングに使っているユーザーが違っただけだったw

写真が投稿できない

今のサイトはほとんどがjavascript使っていろいろやっている。
特にファイルアップロードが必要な時って、ファイルを複数アップロードできるように、フォームはjavascriptを使って動的に
挿入している場合がある。
この場合mechanizeでファイルアップロードフィールドを取得ようとしても無意味!ただ虚しくそこには空っぽのフィールドがあるのみ!!
さて!これでただあるものをスクレイピングして送信するだけではダメだと分かった。
ここでNokogiriさんの出番。
マリー・アントワネット「javascriptでしかファイル用のフィールドが出ないんなら、どうして自分で作らないのかしら?」
というわけで、ファイルアップロードのフィールドを作る。
mechanize/form.rb at master · sparklemotion/mechanize · GitHub
ここを見ればわかるけど、Formクラスって

attr_reader :fields, :buttons, :file_uploads, :radiobuttons, :checkboxes

ってなってて、ファイルアップロード用のフィールドがあるので、要素を自作してこいつに突っ込んでやればいい。
で、できたソースがこれ。ちょっと汚いので誰か美しく書く方法を知っていたら教えて下さい。っていうか自分でリファクタリングしろw

doc = Nokogiri::XML::Document.parse '<input>'
      input_tag = Nokogiri::XML::Node.new 'input', doc
      input_tag['type'] = 'file'
      input_tag['name'] = 'photo1'
      input_tag['id'] = 'photo1'
      input_tag['value'] = file
      upload = Mechanize::Form::FileUpload.new input_tag, file
      form.file_uploads << upload

inputタグにちょっとづつ要素を入れているのをどうにかしたい。このへんはまだ理解できてないなあ。
ちなみにfileっていうところはファイルパス。imgディレクトリの中のhoge.jpegだとすると'./img/hoge.jpeg'的な。
ちなみに、このようにファイル名だけ指定する形式だと、.jpegみたいに特定の拡張子名でないとアップできないっぽい(ここのソースは読んでいない)。
このへんに書いてあったけど、mime_typeを指定すればいいっぽい(試してない)。

感想

ちなみに一番ハマったのはコメントフォームが出ないやつですwww アホスwww
あんま関係ないけど、今までRailsでしかActiveRecordとかRakeとか使ったことなかったけど、今回スクリプトで単体で使ってみてから、結構理解が深まった感がある。yamlとかを設定ファイルとするのも結構楽だったし、今までのRubyのコードの中だと割とよく書けたかな。
ただ、もうちょっとちゃんと設計して書くと綺麗になりそうなのと、クラス設計とかがごちゃっとしてたりするので、メタプロ本とかパーフェクトなやつとかちゃんと読みたいな。


TODO

whenever入れてcron管理

参考

turks/mixi at master · takasing/turks · GitHub
(スパム投稿とかしているわけではないので許してくださいw)