最近因为一些需求,爬了一个带有magnet磁力链接的网站(如果有对怎么爬感兴趣可以说一声,这个文章基本只是为了当成自己的学习记录用哒,也会基于爬完的数据库开始做下一步),大致的结构是每个影片有自己的名字和他人分享的一系列magnet链接,需要批量下载这些磁力链接到本地然后归档。作为一个业余程序员当然不能直接一个一个手动下载了。于是就考虑用python来简化这个工作。

        经过测试发现这一系列magnet中有的是连接不上的(用qbittorrent会一直卡在检索元数据的位置),但是对于同一个影片显然我只需要找到一个可用的资源,也就是获得一个下载最快的magnet就可以。每次进行手动比对、调整保存的路径非常麻烦,于是就通过python-qbittorrent来解决这个问题~

        python-qbittorrent库的pypi和文档都是英文的,这一页的底部点击Read the docs可以直接跳转到官方文档。啃了半天才看懂,基本过程如下:

        首先安装python-qbittorrent库:用经典的pip安装就可以,也可以在pycharm里面找到并安装。

pip install python-qbittorrent

        之后是安装对应系统版本的qbittorrent软件,我写代码用的电脑是mac,所以去搜mac的qbittorrent安装即可,随后需要对软件进行一些设置。

        必要设置:点击qbittorrent上面菜单栏的齿轮,找到首选项里面的Web用户界面,如果需要远程则根据ip地址和服务器域名相应设置,我暂时不需要,则只需要设置下面的本地验证,可以选择账号密码,默认是admin/admin,也可以选择对于本地主机上的客户端跳过验证。

        之后为了个人的功能的实现,在连接选项卡中设置了全局最大连接数和每torrent最大连接数为100。

        使用的时候定义了一个函数如下:

from qbittorrent import Client

def connect_to_qbit():
    qb = Client('http://127.0.0.1:8080/', verify=False)

    qb.login('我的用户名', '我的密码')
    # not required when 'Bypass from localhost' setting is active.
    # defaults to admin:admin.
    # to use defaults, just do qb.login()

    torrents = qb.torrents()
    return qb, torrents

        对于这里的qb和torrents的理解:qb事实上是Client的连接,而torrents是执行torrents=qb.torrents()的时候,qbittorrent客户端内存在的所有任务构成的元组。元组内的每一个元素是一个字典,对应着一个任务的相关信息,个人认为比较关键的信息如下:

字典的key

对应的内容信息

size

种子对应内容的大小

dlspeed

种子的当前下载速度(B为单位)

hash

种子的hash值,也就是magnet:?xt=urn:btih:后面的东西

magnet_uri

种子的完整magnet

progress

种子当前的进度,完成了多少(全部下载完是1)

        另外就是几个比较容易用到的函数:

qb = Client('http://127.0.0.1:8080/', verify=False)
# 连接qb客户端

qb.login('hashiro', '121609103')
# 登陆qb客户端

torrents = qb.torrents()
# 获取任务列表

qb.download_from_link(magnets, savepath=savepath)
# 通过magnet下载,可以传输多个magnet构成的列表,保存在savepath里面,download_from_file是从文件读取magnet。

qb.delete_permanently(hash)
# 通过种子的hash值删除任务以及源文件

qb.delete(hash)
# 通过种子的hash值删除任务

qb.delete_all()
# 删除所有任务

qb.delete_all_permanently()
# 删除所有任务以及源文件

        随后根据我的需求:

import pymysql, time, os, shutil
from qbittorrent import Client

def connect_to_cloud_sql():
    try:
        # 连接数据库
        conn = pymysql.connect(
            host='xxx.xxx.xxx.xxx',
            port=6001,
            user='root',
            password='我的密码',
            db='数据库的名字',
            charset='utf8'
        )
        cur = conn.cursor()
        return conn, cur
    except Exception as e:
        print(e)
        pass

def connect_to_qbit():
    qb = Client('http://127.0.0.1:8080/', verify=False)

    qb.login('我的qb用户名', '我的qb密码')

    # not required when 'Bypass from localhost' setting is active.
    # defaults to admin:admin.
    # to use defaults, just do qb.login()

    torrents = qb.torrents()
    return qb, torrents

def new_dl_symbol():
    torrents = qb.torrents()
    s = 0
    for torrent in torrents:
        s += torrent['dlspeed']
    print('目前下载速度:',s/1000000, 'MB/S')
    if s > 7000000: # 因为我的网速就10MB左右,所以大于7MB了之后就等它下载一会儿,再准备新的种子
        return False
    else:
        return True

class DownloadVideo:
    _path = '保存地址的绝对路径'

    def __init__(self, info_dic):
        self.code = info_dic[0]
        self.name = info_dic[1]
        sql = 'SELECT magnet FROM magnet WHERE code="'+self.code+'"'
        cur.execute(sql)
        self.magnets = [i[0] for i in cur.fetchall()]
        self.magnet_hashs = [magnet[magnet.find('btih:')+5:magnet.find('&')].lower() for magnet in self.magnets]
        self.hashs = []
        self.savepath = self._path + str(self.code) + '/'
        if not os.path.exists(self.savepath):
            os.mkdir(self.savepath)
        self.final_magnet = []

    def download(self):
        if self.magnets == []:
            print('该code没有合适的url!')
            return 3
        qb.download_from_link(self.magnets, savepath=self.savepath)
        print('测试下载速度中……')
        time.sleep(120)
        biggest = 0
        biggest_hash = ''
        self.torrents = qb.torrents()
        for torrent in self.torrents:
            if torrent['hash'] in self.magnet_hashs and biggest < torrent['dlspeed'] and torrent['size'] > 400000000:
                biggest = torrent['dlspeed']
                biggest_hash = torrent['hash']
                self.final_magnet = torrent['magnet_uri']
                self.final_hash = torrent['hash']

        if biggest == 0: # 如果在60秒之内没有发现有下载速度的,就把元数据都找不到的臭弟弟magnet删掉,留下有size的试试
            try_symbol = False
            for torrent in self.torrents:
                if torrent['hash'] in self.magnet_hashs and (torrent['size'] == 0 or try_symbol):
                    qb.delete_permanently(torrent['hash'])
                elif torrent['hash'] in self.magnet_hashs:
                    try_symbol = True
                    if not os.path.exists(self.savepath):
                        os.mkdir(self.savepath)
                    with open(self.savepath + 'log.txt', 'w') as file:
                        file.write('try: '+ torrent['magnet_uri']+'\n')
                    self.final_magnet = torrent['magnet_uri']
                    self.final_hash = torrent['hash']

            if try_symbol:
                print(self.code + ':没有找到有速度的下载数据,写入日志文件……')
                return 1
            else:
                print(self.code + ':没有找到能解析的元数据,写入日志文件……')
                return 2

        for torrent in self.torrents:  # 把比最快的magnet慢的任务都删除
            if torrent['hash'] in self.magnet_hashs and torrent['hash'] != biggest_hash:
                qb.delete_permanently(torrent['hash'])
        if not os.path.exists(self.savepath):
            os.mkdir(self.savepath)
        with open(self.savepath + 'log.txt', 'w') as file:
            file.write(self.final_magnet)
            print('下载magnet:'+self.final_magnet)
        return 0


if __name__ == '__main__':
    nm_path = 'no_mosaic_log/'
    conn, cur = connect_to_cloud_sql()
    qb, torrents = connect_to_qbit()

    sql = 'SELECT code, name, mosaic FROM info WHERE mosaic=0'
    cur.execute(sql)
    result = cur.fetchall()
    print(result)

    dl_list = []
    s = -1
    while s < len(result)-1:
        time.sleep(5)
        if not new_dl_symbol():
            print('下载速度超限!等待完成中……')
            continue
        s += 1
        new_dl = DownloadVideo(result[s])
        dl_list.append(new_dl_av)
        print('---------------------------------第'+str(s+1)+'个文件:'+result[s][0]+'------------------------------')
        print('name:'+ result[s][1])
        with open(DownloadVideo._path+'log.txt', 'a') as logfile:
            code = new_dl.download()
            if code == 0:
                logfile.write('0: ' + result[s][0] + '\n')
            elif code == 1:
                logfile.write('1: ' + result[s][0] + '\n')
            elif code == 2:
                logfile.write('2: ' + result[s][0] + '\n')
            elif code == 3:
                logfile.write('3: ' + result[s][0] + '\n')
        torrents = qb.torrents()


    for torrent in torrents:
        for torrent_info in torrent.keys():
            print(torrent_info, '    ', torrent[torrent_info])
        print('--------------')
    cur.close()
    conn.close()

        代码结构的基本解释:

        首先查询信息数据库,在info的数据库里面获得code,根据code去magnet数据库里面查询需要的磁力链接,若数据库未检索到该code的磁力链接,就将编号3记录在log中。如果此时下载速度低于7MB/s,就将所有磁力链接加入torrent客户端的下载列表,等待两分钟:若已经有magnet有下载速度,就删除其他的任务并记录为0,若没有下载速度,则挑选一个检测到了size(检测到size意味着检测到了元数据)的任务继续,其余删除,记录1。若所有的magnet都没有检测到元数据,就记录2。

python下载种子文件 python下载bt_数据库

        随后观察到了正常运作啦!有小姐姐了~