好用的BitTorrent Tracker API?
你知道有没有简单好用的API,可以让Python或Perl和BitTorrent Tracker进行互动吗?比如,我想拿一个种子文件,列出文件里的所有Tracker,然后向这些Tracker请求与下载的文件相关的用户统计信息。
BitTorrent Tracker的规范其实并不复杂,但我不想重新发明轮子 :)
需要注意的是,我并不想下载数据,只是想获取一些统计信息(Net::BitTorrent对我来说功能太多了)。
3 个回答
2
可以看看 py-transmission 这个链接。
补充一下:我写完这个之后发现,transmissionbt的RPC接口 文档写得非常好,内容也很友好,只要你花点时间去了解基本知识就能轻松上手。
3
光靠命令行不够用吗?:-) (Transmission) 提供了一个叫 transmission-remote 的工具,这个工具可以让你用一条命令来列出追踪器和获取对等节点的统计信息。看看下面的内容:
-pi --peer-info
List the current torrent's connected peers. In the `status' section of the list, the following shorthand is used:
D: Downloading from this peer
d: We would download from this peer if they would let us
E: Encrypted connection
I: Peer is an incoming connection
K: Peer has unchoked us, but we're not interested
O: Optimistic unchoked
U: Uploading to peer
u: We would upload to this peer if they asked
X: Peer was discovered through Peer Exchange (PEX)
?: We unchoked this peer, but they're not interested
...
-si --session-info
List session information from the server
不过,要使用这个工具,你得先把 transmission 作为你的种子下载客户端。如果你这样做了,那么你就可以用 grep 来处理数据,这要看你到底想实现什么目标。
1
我写了一个Perl脚本,用来从.torrent文件中获取数据,收集追踪器的信息,并获取一些统计数据(比如文件哈希、连接到追踪器的IP、文件大小等等)。这没什么复杂的,就是一些Perl的小技巧。要运行这个脚本,你需要安装Perl模块Bencode、curl和transmission-show。调试时产生的垃圾信息会发送到stderr,而正确的输出会发送到stdout。
#!/usr/bin/perl
use Bencode qw( bencode bdecode );
use Data::Dumper;
use warnings;
use strict;
my $G_PEER_ID = "hfgdbvnchdgfhvnfbghf";
my $G_MAX_TIME = 20;
sub peer_decode
{
my $d = shift;
my @a = split '', $d;
# printf ">>%d %d<<\n", length($d), scalar(@a);
my @ret;
while(@a) {
my $ip = sprintf "%d.%d.%d.%d" ,
unpack('C',shift(@a)),
unpack('C',shift(@a)),
unpack('C',shift(@a)),
unpack('C',shift(@a));
my $port = sprintf "%d", 256 * unpack('C',shift(@a))
+ unpack('C',shift(@a));
# printf "%d $ip $port\n",scalar(@a);
push @ret, $ip;
}
return \@ret;
}
sub get_tracker_data_from_file
{
my $fname = shift;
my $ret = {};
my $c = `transmission-show $fname`;
print STDERR "$c\n";
if ( $c =~ /^\s+Hash:\s*(\S+)/mg ) {
$ret->{'hash'} = $1;
}
if ( $c =~ /^\s+Total Size:\s*(.+)$/mg ) {
$ret->{'size'} = $1;
}
my @g;
@g = ($c =~ /Tier \#\d+[\n\r\s]+(\S+)/gm);
if ( @g ) {
$ret->{'tiers'} = \@g;
}
return $ret;
}
sub get_peer_ips
{
my $hash = shift;
my $tracker = shift;
my $ret = undef;
$hash =~ s/(..)/\%$1/g;
$tracker =~ s/\/$//;
my $c = "curl -m $G_MAX_TIME -s '$tracker?info_hash=$hash&peer_id=$G_PEER_ID&uploaded=0&downloaded=0&left=1'";
print STDERR "$c\n";
my $w = `$c`;
return undef if not $w;
printf STDERR "%s\n" , Dumper($w);
return undef if $w =~ /<\s*html\s*>/gi;
$w = bdecode($w, 1);
if ( defined $w->{'peers'} ) {
$ret = peer_decode($w->{'peers'});
}
return $ret;
}
# -- main
my @files = @ARGV;
if ( not @files ) {
print <<END
usage: $0 <file1.torrent> <file2.torrent> ...
(c) http://stackoverflow.com/users/497208
END
}
for my $fname ( @files ) {
printf STDERR "File: %s\n", $fname;
my $tr = get_tracker_data_from_file($fname);
printf STDERR "%s\n", Dumper $tr;
my $hash = undef;
$hash = $tr->{'hash'} if defined $tr->{'hash'};
exit if not defined $hash;
my $size = undef;
if ( defined $tr->{'size'} ) {
$size = $tr->{'size'};
}
else {
$size = "?";
}
if ( defined $tr->{'tiers'} ) {
# shift @{$tr->{'tiers'}} for (1..5);
for my $tracker ( @{$tr->{'tiers'}} ) {
my $ips = get_peer_ips( $hash, $tracker);
printf STDERR "%s\n", Dumper $ips;
if ( defined $ips ) {
for my $ip ( @$ips ) {
my $c = sprintf "%s; %16s; %s; %s", $hash, $ip, $size, $tracker;
printf STDERR "$c\n";
printf "$c\n";
}
}
}
}
}