mixiボイスにRubyでアクセスしていじってみた
先日、mixiエコーがmixiボイスに名前を変えて正式リリースされました。(アドレスはrecent_echo.plのようにechoのままですが)
しかし、APIの提供も今のところなくRSSの配信もないので、いちいち見に行くのも面倒だったので、オレオレUtilをRubyで作ってみました。
自分用に簡単に作ったものなので、もし使用される場合はお好きに改造してください。(特にエラー処理まわり)
- 機能
- ボイスに投稿(返信機能)
- マイミクのボイス・自分のボイス・自分あての返信を取得
- メッセージの削除
- ボイスの取得はページ指定と指定ページからの全件取得が可能です
- ボイスに投稿する時に、返信相手のIDと返信したいメッセージのtimeを指定すると返信になります(Webの方ではどちらかのパラメータがかけていても返信が成功するようですが、リンクに初期値が挿入されるため返信先を閲覧する事が出来ません)
今は、RSSを吐き出す物を作ってCronでまわして定期的にRSSを取得しています。あまり頻繁にアクセスしないようにしたほうがいいかと思います。
このようなRSSが吐き出されます。(例では自分のボイスを取得したものです)
<?xml version="1.0" encoding="UTF-8"?> <rss version="2.0" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"> <channel> <title>mixiボイスRSS</title> <link>https://mixi.jp/</link> <description>mixiボイスのRSSだよ!</description> <image> <url>http://img.mixi.jp/img/basic/common/logo_mixi001.gif</url> <title>mixi</title> <link>https://mixi.jp/</link> </image> <item> <title>Nick: ゆたのボイス</title> <link>http://mixi.jp/view_echo.pl?id=2737220&post_time=20090917221329</link> <description>とりあえず説明を読んでみよう</description> <pubDate>Thu, 17 Sep 2009 22:13:29 +0900</pubDate> </item> <item> <title>Nick: ゆたのボイス</title> <link>http://mixi.jp/view_echo.pl?id=2737220&post_time=20090917221011</link> <description>これがボイスという物かどきどきする</description> <pubDate>Thu, 17 Sep 2009 22:10:11 +0900</pubDate> </item> </channel> </rss>
こんな感じです。
使い方などはソースを見てもらえればわかると思います。
mixiボイスのページの構造が変わったら動かなくなるので適時修正をお願いします。
オレオレmixiボイスUtil
# -*- coding: utf-8 -*- require "jcode" require "uri" require "rubygems" require "mechanize" $KCODE = "U" class Mixi_Voice LOGIN_URL = "https://mixi.jp/" BASE_URL = "http://mixi.jp/" PUBLIC_VOICE_PATH = "recent_echo.pl" USER_VOICE_LIST_PATH = "list_echo.pl" RES_VOICE_PATH = "res_echo.pl" DELETE_VOICE_PATH = "delete_echo.pl" def initialize(id = nil, pass = nil) raise "Require id AND Password" if id.nil? || pass.nil? $agent = WWW::Mechanize.new $agent.max_history = 1 $agent.user_agent_alias = "Windows IE 7" top_page = $agent.get(LOGIN_URL) login_form = top_page.forms[0] login_form["email"] = id login_form["password"] = pass login = $agent.submit(login_form) raise "Login Error" unless login.title.nil? end def get_voice_list(type = :public, option = {}) voice_info = [] path = "" page = option[:page] || 1 get_all = option[:get_all] || false case type when :public path = PUBLIC_VOICE_PATH when :my path = USER_VOICE_LIST_PATH when :res path = RES_VOICE_PATH else raise "Voice Type Error (:public, :my or :res)" end path += "?page" + page.to_s if page > 1 voices_page = $agent.get(BASE_URL + path) loop do voice_table = (voices_page/"//div[@class=\"archiveList\"]/table/tr") voice_table.each do |voice| user_info = (voice/"td[@class=\"thumb\"]/a")[0] break if user_info.nil? user_info["href"] =~ /list_echo.pl\?id=(\d+)$/ user = $1 info = (voice/"td[@class=\"thumb\"]/a/img")[0] thumb = info["src"] nick = info["alt"] comment_info = (voice/"td[@class=\"comment\"]")[0] comment = (comment_info/"div[@class=\"echo_body\"]").inner_text time = (comment_info/"div[@class=\"echo_post_time\"]").inner_text link = "http://mixi.jp/view_echo.pl?id=#{user}&post_time=#{time}" voice_info << {:user=>user, :thumb=>thumb, :nick=>nick, :comment=> comment, :link=> link, :time=>time} end break unless get_all next_page = voices_page.link_with(:text => "次を表示") break if next_page.nil? voices_page = next_page.click end voice_info end def post_message(message, parent_member_id = nil, parent_post_time = nil) return if message.nil? raise "Over 150 Words" if message.jsize > 150 #1.9系ならlength使えばおk voices_page = $agent.get(BASE_URL + PUBLIC_VOICE_PATH) if((!parent_member_id.nil? && parent_post_time.nil?) || (parent_member_id.nil? && !parent_post_time.nil?)) raise "Require parent_member_id AND parent_post_id" elsif (!parent_member_id.nil? && !parent_post_time.nil?) raise "Invalid Number parent_member_id OR parent_post_time" unless parent_member_id.to_s =~ /^[\d]+$/ && parent_post_time.to_s =~ /^[\d]+$/ end post_voice = voices_page.forms[1] post_voice["body"] = message post_voice["parent_member_id"] = parent_member_id unless parent_member_id.nil? post_voice["parent_post_time"] = parent_post_time unless parent_post_time.nil? result = $agent.submit(post_voice) raise "Post Error" unless (result/"//div[@id=\"error\"]")[0].nil? end def delete_voice(post_time = nil) raise "Require Post Date" if post_time.nil? raise "Invalid Number post_time" unless post_time.to_s =~ /^[\d]+$/ voices_page = $agent.get(BASE_URL + PUBLIC_VOICE_PATH) post_key = post_voice = voices_page.forms[1]["post_key"] query = "?post_time=#{post_time}&post_key=#{post_key}&redirect=recent_echo" $agent.get(BASE_URL + DELETE_VOICE_PATH + query) end end
RSSを吐くもの
# -*- coding: utf-8 -*- require "mixi_voice" require "rubygems" require "rss" $KCODE = "U" begin mixi_voice = Mixi_Voice.new("ID", "PASS") all_voice = mixi_voice.get_voice_list(:my, {:page=>1, :get_all=>true}) rss = RSS::Maker.make("2.0") do |make| make.channel.title = "mixiボイスRSS" make.channel.description = "mixiボイスのRSSだよ!" make.channel.link = "https://mixi.jp/" make.image.title = "mixi" make.image.url = "http://img.mixi.jp/img/basic/common/logo_mixi001.gif" make.items.do_sort = true all_voice.each do |voice| make.items.new_item do |item| voice[:time].to_s =~ /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/ time = Time.parse("#{$1}/#{$2}/#{$3} #{$4}:#{$5}:#{$6}") item.link = voice[:link] item.title = "Nick: " + voice[:nick] + "のボイス" item.date = time item.description = voice[:comment] end end end File.open("my_voice.xml", "w") do |f| f.write(rss) end rescue Exception => e puts "Error: " + e end
- get_voice_listで使用するtype
- :my 自分のボイス
- :public マイミクのボイス
- :res 自分への返信
メッセージを取得すると以下の様なHashの配列で返ってきます。
{:nick=>"ゆた", :comment=>"とりあえず説明を読んでみよう", :time=>"20090917221329", :thumb=>"http://profile.img.mixi.jp/photo/member/72/20/2737220_1247381845m.jpg", :user=>"2737220"}
- nick ニックネーム
- comment コメント
- time 投稿時間(削除や返信に使用します)
- thumb 投稿者のサムネ
- user ユーザID
post_messageメソッドの「parent_member_id」はuserを、「parent_post_time」はtimeを使用します。(それぞれ返信したいメッセージのものです)
delete_voiceメソッドの「post_time」は自分の刑したいメッセージのtimeを使用します。
早くAPIを提供して欲しいです。