Perlでニコニコ動画のflvとコメントxmlをダウンロードする
さんざん既出かもしれないけどPerlでニコニコ動画のflvファイルとコメントのxmlファイルをダウンロードするスクリプト。 非公式ながら扱うことのできるニコニコ動画のAPIなんだけど、いくつかポイントがある。flvファイルのパスやコメントを表すスレッドのIDなどを取得するためのURLは
http://www.nicovideo.jp/api/getflv?v=ビデオID
になっていてる。ここにアクセス(GET)して得られる値のサンプルは以下のようなもの。 主なものを解説すると、urlというのがflvのパス、thread_idがコメントを示すスレッドのID、msがそのスレッドを取得できるAPIのURL。
thread_id:1184806392 l:91 url:http://smile-clb51.nicovideo.jp/smile?v=659632.44622 link:http://www.smilevideo.jp/view/659632/991267 ms:http://msg41.nicovideo.jp/api/ user_id:991267 is_premium:0 nickname:yournickname done:true
このAPIをたたく時、またはflvをダウンロードするときには注意がすべきことがある。 まずニコニコ動画にログインした状態のセッションを保持したクッキーをもったUserAgentでアクセスしなくてはいけないのはまず当たり前で、 さらに取得しようとしている動画のパーマリンク、つまり以下のアドレスにアクセスした状態でなくてはエラーがでてしまうのだ。
http://www.nicovideo.jp/watch/ビデオID
これがWebフォーム型のニコニコ動画ダウンロードがうまくいかない理由であり、一方、動画のページにダウンロードボタンを追加するGreasemonkeyではダウンロードが成功するゆえんでもある。 また、コメントのXMLを取得するには、上記APIで取得したmsの値であるURLに対して以下のXMLをPOSTすれば最近の500件を得ることができる。
<thread res_from="-500" version="20061206" thread="スレッドID" />
以上を踏まえて以下のflvとコメントxmlをダウンロードするスクリプトが完成。
#!/usr/bin/perl
use strict;
use LWP::UserAgent;
use HTTP::Cookies;
use URI::Escape;
use HTTP::Request;
use HTTP::Headers;
my $video_id = $ARGV[0] || "sm721154";
my $mail = "yourmailaddress";
my $password = "yourpassword";
my $ua = LWP::UserAgent->new;
$ua->cookie_jar( HTTP::Cookies->new(
file => 'cookie.lwp',
autosave => 1,
));
&login();
$ua->get( "http://www.nicovideo.jp/watch/$video_id" );
my $res = $ua->get( "http://www.nicovideo.jp/api/getflv?v=$video_id" );
my $content = uri_unescape($res->content);
my %data;
my @temp = split("&",$content);
foreach my $prop (@temp){
if($prop =~ /(.*?)=(.*)/){
$data{$1} = $2;
}
}
#save flv
$res = $ua->get( $data{url} );
&save($res->content, $video_id . ".flv");
#save xml
my $post_data = "<thread res_from=\"-500\" version=\"20061206\" thread=\"" . $data{thread_id} ."\" />";
my $header = HTTP::Headers->new;
$header->header('Content-Type' => 'text/xml');
my $req = HTTP::Request->new('POST', $data{ms}, $header, $post_data );
$res = $ua->request($req);
&save($res->content, $video_id . ".xml");
sub login{
$ua->post( "http://www.nicovideo.jp/login",
[
mail => $mail,
password => $password,
]);
}
sub save{
my ($content, $filename) = @_;
open FH, ">$filename";
binmode FH;
print FH $content;
close FH;
}


