mixi is the biggest social network site in Japan. There are more users than ten million. Many people have friends networks in mixi, and mixi announced about respond OpenID and OpenSocial API, but they are very slow!! I heard that mixi is going to release OpenID API about Sep. It's too late compared to Facebook.
The Friend of a Friend(FOAF) is creating a Web of machine-readable pages describing people, the links between them and the things they create and do. I have created program to extract the friend links from mixi.
Usage:
% svn co http://svn.raku.to/throwaway/mixi2foaf.rb
% ruby mixi2foaf.rb email password > foaf.rdf
NOTE: Customize your profile
You need to customize profile about yourself, for details see mixi2foaf.rb.
# FIXME: Edit your profile
mixi.me = FOAF::Person.new({
:rdf_id => 'rakuto',
:name => 'Rakuto Furutani',
:nick => 'rakuto',
:openid => '=rakuto',
:mbox_sha1sum => 'rakuto@nospam.gmail.com'.sub('nospam.', ''),
:jabberID => 'rakuto@nospam.gmail.com'.sub('nospam.', ''),
:msnChatID => 'Strawberry_au_rait@hotmail.com'
})
Example:
% ruby mixi2foaf.rb rakuto@gmail.com ********* > foaf.rdf
[Traverse] http://mixi.jp/show_friend.pl?id=4588051
[Traverse] http://mixi.jp/show_friend.pl?id=3805395
...
%
foaf.rdf
<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF xmlns:wot="http://xmlns.com/wot/0.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:lang="ja" xml:lang="ja" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:dcterms="http://purl.org/dc/terms/" xmlns="http://www.w3.org/foaf/0.1/">
<foaf:Person rdf:ID="rakuto">
<foaf:nick>rakuto</foaf:nick>
<foaf:jabberID>rakuto@gmail.com</foaf:jabberID>
<foaf:mbox_sha1sum>bf8892066afd2ea3eef4f3c1fd834eed96ba1c39</foaf:mbox_sha1sum>
<foaf:openid>=rakuto</foaf:openid>
<foaf:msnChatID>Strawberry_au_rait@hotmail.com</foaf:msnChatID>
<foaf:rdf_id>rakuto</foaf:rdf_id>
</foaf:Person>
<knows>
<Person>
<name>ゆりさん</name>
<img>http://member.img.mixi.jp/photo/member/80/51/4588051_99567334.jpg</img>
<nick>ゆりさん</nick>
<topic_interest>映画鑑賞, 音楽鑑賞, 料理, ショッピング, ファッション, 読書, インターネット, ペット</topic_interest>
<based_near>京都府京都市</based_near>
</Person>
</knows>
<knows>
<Person>
<name>うじひささん</name>
<img>http://member.img.mixi.jp/photo/member/53/95/3805395_1723386446.jpg</img>
<nick>うじひささん</nick>
<topic_interest>アート, 語学, ペット</topic_interest>
</Person>
</knows>
<knows>
<Person>
<name>さっちぃーさん</name>
<img>http://member.img.mixi.jp/photo/member/40/38/3064038_2463714862.jpg</img>
<nick>さっちぃーさん</nick>
<topic_interest>スポーツ, スポーツ観戦, お酒, ファッション, アウトドア, ドライブ, 旅行, 読書, ゲーム, インターネット</topic_interest>
<based_near>京都府京都市</based_near>
</Person>
</knows>
<knows>
<Person>
<name>genkiさん</name>
<img>http://member.img.mixi.jp/photo/member/5/69/2560569_1803584202.jpg</img>
<nick>genkiさん</nick>
<topic_interest>映画鑑賞, 読書, インターネット</topic_interest>
<based_near>東京都世田谷区</based_near>
</Person>
</knows>
<knows>
<Person>
<name>いっぺいさん</name>
<img>http://member.img.mixi.jp/photo/member/65/15/2276515_15823768.jpg</img>
<nick>いっぺいさん</nick>
<topic_interest>映画鑑賞, スポーツ観戦, アウトドア, ドライブ, インターネット</topic_interest>
<based_near>滋賀県犬上郡</based_near>
</Person>
</knows>
<knows>
<Person>
<name>まちゃきさん</name>
<img>http://member.img.mixi.jp/photo/member/12/57/2231257_4177973050.jpg</img>
<nick>まちゃきさん</nick>
<topic_interest>映画鑑賞, スポーツ, スポーツ観戦, 音楽鑑賞, お酒, マンガ, ゲーム</topic_interest>
<based_near>兵庫県姫路市</based_near>
</Person>
</knows>
<knows>
<Person>
<name>びっくさん</name>
<img>http://member.img.mixi.jp/photo/member/74/81/2227481_2218119710.jpg</img>
<nick>びっくさん</nick>
<topic_interest>映画鑑賞, スポーツ, スポーツ観戦, 料理, アウトドア, ドライブ, 旅行, テレビ, ペット, 美容・ダイエット</topic_interest>
<based_near>東京都江戸川区</based_near>
</Person>
</knows>
<knows>
<Person>
<name>ふっちさん</name>
<img>http://member.img.mixi.jp/photo/member/12/13/2221213_1175337526.jpg</img>
<nick>ふっちさん</nick>
<topic_interest>音楽鑑賞, ファッション, テレビ</topic_interest>
</Person>
</knows>
<knows>
<Person>
<name>たねさん</name>
<img>http://member.img.mixi.jp/photo/member/27/88/2112788_3718693077.jpg</img>
<nick>たねさん</nick>
<topic_interest>映画鑑賞, スポーツ, スポーツ観戦, 音楽鑑賞, ドライブ</topic_interest>
<based_near>京都府京都市</based_near>
</Person>
</knows>
<knows>
<Person>
<name>きりさん</name>
<img>http://member.img.mixi.jp/photo/member/54/23/2025423_3963467882.jpg</img>
<nick>きりさん</nick>
<topic_interest>スポーツ, スポーツ観戦, 音楽鑑賞, グルメ</topic_interest>
<based_near>京都府京都市</based_near>
</Person>
</knows>
<knows>
<Person>
<name>ひでさん</name>
<img>http://member.img.mixi.jp/photo/member/17/46/2001746_3424328848.jpg</img>
<nick>ひでさん</nick>
<topic_interest>スポーツ, スポーツ観戦, 音楽鑑賞, 料理, グルメ, ショッピング, アウトドア, ドライブ, 旅行, インターネット</topic_interest>
<based_near>京都府京都市</based_near>
</Person>
</knows>
<knows>
<Person>
<name>さとしぃさん</name>
<img>http://member.img.mixi.jp/photo/member/5/38/1410538_2487809269.jpg</img>
<nick>さとしぃさん</nick>
<topic_interest>映画鑑賞, スポーツ, 音楽鑑賞, ショッピング, 語学, 読書, マンガ, インターネット, ギャンブル</topic_interest>
<based_near>滋賀県</based_near>
</Person>
</knows>
<knows>
<Person>
<name>なお☆゜+.さん</name>
<img>http://member.img.mixi.jp/photo/member/96/1/1339601_3143320574.jpg</img>
<nick>なお☆゜+.さん</nick>
<topic_interest>映画鑑賞, 音楽鑑賞, グルメ, お酒, ショッピング, ファッション, ドライブ, 旅行, ペット</topic_interest>
<based_near>京都府京都市</based_near>
</Person>
</knows>
<knows>
<Person>
<name>あィ ? ゆゥ 様さん</name>
<img>http://member.img.mixi.jp/photo/member/37/71/883771_3362183383.jpg</img>
<nick>あィ ? ゆゥ 様さん</nick>
<topic_interest>スポーツ, グルメ, お酒, 美容・ダイエット</topic_interest>
<based_near>京都府京都市</based_near>
</Person>
</knows>
<knows>
<Person>
<name>ぷりんさん</name>
<img>http://img.mixi.jp/img/basic/common/noimage_member180.gif</img>
<nick>ぷりんさん</nick>
</Person>
</knows>
<knows>
<Person>
<name>cuzicさん</name>
<img>http://member.img.mixi.jp/photo/member/66/22/516622_1304637750.jpg</img>
<nick>cuzicさん</nick>
<topic_interest>語学, 読書, テレビ</topic_interest>
<based_near>大阪府大阪市</based_near>
</Person>
</knows>
<knows>
<Person>
<name>ナ オタケさん</name>
<img>http://member.img.mixi.jp/photo/member/43/66/344366_692701929.jpg</img>
<nick>ナ オタケさん</nick>
<topic_interest>スポーツ, 音楽鑑賞, アウトドア, アート, 読書, ゲーム, インターネット</topic_interest>
<based_near>長崎県佐世保市</based_near>
</Person>
</knows>
<knows>
<Person>
<name>ankopartyさん</name>
<img>http://member.img.mixi.jp/photo/member/29/2/292902_3069630518.jpg</img>
<nick>ankopartyさん</nick>
<topic_interest>音楽鑑賞, グルメ, ショッピング, ファッション, 旅行, インターネット, ペット</topic_interest>
<based_near>埼玉県</based_near>
</Person>
</knows>
<knows>
<Person>
<name>hirokoさん</name>
<img>http://member.img.mixi.jp/photo/member/73/65/47365_319217593.jpg</img>
<nick>hirokoさん</nick>
<topic_interest>スポーツ, スポーツ観戦, 音楽鑑賞, 料理, グルメ, ファッション, 旅行</topic_interest>
<based_near>滋賀県大津市</based_near>
</Person>
</knows>
<knows>
<Person>
<name>いさむさん</name>
<img>http://member.img.mixi.jp/photo/member/33/41/3341_118115164.jpg</img>
<nick>いさむさん</nick>
<topic_interest>映画鑑賞, 音楽鑑賞, グルメ, お酒, ショッピング, ファッション, ドライブ, 旅行, 読書, インターネット, ペット</topic_interest>
</Person>
</knows>
<knows>
<Person>
<name>@さん</name>
<img>http://member.img.mixi.jp/photo/member/32/37/3237_54519266.jpg</img>
<nick>@さん</nick>
<topic_interest>インターネット</topic_interest>
<based_near>滋賀県栗東市</based_near>
</Person>
</knows>
<knows>
<Person>
<name>あやさん</name>
<img>http://member.img.mixi.jp/photo/member/22/88/2288_1047374038.jpg</img>
<nick>あやさん</nick>
<topic_interest>映画鑑賞, スポーツ, 音楽鑑賞, 料理, グルメ, ショッピング, 読書</topic_interest>
<based_near>香川県東かがわ市</based_near>
</Person>
</knows>
<knows>
<Person>
<name>ひでとさん</name>
<img>http://member.img.mixi.jp/photo/member/7/44/744_785912264.jpg</img>
<nick>ひでとさん</nick>
<topic_interest>映画鑑賞, 音楽鑑賞, グルメ, お酒, ファッション, ドライブ, 旅行, 読書, インターネット</topic_interest>
<based_near>京都府京都市</based_near>
</Person>
</knows>
<knows>
<Person>
<name>ひでふみさん</name>
<img>http://member.img.mixi.jp/photo/member/5/2/502_1466901064.jpg</img>
<nick>ひでふみさん</nick>
<topic_interest>映画鑑賞, スポーツ, 音楽鑑賞, お酒, アート, 読書</topic_interest>
<based_near>群馬県桐生市</based_near>
</Person>
</knows>
<knows>
<Person>
<name>こばげんさん</name>
<img>http://member.img.mixi.jp/photo/member/4/74/474_3993761079.jpg</img>
<nick>こばげんさん</nick>
<topic_interest>音楽鑑賞, 読書, マンガ, インターネット</topic_interest>
</Person>
</knows>
<knows>
<Person>
<name>匡志さん</name>
<img>http://img.mixi.jp/img/basic/common/noimage_member180.gif</img>
<nick>匡志さん</nick>
<topic_interest>旅行, 読書, インターネット</topic_interest>
<based_near>大阪府富田林市</based_near>
</Person>
</knows>
<knows>
<Person>
<name>ゆうきさん</name>
<img>http://member.img.mixi.jp/photo/member/1/12/112_3714846406.jpg</img>
<nick>ゆうきさん</nick>
<topic_interest>映画鑑賞, 料理, お酒, ショッピング, ファッション, 読書, マンガ, インターネット</topic_interest>
<based_near>東京都江戸川区</based_near>
</Person>
</knows>
<knows>
<Person>
<name>うらたさん</name>
<img>http://member.img.mixi.jp/photo/member/0/6/6_814100255.jpg</img>
<nick>うらたさん</nick>
<topic_interest>音楽鑑賞, カラオケ・バンド, 料理, グルメ, ショッピング, ファッション, アート, マンガ</topic_interest>
<based_near>富山県滑川市</based_near>
</Person>
</knows>
</rdf:RDF>
#
# Generate FOAF (Friend Of A Friend) from mixi <http://mixi.jp/>.
# mixi is the biggest social network site in Japan.
#
# == FOAF
# FOAF Vocabulary Specification 0.91 <http://xmlns.com/foaf/spec/>
#
# Author: Rakuto Furutani <http://raku.to/>
#
require 'rubygems'
require 'mechanize'
require 'active_support' # For builder.rb
require 'uri'
require 'logger'
require 'iconv'
require 'cgi'
require 'digest/sha1'
$KCODE = 'u'
$logger = Logger.new(STDERR)
module FOAF
class Person
attr_accessor :rdf_id, :name, :nick, :jabberID, :aimChatID, :msnChatID, :mbox, :description,
:mbox_sha1sum, :openid, :dateOfBirth, :jabberID, :aimChatID, :msnChatID
def initialize(attrs)
attrs.each do |k, v|
instance_eval %Q{self.#{k} = '#{v}'}
end
end
end
class Base
attr_accessor :me
XML_NS = {
'xml:lang' => 'en',
'xmlns' => 'http://www.w3.org/foaf/0.1/',
'xmlns:foaf' => 'http://xmlns.com/foaf/0.1/',
'xmlns:rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
'xmlns:rdfs' => 'http://www.w3.org/2000/01/rdf-schema#',
'xmlns:dc' => 'http://purl.org/dc/elements/1.1/',
'xmlns:dcterms' => 'http://purl.org/dc/terms/',
'xmlns:wot' => 'http://xmlns.com/wot/0.1/'
}
def initialize(username, password)
@username = username
@password = password
@agent = WWW::Mechanize.new
end
def login
end
def to_foaf
end
end
class Mixi < Base
def initialize(username, password)
@base_uri = URI.parse('http://mixi.jp/')
super
end
def login!
top = @agent.get(@base_uri)
login_form = top.forms.first
login_form.fields.name('email').value = @username
login_form.fields.name('password').value = @password
raise Exception, 'login failed' if login_form.submit.meta.empty?
end
def to_foaf(xmlns={})
login!
@friends = extract_friends!
xm = Builder::XmlMarkup.new(:indent => 2)
xm.instruct!
foaf = xm.rdf :RDF, XML_NS.merge(xmlns) do
# About me
xm.foaf :Person, 'rdf:ID' => @me.rdf_id do
(@me.public_methods - Object.public_methods).find_all {|meth| meth =~ /[^=]$/}.each do |meth|
if v = @me.__send__(meth)
case meth
when 'mbox_sha1sum'
xm.foaf meth.to_sym, Digest::SHA1.hexdigest(v)
else
xm.foaf meth.to_sym, v
end
end
end
end if @me
# Extract friends information
@friends.each do |f|
xm.knows do
xm.Person do
xm.name f[:name] if f.key?(:name)
xm.gender f[:gender] if f.key?(:gender)
xm.img f[:image] if f.key?(:image)
xm.homepage f[:homepage] if f.key?(:url)
xm.nick f[:name] if f.key?(:name)
xm.topic_interest f[:hobby].join(', ') if f.key?(:hobby)
xm.based_near f[:home_town] if f.key?(:home_town)
end
end
end
end
end
private
def extract_friends!
# Obtain my friend list
friend_list_page = @agent.get(@base_uri + 'list_friend.pl')
while true
friends = (friend_list_page.parser/'div.iconList03 ul li div').inject([]) do |ret, div|
returning ret do
begin
ret << {
:name => (div/'span').inner_text.strip.toutf8.match(/(.+?)\(\d+\)/)[1],
:url => @base_uri + (div/'div.iconListImage a')[0]['href']
} if div['class'] =~ /^iconState/ && div.inner_html.strip != ' '
rescue => e
# Just ignor it
end
end
end
# find anchor to next page
if (anchor = friend_list_page.parser/'div[@class="pageList02"]//ul//li[2]//a[1]').empty?
break
else
friend_list_page = @agent.get(@base_uri + anchor[0]['href'])
end
end
# Obtain details of friends
#friends = [friends[0]]
friends.map! do |f|
$logger.info "[Traverse] #{f[:url]}"
friend_page = @agent.get(f[:url])
# an image
f[:image] = (friend_page/'div.contents01 img')[0]['src']
# a profile
(friend_page.parser/'#profile ul li').each do |li|
dt = li/'dl dt'
dd = li/'dl dd'
value = dd.inner_text.toutf8.strip
case CGI.escape(dt.inner_text.toutf8.strip)
when '%E6%80%A7%E5%88%A5' # gender
f[:sex] = CGI.escape(value) == '%E5%A5%B3%E6%80%A7'? 'female' : 'female'
when '%E7%8F%BE%E4%BD%8F%E6%89%80' # address
f[:address] = value
when '%E5%B9%B4%E9%BD%A2' # age
f[:age] = value
when '%E8%AA%95%E7%94%9F%E6%97%A5' # birthday
f[:birthday] = value
when '%E8%A1%80%E6%B6%B2%E5%9E%8B' # type of blood
f[:type_of_blood] = value
when '%E5%87%BA%E8%BA%AB%E5%9C%B0' # home town
f[:home_town] = value
when '%E8%B6%A3%E5%91%B3' # hobby
f[:hobby] = dd.inner_text.toutf8.strip.split(',')
when '%E8%81%B7%E6%A5%AD' # job
f[:job] = value
when '%E6%89%80%E5%B1%9E' # organization
f[:org] = value
when '%E8%87%AA%E5%B7%B1%E7%B4%B9%E4%BB%8B' # self introduction
f[:introduction] = value
end
end
f
end
end
end
end
if $0 == __FILE__
# USAGE: ruby mixi2foaf.rb USERNAME PASSWORD
mixi = FOAF::Mixi.new(ARGV[0], ARGV[1])
# FIXME: Edit your profile
mixi.me = FOAF::Person.new({
:rdf_id => 'rakuto',
:name => 'Rakuto Furutani',
:nick => 'rakuto',
:openid => '=rakuto',
:mbox_sha1sum => 'rakuto@nospam.gmail.com'.sub('nospam.', ''),
:jabberID => 'rakuto@nospam.gmail.com'.sub('nospam.', ''),
:msnChatID => 'Strawberry_au_rait@hotmail.com'
})
puts mixi.to_foaf('xmlns:lang' => 'ja', 'xml:lang' => 'ja')
end