2015-05-25 3 views
2

Я пытаюсь извлечь размер и имя из торрент-файла с расшифровкой содержимого торрент-файла с помощью bencode.Как декодировать данные торрента bencoded

Я сделал pip install bencode, затем я тестировал одну из строк торрент-файла, как вы можете видеть там.

import bencode 

blabla = 'd8:announce70:http://tracker.t411.io:56969/c5faa6720249d33ff6ba2af48640af89/announce7:comment29:https://www.t411.io/t/524280210:created by19:https://www.t411.io13:creation datei1431685353e4:infod6:lengthi14634059e4:name22:Charlie-Hebdo-1178.pdf12:piece lengthi262144e6:pieces1120:' 
myprint = bencode.decode_string(blabla,1) 
print myprint 

Это файл, пункт установить положить в питона Lib:

from BTL import BTFailure 


def decode_int(x, f): 
    f += 1 
    newf = x.index('e', f) 
    n = int(x[f:newf]) 
    if x[f] == '-': 
     if x[f + 1] == '0': 
      raise ValueError 
    elif x[f] == '0' and newf != f+1: 
     raise ValueError 
    return (n, newf+1) 

def decode_string(x, f): 
    colon = x.index(':', f) 
    n = int(x[f:colon]) 
    if x[f] == '0' and colon != f+1: 
     raise ValueError 
    colon += 1 
    return (x[colon:colon+n], colon+n) 

def decode_list(x, f): 
    r, f = [], f+1 
    while x[f] != 'e': 
     v, f = decode_func[x[f]](x, f) 
     r.append(v) 
    return (r, f + 1) 

def decode_dict(x, f): 
    r, f = {}, f+1 
    while x[f] != 'e': 
     k, f = decode_string(x, f) 
     r[k], f = decode_func[x[f]](x, f) 
    return (r, f + 1) 

decode_func = {} 
decode_func['l'] = decode_list 
decode_func['d'] = decode_dict 
decode_func['i'] = decode_int 
decode_func['0'] = decode_string 
decode_func['1'] = decode_string 
decode_func['2'] = decode_string 
decode_func['3'] = decode_string 
decode_func['4'] = decode_string 
decode_func['5'] = decode_string 
decode_func['6'] = decode_string 
decode_func['7'] = decode_string 
decode_func['8'] = decode_string 
decode_func['9'] = decode_string 

def bdecode(x): 
    try: 
     r, l = decode_func[x[0]](x, 0) 
    except (IndexError, KeyError, ValueError): 
     raise BTFailure("not a valid bencoded string") 
    if l != len(x): 
     raise BTFailure("invalid bencoded value (data after valid prefix)") 
    return r 

from types import StringType, IntType, LongType, DictType, ListType, TupleType 


class Bencached(object): 

    __slots__ = ['bencoded'] 

    def __init__(self, s): 
     self.bencoded = s 

def encode_bencached(x,r): 
    r.append(x.bencoded) 

def encode_int(x, r): 
    r.extend(('i', str(x), 'e')) 

def encode_bool(x, r): 
    if x: 
     encode_int(1, r) 
    else: 
     encode_int(0, r) 

def encode_string(x, r): 
    r.extend((str(len(x)), ':', x)) 

def encode_list(x, r): 
    r.append('l') 
    for i in x: 
     encode_func[type(i)](i, r) 
    r.append('e') 

def encode_dict(x,r): 
    r.append('d') 
    ilist = x.items() 
    ilist.sort() 
    for k, v in ilist: 
     r.extend((str(len(k)), ':', k)) 
     encode_func[type(v)](v, r) 
    r.append('e') 

encode_func = {} 
encode_func[Bencached] = encode_bencached 
encode_func[IntType] = encode_int 
encode_func[LongType] = encode_int 
encode_func[StringType] = encode_string 
encode_func[ListType] = encode_list 
encode_func[TupleType] = encode_list 
encode_func[DictType] = encode_dict 

try: 
    from types import BooleanType 
    encode_func[BooleanType] = encode_bool 
except ImportError: 
    pass 

def bencode(x): 
    r = [] 
    encode_func[type(x)](x, r) 
    return ''.join(r) 

Дело в том, что я не понимаю, как я могу расшифровать свою линию с этим bencode.

Я уже попробовал размораживание bdecode но это выход:

[email protected]:/home/florian/Téléchargements# python decript.py 
Traceback (most recent call last): 
    File "decript.py", line 4, in <module> 
    myprint = bencode.bdecode(blabla) 
    File "/usr/local/lib/python2.7/dist-packages/bencode/__init__.py", line 68, in bdecode 
    raise BTFailure("not a valid bencoded string") 
bencode.BTL.BTFailure: not a valid bencoded string 

Так что я попытался с опр decode_string но с decode_string(blabla, 1) это декодировать только первое слово:

[email protected]:/home/florian/Téléchargements# python decript.py 
('announce', 11) 

и номер как 2, 3, 4 не работают и отображают ошибку, например:

[email protected]:/home/florian/Téléchargements# python decript.py 
Traceback (most recent call last): 
    File "decript.py", line 4, in <module> 
    myprint = bencode.decode_string(blabla,10) 
    File "/usr/local/lib/python2.7/dist-packages/bencode/__init__.py", line 29, in decode_string 
    n = int(x[f:colon]) 
ValueError: invalid literal for int() with base 10: 'e70' 

Я хочу декодировать всю строку, и я не понимаю, как это сделать с помощью этого bencode, например.

ответ

2

У вас есть неполная строка Bencoded.

Первая часть говорит вам, что есть словарь:

d... 

который должен быть обработан до тех пор, пока это e характер. В строке ввода нет такого символа.

Руководство синтаксического анализа показывает, у вас есть ключи announce, comment, created by, creation date и info, где последний является вложенным словарем с length, name, piece-length и pieces. Затем ваша строка останавливается; нет значения для pieces и нет e, чтобы отметить конец либо внешнего словаря, либо вложенного словаря info. У нас есть индикатор типа и длины: 1120.

Вы могли бы попытаться использовать функции декодирования непосредственно, а затем принять во внимание, что они возвращают значение и смещение:

>>> bencode.decode_string(blabla, 1) 
('announce', 11) 

11 является смещение для следующего значения:

>>> bencode.decode_string(blabla, 11) 
('http://tracker.t411.io:56969/c5faa6720249d33ff6ba2af48640af89/announce', 84) 

и 84 снова в следующем:

>>> bencode.decode_string(blabla, 84) 
('comment', 93) 

Если учесть, что строка неполна и что не все закодированные объекты являются строками, вы все равно можете декодировать, что мало.

Смещение также сообщает вам, какую функцию использовать для декодирования:

>>> blabla[1] 
'8' 
>>> bencode.decode_func[blabla[1]] 
<function decode_string at 0x1004632a8> 

Количество здесь заклинания, сколько символов ожидать. Так пропуская неисправную отображение d словаря вы получите:

>>> offset = 1 
>>> while True: 
...  value, offset = bencode.decode_func[blabla[offset]](blabla, offset) 
...  print value 
... 
announce 
http://tracker.t411.io:56969/c5faa6720249d33ff6ba2af48640af89/announce 
comment 
https://www.t411.io/t/5242802 
created by 
https://www.t411.io 
creation date 
1431685353 
info 
Traceback (most recent call last): 
    File "<stdin>", line 2, in <module> 
    File "/Users/mj/Development/venvs/stackoverflow-2.7/lib/python2.7/site-packages/bencode/__init__.py", line 44, in decode_dict 
    while x[f] != 'e': 
IndexError: string index out of range 

который терпит неудачу, потому что вы попали в гнездовой словарь без e. Вы можете извлечь эти ключи тоже путем добавления одного до последнего смещения:

>>> offset 
194 
>>> blabla[offset] 
'd' 
>>> offset += 1 
>>> while True: 
...  value, offset = bencode.decode_func[blabla[offset]](blabla, offset) 
...  print value 
... 
length 
14634059 
name 
Charlie-Hebdo-1178.pdf 
piece length 
262144 
pieces 

Traceback (most recent call last): 
    File "<stdin>", line 2, in <module> 
IndexError: string index out of range 

Или вы можете просто прочитать данные, как двоичных данных, а не укоротить его:

with open(torrentfilename, 'rb') as torrentfile: 
    torrent = bencode.bdecode(torrentfile.read()) 
# now you have a dictionary. 
+0

«Первая часть говорит вам, что есть словарь с 8 элементами». Это неверно. – the8472

+0

@ the8472: на самом деле. Это всего лишь длина закодированной строки. –

+1

Я думаю, что, наконец, понимаю, спасибо за ваш очень хороший ответ. В быстром я просто хочу извлечь имя и размер для каждого файла '.torrent', а затем хэш после, но смещение никогда не будет таким же, поэтому я должен обнаруживать« имя »и« длина »внутри моего сценария, я думаю , И почему сценарий останавливается на 'e'? Потому что, если вы хотите прочитать всю информацию ... (Извините за мой уровень питона) @MartijnPieters – Bouh10

3

Строка, которую вы пытаетесь декодировать, кажется усеченной. он заканчивается на pieces1120:, указывая, что должно следовать не менее 1120 байт.

BEncoding - это двоичный формат. Это только частично понятное для человека и не предназначено для встраивания в такие чувствительные к кодировке вещи, как файлы исходного кода. Я предлагаю вам прочитать его прямо из файла.

+0

Вы имеете в виду, что я должен не взять строку из файла в gedit, но прочитать ее прямо с помощью команды в моем скрипте? – Bouh10

+4

вы не должны декодировать «строку», вы должны сразу декодировать весь файл. bencoding не является линейным. и да, используйте файл-IO в вашем скрипте. – the8472