Coder Social home page Coder Social logo

magnet-dht's Introduction

Python3 DHT 网络磁力种子采集器

😎 严肃的理论

磁力链接

现在我们使用迅雷等工具下载资源的时候,基本上都只需要一个叫做磁力链接的东西就可以了,非常方便。

我仿佛听到了车鸣声

磁力定义

磁力链接是对等网络中进行信息检索和下载文档的电脑程序。和基于“位置”连接的统一资源定位符不同,磁力链接是基于元数据文件内容,属于统一资源名称。也就是说,磁力链接不基于文档的 IP 地址或定位符,而是在分布式数据库中,通过散列函数值来识别、搜索来下载文档。因为不依赖一个处于启动状态的主机来下载文档,所以特别适用没有中心服务器的对等网络。

磁力链接格式类似于 magnet:?xt=urn:btih:E7FC73D9E20697C6C440203F5884EF52F9E4BD28

分解一下这个链接

  • magnet:协议名。
  • xt:exact topic 的缩写,表示资源定位点。BTIH(BitTorrent Info Hash)表示哈希方法名,这里还可以使用 SHA1 和 MD5。这个值是文件的标识符,是不可缺少的。

一般来讲,一个磁力链接只需要上面两个参数即可找到唯一对应的资源。也有其他的可选参数提供更加详细的信息。

  • dn:display name 的缩写,表示向用户显示的文件名。
  • tr:tracker 的缩写,表示 tracker 服务器的地址。
  • kt: 关键字,更笼统的搜索,指定搜索关键字而不是特定文件。
  • mt:文件列表,链接到一个包含磁力链接的元文件 (MAGMA - MAGnet MAnifest)。

这里可以阅读阮一峰的 BT 下载的未来,我很喜欢他文章的最后一句话。

当互联网上每一台机器都在自动交换信息的时候,谎言和封锁又能持续多久呢?

种子/DHT

通过磁力就可以获取种子文件从而进行下载,这跟直接使用种子下载时一个道理的,只是少了从磁力到种子文件的一个过程而已。

老司机 带带我

种子定义

BitTorrent 协议的种子文件可以保存一组文件的元数据。这种格式的文件被 BitTorrent 协议所定义。扩展名一般为“.torrent”。

种子结构

.torrent 种子文件本质上是文本文件,包含 Tracker 信息和文件信息两部分。Tracker 信息主要是 BT 下载中需要用到的 Tracker 服务器的地址和针对 Tracker 服务器的设置,文件信息是根据对目标文件的计算生成的,计算结果根据 BitTorrent 协议内的 Bencode 规则进行编码。它的主要原理是需要把提供下载的文件虚拟分成大小相等的块,块大小必须为2k的整数次方(由于是虚拟分块,硬盘上并不产生各个块文件),并把每个块的索引信息和 Hash 验证码写入种子文件中;所以,种子文件就是被下载文件的“索引”。

种子-磁力联系

磁力链接的唯一标识符就是 40 个 16 进制字符码,也就是 magnet:?xt=urn:btih:E7FC73D9E20697C6C440203F5884EF52F9E4BD28 中的 E7FC73D9E20697C6C440203F5884EF52F9E4BD28。这个同时也是种子文件的 info_hash,是每个种子的唯一标识码。根据它就能将磁力链接于种子联系起来,得到资源的详细信息,进而下载资源。

DHT

BitTorrent 使用”分布式哈希表”(DHT)来为无 tracker 的种子(torrents)存储 peer 之间的联系信息。这样每个 peer 都成了 tracker。这个协议基于 Kademila 网络并且在 UDP 上实现。DHT 由节点组成,它存储了 peer 的位置。BitTorrent 客户端包含一个 DHT 节点,这个节点用来联系 DHT 中其他节点,从而得到 peer 的位置,进而通过 BitTorrent 协议下载。

  • peer: 一个 TCP 端口上监听的客户端/服务器,它实现了 BitTorrent 协议。
  • 节点: 一个 UDP 端口上监听的客户端/服务器,它实现了 DHT(分布式哈希表) 协议。

如果对 DHT 协议感兴趣的话一定要看下 DHT 协议 的具体内容,这里有 中文翻译版本。(想要彻底读懂项目的话一定要先了解该协议,代码都是基于该协议实现的,我也是反复的阅读了好几遍。)

😉 务实的实践

项目来源

一般来讲到 Python 爬取,大家的第一印象可能就是 requests/aiohttp,或者是 scrapy/pyspider 等爬虫框架。基本上都是从指定的 HTML 页面爬取信息。我有一个项目 torrent-cli 就是一个从资源网站上爬取磁力信息的工具。

赶紧上车

然而我

渴望进步

想自给自足获取磁力种子,Google 了一番,发现大家基本上的代码都是从 simDHT 这个项目来的,首先这个项目很棒,但是些问题如代码不规范、实现细节基本没有一行注释、不兼容 Python3。然而很多网上同类的代码基本上也是对这个完全照搬....

眉头一皱

所以我知道我要开始干活了

努力干活

经过一波 happy coding 之后。

开开心心写代码

当然最后还是给码出来了啦

ojbk

项目结构

核心代码

从 DHT 网络中获取磁力链接。主要是利用一些大型的服务器 tracker,冒充 DHT 节点,使用 UDP 协议加入到 DHT 网络中搜索一波以及和其他节点搞好关系,让他们也分享我点资源。

大哥喝可乐

磁力数据存放在了 redis,利用 redis 的集合特性来去重。使用了多线程/多进程,用于提高爬取效率。在我的本地机器(i7-7700HQ/16G 内存/8M 网速)跑了一下,效果还不错。

运行效果

运行效果

查看 redis 磁链数量

$ redis-cli
127.0.0.1:6379> scard magnets
(integer) 1151256

然后代码推送到我那台 性能强悍 1 核/2G 内存/1M 网速 阿里云服务器跑一下,哎....

穷

利用 aria2 将磁力链接转换为种子文件。尝试了一些其他的方式将磁力转换为种子,但效果好像都不怎么理想。使用过 libtorrent 的 Python 版本,不知道是我打开方式不对还是它本来效率就不高,反正愣是一个种子都没有转换成功。

好气喔

最后兜兜转转用到了 aria2 发现效率还可以。但是要先把 aria2 安装到你的 PATH 中,具体参考官网介绍。使用其 RPC 特性,节省线程开销。

真香

解析种子文件内容,同样也是利用了 Bencode 进行解码。有了种子我们当然要看看到底是些什么资源了啦。你说世界就是这么小,在我解析出来的几百个种子文件中,居然有几个都是一个社区的,那个以 1024 为标志的社区。

还有这种操作

有图有真相

知乎社区

不过我还是希望大家铭记下面这 24 字箴言

社会主义核心价值观

辅助代码

  • database.py:封装了关于 redis 的数据操作,主要是利用其集合数据结构。
  • utils.py:一些工具函数

如何使用

获取源码及安装依赖环境

确保已经安装好 redis,redis 的具体配置可以在 database.py 里面修改

$ git clone https://github.com/chenjiandongx/magnet-dht.git
$ cd magnet-dht
$ pip install -r requirements.txt

运行项目

进程数量可以在 crawler.py 进行调整

$ python manage.py -h
usage: manage.py [-h] [-s] [-m] [-p]

start manage.py with flag.

optional arguments:
  -h, --help  show this help message and exit
  -s          run start_server func.
  -m          run magnet2torrent func
  -p          run parse_torrent func

Note: 在运行 python manage.py -m 的时候,要先开个终端窗口启动 aria2c 服务。

$ aria2c --enable-rpc=true --bt-metadata-only=true --bt-save-metadata=true

😃 深刻的感悟

自我接触编程以来,我一直都是属于兴趣驱动的,对某种技术感兴趣的话就会花时间去研究去尝试。想成为一个有趣的人,去做一些有趣的事。

有趣的灵魂

真心觉得能把脑海里的想法转变为代码实现是件很棒的事,即使可能这件事在别人看来并没有什么了不起。技术发展变化总是那么快,不紧跟着可能不小心就掉队了。所以希望每个真心热爱编程的人都能不忘初心,永远保持对新技术的热情,永远能从编码中找到乐趣。

stay real, stay wild

License

MIT ©chenjiandongx

magnet-dht's People

Contributors

chenjiandongx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

magnet-dht's Issues

请问爬取速度很慢是什么问题

Mac系统,安装上了,也能跑起来,但是速度很慢,平均1分钟搜不到1个磁力链。请问是系统问题还是电脑配置问题呢?或者是别的原因?

冬哥你好

请问运行该脚本的硬性条件是必须要有公网IP,关闭防火墙吗?
我在虚拟机试着运行了但是没有反应
系统环境: deepin 15.8 Python3.6 已安装 pip环境

tracker列表中只有最下面的三个可以使用,作者 udp.send_to时 忽略了异常,发送udp数据包的address必须是tuple

BOOTSTRAP_NODES = [
"udp://tracker.open-internet.nl:6969/announce",
"udp://tracker.coppersurfer.tk:6969/announce",
"udp://exodus.desync.com:6969/announce",
"udp://tracker.opentrackr.org:1337/announce",
"udp://tracker.internetwarriors.net:1337/announce",
"udp://9.rarbg.to:2710/announce",
"udp://public.popcorn-tracker.org:6969/announce",
"udp://tracker.vanitycore.co:6969/announce",
"https://1.track.ga:443/announce",
"udp://tracker.tiny-vps.com:6969/announce",
"udp://tracker.cypherpunks.ru:6969/announce",
"udp://thetracker.org:80/announce",
"udp://tracker.torrent.eu.org:451/announce",
"udp://retracker.lanta-net.ru:2710/announce",
"udp://bt.xxx-tracker.com:2710/announce",
"http://retracker.telecom.by:80/announce",
"http://retracker.mgts.by:80/announce",
"http://0d.kebhana.mx:443/announce",
"udp://torr.ws:2710/announce",
"udp://open.stealth.si:80/announce",
("router.bittorrent.com", 6881),
("dht.transmissionbt.com", 6881),
("router.utorrent.com", 6881),
]
tracker列表中只有最下面的三个可以使用,作者 udp.send_to时 忽略了异常,发送udp数据包的address必须是tuple

程序无法正常运行

刚进去便是远程主机强迫关闭了连接 与 #4 类似
或者有几率刚listen完什么都不说就退出了
或者还有可能卡在listen完,什么都不输出,既不抓取链接也不退出

python报错

[root@fox magnet-dht]# python manage.py
Traceback (most recent call last):
File "manage.py", line 6, in
from magnet_dht.crawler import start_server
File "/root/magnet-dht/magnet_dht/crawler.py", line 13, in
from .utils import get_logger, get_nodes_info, get_rand_id, get_neighbor
File "/root/magnet-dht/magnet_dht/utils.py", line 55
yield (nid, ip, port)
SyntaxError: 'return' with argument inside generator
You have new mail in /var/spool/mail/root

如何找到第一个节点的?

您好,作者:
完全去中心化的DHT 是如何寻找第一个节点的?我一直不是很清楚,您可以给我解答一下吗?
此外,我在使用Vuze 这个软件的时候自己上传文件做了种子,然后我自己下载自己的种子,为什么毫无反应,一直在寻找下载资源。敬请指教

无法运行起来了。

tea@instance-1:~/magnet-dht$ python manage.py -s
Traceback (most recent call last):
File "manage.py", line 6, in
from magnet_dht.crawler import start_server
File "/home/tea/magnet-dht/magnet_dht/crawler.py", line 13, in
from .utils import get_logger, get_nodes_info, get_rand_id, get_neighbor
File "/home/tea/magnet-dht/magnet_dht/utils.py", line 55
yield (nid, ip, port)
SyntaxError: 'return' with argument inside generator

yield (nid, ip, port) #迭代器这么写是为了多线程吗?这种写法一直查不到怎么用。

几点建议

项目非常好.很喜欢,感谢作者的贡献.
下载看了下,有几点建议:

  1. 需要配置部分,集中提出来放到一个主目录的配置文件里,方便配置;
  2. tracker部分更改为从https://github.com/ngosang/trackerslist/blob/master/trackers_best.txt动态更新;
  3. bencoder.pyx不支持py3.7,编译需要vc14但是我装了N个版本都编译不成功,是否可以换成其他bencoder模块;
  4. aria2c部分应加入更多配置选项,如token/https等等.
    再次感谢作者的贡献!

一直是这个,怎么回事

2020-07-03 12:06:50,924 - WARNING - not a valid bencoded string
2020-07-03 12:06:51,016 - WARNING - 'DHTServer' object has no attribute 'rc'

作者在peers_request时搜集hash info,导致大量的hash info不可用

def on_get_peers_request(self, msg, address):
"""
处理 get_peers 请求,获取 info hash

    :param msg: 节点报文信息
    :param address: 节点地址
    """
    tid = msg[b"t"]
    try:
        info_hash = msg[b"a"][b"info_hash"]
        self.save_magnet(info_hash)
    except KeyError:
        # 没有对应的 info hash,发送错误回复
        self.send_error(tid, address)

get_peers 消息里的 info_hash 我们可以进行忽略,此时对方也是在查找对应 info_hash 的种子文件,只有收到 announce_peer 消息时的 info_hash 对我们才有用,因为它表示当前对方正在指定端口下载该种子文件的 metadata 信息。

关于项目运行

项目运行到9001端口就走不动了,aria2、redis均已运行。求解答

y

yy

数据库换成sqlite的更简单

扫了几百条磁力链接,没一天可以解析下载的奔溃,还顺道把数据给换了
先建立sqlite数据pip install sqlite

def add_table(tablename,val):#创建数据表
cmd='CREATE TABLE "'+str(tablename)+'" (ID INTEGER PRIMARY KEY AUTOINCREMENT,'+val+')'
cursor.execute(cmd)
print ("ok")
#add_table('magnet','time TEXT NOT NULL,magnet TEXT NOT NULL')

表里2列第一列时间 第二列磁力链接地址 !

更换数据库为sqlite

#!/usr/bin/env python

coding=utf-8

import sqlite3,os,json, time,datetime
basepath = os.path.dirname(file)
#conn = sqlite3.connect("./magnet.db",check_same_thread = False)
#cursor = conn.cursor()

获取当前时间

t = int(time.time())
now_time = datetime.datetime.now()
times=datetime.datetime.strftime(now_time,'%Y-%m-%d %H:%M:%S')

class RedisClient:
def init(self):
self.conn = sqlite3.connect("./magnet.db",check_same_thread = False)
self.cursor = self.conn.cursor()

def add_magnet(self, magnet):
    """
    新增磁力链接
    """
    val='NULL,"'+times+'","'+magnet+'"'
    cmd='INSERT INTO magnet VALUES ( '+val+' )'
    self.cursor.execute(cmd);
    self.conn.commit()
    #self.redis.sadd(REDIS_KEY, magnet)


def get_magnets(self, count=128):
    """
    返回指定数量的磁力链接json.dumps()
    """
    cmd='SELECT magnet from magnet id order by id desc LIMIT 2'
    cursors = self.cursor.execute(cmd)
    result = cursors.fetchall()
    return json.dumps(result)
    #return self.redis.srandmember(REDIS_KEY, count)

从sqliet拿数据去转换

#!usr/bin/python

encoding=utf-8

from http.client import HTTPConnection
import json

from .database import RedisClient

SAVE_PATH = "./torrents"
STOP_TIMEOUT = 60
MAX_CONCURRENT = 16
MAX_MAGNETS = 256

ARIA2RPC_ADDR = "127.0.0.1"
ARIA2RPC_PORT = 6800

rd = RedisClient()

def get_magnets():
"""
获取磁力链接json.loads()return
"""
mgs = json.loads(rd.get_magnets(MAX_MAGNETS))
for m in mgs:
# 解码成字符串
#print (m[0])
#yield str(m[0]).decode('utf-8')
return m[0]

def exec_rpc(magnet):
"""
使用 rpc,减少线程资源占用,关于这部分的详细信息科参考
https://aria2.github.io/manual/en/html/aria2c.html?highlight=enable%20rpc#aria2.addUri
"""
conn = HTTPConnection(ARIA2RPC_ADDR, ARIA2RPC_PORT)
req = {
"jsonrpc": "2.0",
"id": "magnet",
"method": "aria2.addUri",
"params": [
[magnet],
{
"bt-stop-timeout": str(STOP_TIMEOUT),
"max-concurrent-downloads": str(MAX_CONCURRENT),
"listen-port": "6881",
"dir": SAVE_PATH,
},
],
}
conn.request(
"POST", "/jsonrpc", json.dumps(req), {"Content-Type": "application/json"}
)

#res = json.loads(conn.getresponse().read())
print (conn.getresponse().read())
if "error" in 'res':
    print("Aria2c replied with an error:", res["error"])

def magnet2torrent():
"""
磁力转种子
"""
ma=json.loads(rd.get_magnets(MAX_MAGNETS))
for magnet in ma:
print (magnet[0])
exec_rpc(magnet[0])

国内网络

这个在国内是不是不能用?我打开后一直没有反应。
tim 20180707154909

推到服务器也没有反应TuT

大佬好,我按照您的步骤,把这个代码推到了aliyun那个最基础的服务器上,执行后还是没有反应。。(已经安装了环境和依赖)请问这个一定要公网ip才行吗?因为真的一个磁力链接都没有爬到QAQ。。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.