それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

MechanizeでChromeのCookieを扱って面倒なログインを飛ばす

ログイン処理を書くのが趣味だけど、どうしてもログインを自動化しにくいサイトが有る。

たとえばYahooやニコニコ動画ニコニコ動画はブラウザログインすると別ログインがキックアウトされる多重ログイン禁止。Yahoo JapanはログインフォームにJS検知が埋まっていて画像認証になる。回避策考えるのが面倒。msn(live.com)はすげー面倒だし。

ログインフォーム処理を高速回避

ログインフォームの作成処理を高速回避して、とりあえず目的だけ達したいことは多い。
そういう時は、ブラウザのCookieを取り出せば楽ちん。

ChromeCookieを使うMechanizeパッチ

#coding: utf-8
require 'mechanize'

class Mechanize
  def load_chrome_cookie(cookie_domain, cookie_path="/")
    case RUBY_PLATFORM
      when /darwin/
        path_to_chrome_cookies = Object::File.expand_path("~/Library/Application Support/Google/Chrome/Default/Cookies")
      when /win/
        path_to_chrome_cookies = Object::File.expand_path( "AppData/Local/Google/Chrome/User Data/Cookies" ,ENV["USERPROFILE"])
      when /linux/
        path_to_chrome_cookies = Object::File.expand_path("~/.config/google-chrome/Default/Cookies")
    end

    raise "Chromeの個人データフォルダが見つからない" unless Object::File.exists?(path_to_chrome_cookies)
    # www.yahoo.co.jp のようなドメインを指定した場合は .www.yahoo.co.jp に変換
    cookie_domain = ".#{cookie_domain}" unless cookie_domain =~ /^\./
    # puts cookie_domain

    db = nil
    begin 
      require 'sqlite3'
      db = SQLite3::Database.new(path_to_chrome_cookies)
      db.results_as_hash = true
      mandatory_cookie = {}
      #todo secure 処理
      sql = "select * from cookies where  host_key like \"#{cookie_domain}\"  and path = \"#{cookie_path}\" "
      #puts sql
      db.execute(sql){|r| 
        #p r["value"]
        r["creation_utc"] = Time.at( Time.utc(1601,1,1,0,0,0,0).to_i , r["creation_utc"] )
        r["expires_utc"] = Time.at( Time.utc(1601,1,1,0,0,0,0).to_i , r["expires_utc"] )
        mandatory_cookie[r["name"]]=r["value"]
      }
      mandatory_cookie = mandatory_cookie.map{|k,v| "#{k}=#{v};" }.join(" ")
      #pp mandatory_cookie
    ensure
      db.close unless db.nil?
    end
    #cookie_domain = cookie_domain.gsub(/^\./, "")  if cookie_domain =~ /^\./

    mandatory_cookie.split(" ").each{|e|
        e = e.gsub(/;/, "").split("=", 2)
        cookie_params = {:name=>e[0],:value=> e[1], :domain => cookie_domain, :expires => Time.now + 60*60*24*30,:created_at=> Time.now - 60*60*24*30, :path => cookie_path }
        #p cookie_params
         cookie = Mechanize::Cookie.new(cookie_params)
         # p cookie
        self.cookie_jar.add(cookie)
    }
    self.cookies.map{|e| e.cookie_value + ";"}.join(" ")
  end
end

利用サンプル

m = Mechanize.new
m.user_agent_alias = 'Windows IE 7' 
m.load_chrome_cookie("yahoo.co.jp")
m.get "http://www.yahoo.co.jp/"
puts m.page.body

ログインフォームはシンプルなのがイイな。

Yahooの画像認証についてはスクリプトから回避できるけど、MSNに至っては考えるのが面倒。
どうやるのかぱっと見想像がつかない。だから諦めて目的だけ達したい。

でもどうしてもログインフォームを何とかしたいことが多いので、シンプルなのがいいな。
Javascriptを中途半端に「使う」サイトはマジ勘弁。。。

PhantomJSでブラウザログイン

PhantomJSつかってブラウザをオートパイロットシステム作ってもいいけど、デバッグが面倒なのでCookie生成程度に留めておいたほうがいいや。


2014-11-17 若干修正

ruby 2.1 系でTime.atがうごかなくなってたので修正

まったく、ruby のバージョンアップでコアの組み込みライブラリAPIの動作変えないでほしいわ。。。

2014-11-17 追記

ChromeCookieは、value からencrypted_value に保存されるようになってて、sqlite3を除いただけでは取れなくなったので、chromeapplescript で起動して、該当サイトに行って、script をインジェクションして、cookieを読み出さなくちゃいけない模様。もう面倒臭い・・・