l'essentiel est invisible pour les yeux

Saturday, March 15, 2008

[ruby] mixi2foaf.rb generates FOAF with friends network in mixi.

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>&#12422;&#12426;&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/80/51/4588051_99567334.jpg</img>
<nick>&#12422;&#12426;&#12373;&#12435;</nick>
<topic_interest>&#26144;&#30011;&#37969;&#36062;, &#38899;&#27005;&#37969;&#36062;, &#26009;&#29702;, &#12471;&#12519;&#12483;&#12500;&#12531;&#12464;, &#12501;&#12449;&#12483;&#12471;&#12519;&#12531;, &#35501;&#26360;, &#12452;&#12531;&#12479;&#12540;&#12493;&#12483;&#12488;, &#12506;&#12483;&#12488;</topic_interest>

<based_near>&#20140;&#37117;&#24220;&#20140;&#37117;&#24066;</based_near>
</Person>
</knows>
<knows>
<Person>
<name>&#12358;&#12376;&#12402;&#12373;&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/53/95/3805395_1723386446.jpg</img>
<nick>&#12358;&#12376;&#12402;&#12373;&#12373;&#12435;</nick>

<topic_interest>&#12450;&#12540;&#12488;, &#35486;&#23398;, &#12506;&#12483;&#12488;</topic_interest>
</Person>
</knows>
<knows>
<Person>
<name>&#12373;&#12387;&#12385;&#12355;&#12540;&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/40/38/3064038_2463714862.jpg</img>

<nick>&#12373;&#12387;&#12385;&#12355;&#12540;&#12373;&#12435;</nick>
<topic_interest>&#12473;&#12509;&#12540;&#12484;, &#12473;&#12509;&#12540;&#12484;&#35251;&#25126;, &#12362;&#37202;, &#12501;&#12449;&#12483;&#12471;&#12519;&#12531;, &#12450;&#12454;&#12488;&#12489;&#12450;, &#12489;&#12521;&#12452;&#12502;, &#26053;&#34892;, &#35501;&#26360;, &#12466;&#12540;&#12512;, &#12452;&#12531;&#12479;&#12540;&#12493;&#12483;&#12488;</topic_interest>
<based_near>&#20140;&#37117;&#24220;&#20140;&#37117;&#24066;</based_near>
</Person>

</knows>
<knows>
<Person>
<name>genki&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/5/69/2560569_1803584202.jpg</img>
<nick>genki&#12373;&#12435;</nick>
<topic_interest>&#26144;&#30011;&#37969;&#36062;, &#35501;&#26360;, &#12452;&#12531;&#12479;&#12540;&#12493;&#12483;&#12488;</topic_interest>

<based_near>&#26481;&#20140;&#37117;&#19990;&#30000;&#35895;&#21306;</based_near>
</Person>
</knows>
<knows>
<Person>
<name>&#12356;&#12387;&#12410;&#12356;&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/65/15/2276515_15823768.jpg</img>
<nick>&#12356;&#12387;&#12410;&#12356;&#12373;&#12435;</nick>

<topic_interest>&#26144;&#30011;&#37969;&#36062;, &#12473;&#12509;&#12540;&#12484;&#35251;&#25126;, &#12450;&#12454;&#12488;&#12489;&#12450;, &#12489;&#12521;&#12452;&#12502;, &#12452;&#12531;&#12479;&#12540;&#12493;&#12483;&#12488;</topic_interest>
<based_near>&#28363;&#36032;&#30476;&#29356;&#19978;&#37089;</based_near>
</Person>
</knows>
<knows>
<Person>
<name>&#12414;&#12385;&#12419;&#12365;&#12373;&#12435;</name>

<img>http://member.img.mixi.jp/photo/member/12/57/2231257_4177973050.jpg</img>
<nick>&#12414;&#12385;&#12419;&#12365;&#12373;&#12435;</nick>
<topic_interest>&#26144;&#30011;&#37969;&#36062;, &#12473;&#12509;&#12540;&#12484;, &#12473;&#12509;&#12540;&#12484;&#35251;&#25126;, &#38899;&#27005;&#37969;&#36062;, &#12362;&#37202;, &#12510;&#12531;&#12460;, &#12466;&#12540;&#12512;</topic_interest>
<based_near>&#20853;&#24235;&#30476;&#23019;&#36335;&#24066;</based_near>
</Person>

</knows>
<knows>
<Person>
<name>&#12403;&#12387;&#12367;&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/74/81/2227481_2218119710.jpg</img>
<nick>&#12403;&#12387;&#12367;&#12373;&#12435;</nick>
<topic_interest>&#26144;&#30011;&#37969;&#36062;, &#12473;&#12509;&#12540;&#12484;, &#12473;&#12509;&#12540;&#12484;&#35251;&#25126;, &#26009;&#29702;, &#12450;&#12454;&#12488;&#12489;&#12450;, &#12489;&#12521;&#12452;&#12502;, &#26053;&#34892;, &#12486;&#12524;&#12499;, &#12506;&#12483;&#12488;, &#32654;&#23481;&#12539;&#12480;&#12452;&#12456;&#12483;&#12488;</topic_interest>

<based_near>&#26481;&#20140;&#37117;&#27743;&#25144;&#24029;&#21306;</based_near>
</Person>
</knows>
<knows>
<Person>
<name>&#12405;&#12387;&#12385;&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/12/13/2221213_1175337526.jpg</img>
<nick>&#12405;&#12387;&#12385;&#12373;&#12435;</nick>

<topic_interest>&#38899;&#27005;&#37969;&#36062;, &#12501;&#12449;&#12483;&#12471;&#12519;&#12531;, &#12486;&#12524;&#12499;</topic_interest>
</Person>
</knows>
<knows>
<Person>
<name>&#12383;&#12397;&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/27/88/2112788_3718693077.jpg</img>

<nick>&#12383;&#12397;&#12373;&#12435;</nick>
<topic_interest>&#26144;&#30011;&#37969;&#36062;, &#12473;&#12509;&#12540;&#12484;, &#12473;&#12509;&#12540;&#12484;&#35251;&#25126;, &#38899;&#27005;&#37969;&#36062;, &#12489;&#12521;&#12452;&#12502;</topic_interest>
<based_near>&#20140;&#37117;&#24220;&#20140;&#37117;&#24066;</based_near>
</Person>
</knows>
<knows>
<Person>

<name>&#12365;&#12426;&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/54/23/2025423_3963467882.jpg</img>
<nick>&#12365;&#12426;&#12373;&#12435;</nick>
<topic_interest>&#12473;&#12509;&#12540;&#12484;, &#12473;&#12509;&#12540;&#12484;&#35251;&#25126;, &#38899;&#27005;&#37969;&#36062;, &#12464;&#12523;&#12513;</topic_interest>
<based_near>&#20140;&#37117;&#24220;&#20140;&#37117;&#24066;</based_near>
</Person>
</knows>

<knows>
<Person>
<name>&#12402;&#12391;&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/17/46/2001746_3424328848.jpg</img>
<nick>&#12402;&#12391;&#12373;&#12435;</nick>
<topic_interest>&#12473;&#12509;&#12540;&#12484;, &#12473;&#12509;&#12540;&#12484;&#35251;&#25126;, &#38899;&#27005;&#37969;&#36062;, &#26009;&#29702;, &#12464;&#12523;&#12513;, &#12471;&#12519;&#12483;&#12500;&#12531;&#12464;, &#12450;&#12454;&#12488;&#12489;&#12450;, &#12489;&#12521;&#12452;&#12502;, &#26053;&#34892;, &#12452;&#12531;&#12479;&#12540;&#12493;&#12483;&#12488;</topic_interest>

<based_near>&#20140;&#37117;&#24220;&#20140;&#37117;&#24066;</based_near>
</Person>
</knows>
<knows>
<Person>
<name>&#12373;&#12392;&#12375;&#12355;&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/5/38/1410538_2487809269.jpg</img>
<nick>&#12373;&#12392;&#12375;&#12355;&#12373;&#12435;</nick>

<topic_interest>&#26144;&#30011;&#37969;&#36062;, &#12473;&#12509;&#12540;&#12484;, &#38899;&#27005;&#37969;&#36062;, &#12471;&#12519;&#12483;&#12500;&#12531;&#12464;, &#35486;&#23398;, &#35501;&#26360;, &#12510;&#12531;&#12460;, &#12452;&#12531;&#12479;&#12540;&#12493;&#12483;&#12488;, &#12462;&#12515;&#12531;&#12502;&#12523;</topic_interest>
<based_near>&#28363;&#36032;&#30476;</based_near>
</Person>
</knows>
<knows>

<Person>
<name>&#12394;&#12362;&#9734;&#12444;+.&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/96/1/1339601_3143320574.jpg</img>
<nick>&#12394;&#12362;&#9734;&#12444;+.&#12373;&#12435;</nick>
<topic_interest>&#26144;&#30011;&#37969;&#36062;, &#38899;&#27005;&#37969;&#36062;, &#12464;&#12523;&#12513;, &#12362;&#37202;, &#12471;&#12519;&#12483;&#12500;&#12531;&#12464;, &#12501;&#12449;&#12483;&#12471;&#12519;&#12531;, &#12489;&#12521;&#12452;&#12502;, &#26053;&#34892;, &#12506;&#12483;&#12488;</topic_interest>

<based_near>&#20140;&#37117;&#24220;&#20140;&#37117;&#24066;</based_near>
</Person>
</knows>
<knows>
<Person>
<name>&#12354;&#12451; ? &#12422;&#12453; &#27096;&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/37/71/883771_3362183383.jpg</img>

<nick>&#12354;&#12451; ? &#12422;&#12453; &#27096;&#12373;&#12435;</nick>
<topic_interest>&#12473;&#12509;&#12540;&#12484;, &#12464;&#12523;&#12513;, &#12362;&#37202;, &#32654;&#23481;&#12539;&#12480;&#12452;&#12456;&#12483;&#12488;</topic_interest>
<based_near>&#20140;&#37117;&#24220;&#20140;&#37117;&#24066;</based_near>
</Person>
</knows>
<knows>

<Person>
<name>&#12407;&#12426;&#12435;&#12373;&#12435;</name>
<img>http://img.mixi.jp/img/basic/common/noimage_member180.gif</img>
<nick>&#12407;&#12426;&#12435;&#12373;&#12435;</nick>
</Person>
</knows>
<knows>
<Person>

<name>cuzic&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/66/22/516622_1304637750.jpg</img>
<nick>cuzic&#12373;&#12435;</nick>
<topic_interest>&#35486;&#23398;, &#35501;&#26360;, &#12486;&#12524;&#12499;</topic_interest>
<based_near>&#22823;&#38442;&#24220;&#22823;&#38442;&#24066;</based_near>
</Person>

</knows>
<knows>
<Person>
<name>&#12490;&#12288;&#12458;&#12479;&#12465;&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/43/66/344366_692701929.jpg</img>
<nick>&#12490;&#12288;&#12458;&#12479;&#12465;&#12373;&#12435;</nick>
<topic_interest>&#12473;&#12509;&#12540;&#12484;, &#38899;&#27005;&#37969;&#36062;, &#12450;&#12454;&#12488;&#12489;&#12450;, &#12450;&#12540;&#12488;, &#35501;&#26360;, &#12466;&#12540;&#12512;, &#12452;&#12531;&#12479;&#12540;&#12493;&#12483;&#12488;</topic_interest>

<based_near>&#38263;&#23822;&#30476;&#20304;&#19990;&#20445;&#24066;</based_near>
</Person>
</knows>
<knows>
<Person>
<name>ankoparty&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/29/2/292902_3069630518.jpg</img>
<nick>ankoparty&#12373;&#12435;</nick>

<topic_interest>&#38899;&#27005;&#37969;&#36062;, &#12464;&#12523;&#12513;, &#12471;&#12519;&#12483;&#12500;&#12531;&#12464;, &#12501;&#12449;&#12483;&#12471;&#12519;&#12531;, &#26053;&#34892;, &#12452;&#12531;&#12479;&#12540;&#12493;&#12483;&#12488;, &#12506;&#12483;&#12488;</topic_interest>
<based_near>&#22524;&#29577;&#30476;</based_near>
</Person>
</knows>
<knows>
<Person>

<name>hiroko&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/73/65/47365_319217593.jpg</img>
<nick>hiroko&#12373;&#12435;</nick>
<topic_interest>&#12473;&#12509;&#12540;&#12484;, &#12473;&#12509;&#12540;&#12484;&#35251;&#25126;, &#38899;&#27005;&#37969;&#36062;, &#26009;&#29702;, &#12464;&#12523;&#12513;, &#12501;&#12449;&#12483;&#12471;&#12519;&#12531;, &#26053;&#34892;</topic_interest>

<based_near>&#28363;&#36032;&#30476;&#22823;&#27941;&#24066;</based_near>
</Person>
</knows>
<knows>
<Person>
<name>&#12356;&#12373;&#12416;&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/33/41/3341_118115164.jpg</img>
<nick>&#12356;&#12373;&#12416;&#12373;&#12435;</nick>

<topic_interest>&#26144;&#30011;&#37969;&#36062;, &#38899;&#27005;&#37969;&#36062;, &#12464;&#12523;&#12513;, &#12362;&#37202;, &#12471;&#12519;&#12483;&#12500;&#12531;&#12464;, &#12501;&#12449;&#12483;&#12471;&#12519;&#12531;, &#12489;&#12521;&#12452;&#12502;, &#26053;&#34892;, &#35501;&#26360;, &#12452;&#12531;&#12479;&#12540;&#12493;&#12483;&#12488;, &#12506;&#12483;&#12488;</topic_interest>
</Person>
</knows>
<knows>

<Person>
<name>&#65312;&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/32/37/3237_54519266.jpg</img>
<nick>&#65312;&#12373;&#12435;</nick>
<topic_interest>&#12452;&#12531;&#12479;&#12540;&#12493;&#12483;&#12488;</topic_interest>
<based_near>&#28363;&#36032;&#30476;&#26647;&#26481;&#24066;</based_near>
</Person>
</knows>

<knows>
<Person>
<name>&#12354;&#12420;&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/22/88/2288_1047374038.jpg</img>
<nick>&#12354;&#12420;&#12373;&#12435;</nick>
<topic_interest>&#26144;&#30011;&#37969;&#36062;, &#12473;&#12509;&#12540;&#12484;, &#38899;&#27005;&#37969;&#36062;, &#26009;&#29702;, &#12464;&#12523;&#12513;, &#12471;&#12519;&#12483;&#12500;&#12531;&#12464;, &#35501;&#26360;</topic_interest>

<based_near>&#39321;&#24029;&#30476;&#26481;&#12363;&#12364;&#12431;&#24066;</based_near>
</Person>
</knows>
<knows>
<Person>
<name>&#12402;&#12391;&#12392;&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/7/44/744_785912264.jpg</img>
<nick>&#12402;&#12391;&#12392;&#12373;&#12435;</nick>

<topic_interest>&#26144;&#30011;&#37969;&#36062;, &#38899;&#27005;&#37969;&#36062;, &#12464;&#12523;&#12513;, &#12362;&#37202;, &#12501;&#12449;&#12483;&#12471;&#12519;&#12531;, &#12489;&#12521;&#12452;&#12502;, &#26053;&#34892;, &#35501;&#26360;, &#12452;&#12531;&#12479;&#12540;&#12493;&#12483;&#12488;</topic_interest>
<based_near>&#20140;&#37117;&#24220;&#20140;&#37117;&#24066;</based_near>
</Person>
</knows>
<knows>

<Person>
<name>&#12402;&#12391;&#12405;&#12415;&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/5/2/502_1466901064.jpg</img>
<nick>&#12402;&#12391;&#12405;&#12415;&#12373;&#12435;</nick>
<topic_interest>&#26144;&#30011;&#37969;&#36062;, &#12473;&#12509;&#12540;&#12484;, &#38899;&#27005;&#37969;&#36062;, &#12362;&#37202;, &#12450;&#12540;&#12488;, &#35501;&#26360;</topic_interest>
<based_near>&#32676;&#39340;&#30476;&#26704;&#29983;&#24066;</based_near>

</Person>
</knows>
<knows>
<Person>
<name>&#12371;&#12400;&#12370;&#12435;&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/4/74/474_3993761079.jpg</img>
<nick>&#12371;&#12400;&#12370;&#12435;&#12373;&#12435;</nick>
<topic_interest>&#38899;&#27005;&#37969;&#36062;, &#35501;&#26360;, &#12510;&#12531;&#12460;, &#12452;&#12531;&#12479;&#12540;&#12493;&#12483;&#12488;</topic_interest>

</Person>
</knows>
<knows>
<Person>
<name>&#21281;&#24535;&#12373;&#12435;</name>
<img>http://img.mixi.jp/img/basic/common/noimage_member180.gif</img>
<nick>&#21281;&#24535;&#12373;&#12435;</nick>
<topic_interest>&#26053;&#34892;, &#35501;&#26360;, &#12452;&#12531;&#12479;&#12540;&#12493;&#12483;&#12488;</topic_interest>

<based_near>&#22823;&#38442;&#24220;&#23500;&#30000;&#26519;&#24066;</based_near>
</Person>
</knows>
<knows>
<Person>
<name>&#12422;&#12358;&#12365;&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/1/12/112_3714846406.jpg</img>
<nick>&#12422;&#12358;&#12365;&#12373;&#12435;</nick>

<topic_interest>&#26144;&#30011;&#37969;&#36062;, &#26009;&#29702;, &#12362;&#37202;, &#12471;&#12519;&#12483;&#12500;&#12531;&#12464;, &#12501;&#12449;&#12483;&#12471;&#12519;&#12531;, &#35501;&#26360;, &#12510;&#12531;&#12460;, &#12452;&#12531;&#12479;&#12540;&#12493;&#12483;&#12488;</topic_interest>
<based_near>&#26481;&#20140;&#37117;&#27743;&#25144;&#24029;&#21306;</based_near>
</Person>
</knows>
<knows>

<Person>
<name>&#12358;&#12425;&#12383;&#12373;&#12435;</name>
<img>http://member.img.mixi.jp/photo/member/0/6/6_814100255.jpg</img>
<nick>&#12358;&#12425;&#12383;&#12373;&#12435;</nick>
<topic_interest>&#38899;&#27005;&#37969;&#36062;, &#12459;&#12521;&#12458;&#12465;&#12539;&#12496;&#12531;&#12489;, &#26009;&#29702;, &#12464;&#12523;&#12513;, &#12471;&#12519;&#12483;&#12500;&#12531;&#12464;, &#12501;&#12449;&#12483;&#12471;&#12519;&#12531;, &#12450;&#12540;&#12488;, &#12510;&#12531;&#12460;</topic_interest>

<based_near>&#23500;&#23665;&#30476;&#28369;&#24029;&#24066;</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 != '&nbsp;'
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