python-qbittorrent+爬虫第二弹:爬取国内某bt站内容、分析页面,批量导入qbittorrent并下载归档

2023-05-16

        书接上文​​​​​​​,说到想批量下载电影,通过一个数据库获取了所有下载内容的链接,所以这个数据库从那里来呢?当然要依靠我们万能的python了,正好我最近在用一个bt站,又很想从上面找日剧看,奈何一个一个搜索下载太麻烦了,更不要说搭建好qbittorrent的webui,然后从nas下载了。

 

         基本架构:用python获取日剧信息,然后从中间获得清晰度最高的种子,然后传输到局域网的nas下载。

        

        先来看看爬虫的核心部分吧~后面有源码!

        首先当然是打开搜索页面,发现即使按照日本+日语两个关键词搜索,仍然会有007这样的电影混进其中,因此需要改进,改进方法就是从html中抓取是否包含“语     言 日语”以及“地     域 日本”这样的关键词。第一个部分的源代码如下:

import requests
import re
import time
import random


def getdetail(file, id):
    """
    分析详情页函数
    :param file: 详情页html文件对象
    :return: 一个字典,包含id、译名、清晰度信息、其他版本id、带passkey的url,如果不是日剧就返回空
    """
    with open('log.txt', 'r', encoding='utf8') as logfile:
        logtext = logfile.read()
    if logtext.find(f"'id': {str(id)}") != -1:
        print('getted!:', id)
        return
    return_dic = {
        'id': id,
        'name': '',
        'res': '',
        'url': '',
        'other': []
    }
    text = file.read()
    if text.find('产  地 日本') == -1 or text.find('语  言 日语') == -1:
        return
    res_re = re.compile('<b>分辨率:&nbsp;</b>(.*?)[pi]')
    try:
        return_dic['res'] = int(res_re.findall(text)[0])
    except:
        return_dic['res'] = 0
    other_re = re.compile('a href="https://www\.hdarea\.co/details\.php\?id=(.*?)&amp;hit=1"')
    return_dic['other'] = other_re.findall(text)
    name_re = re.compile('译  名 (.*?)<')
    name_list = name_re.findall(text)
    if name_list:
        if name_list[0].find('/') != -1:
            return_dic['name'] = name_list[0][:name_list[0].find('/')]
        else:
            return_dic['name'] = name_list[0]
    else:
        bad_name = re.compile('">副标题</td><td class="rowfollow" valign="top" align="left">(.*?)</td></tr>').findall(text)[0]
        return_dic['name'] = bad_name[:bad_name.find('/')]

    return_dic['url'] = f'https://www.hdarea.co/download.php?id={str(id)}&passkey=你的passkey~(还想看我的??)'
    print(return_dic)
    with open('log.txt', 'a+') as logfile:
        logfile.write(str(return_dic)+'\n')

        下面详细介绍一下代码的每个部分在干什么:

        输入一个html文件读取后的文件对象,以及这个页面对应的id

        首先定义了一个return_dic的格式,从详情页分析会拿到id、译名、清晰度信息、其他版本id、带passkey的url,如果不是日剧就返回空

        所以第一步自然是用刚刚订好的筛选条件看看是不是日剧,不是就可以下一个文件了。

        第二步是用正则表达式尝试匹配一下清晰度,考虑到同时有1080p和1080i,咱们都要匹配上,如果不是按照这样格式写的(反正也不是很多),就给个0吧。随后调试过程中还发现,有一些格式写得很奔放,咱也看不懂但是就是不能这么比,但是会让我们的程序报错,那就给个try吧。

        之后就是简单地字符串处理,用正则表达式匹配译名等信息(如果译名匹配不到就直接拿它的副标题),用来当作文件夹的名字,随后观察下载的url那一行,把相应的url给拼接好【我也是刚刚知道bt站给的这种https链接中决定下载的文件是什么的唯一凭证居然是那个唯一的id】

        最后把它写到一个log里面,后续需要批量加入到qbittorrent,只需要连接好webui直接用这个log文件就可以了。

       

        这段代码等于是整个工作的第二个部分,完成之后还有两个工作:第一个是获取这个getdetail函数中所需要的html文件,可以爬虫一下,然后抓取所有类似于链接的url,提取中间的id方便通信,第二个是读取log.txt,然后加入合适的量下载(一次下多了就怕分享率炸了),但是剩下的没有什么太多技术含量,所以就直接把所有文件的源码摆上来,之后再慢慢聊:

# hdarea_detail.py

import requests
import re
import time
import random


def getdetail(file, id):
    """
    分析详情页函数
    :param file: 详情页html文件对象
    :return: 一个字典,包含id、译名、清晰度信息、其他版本id、带passkey的url,如果不是日剧就返回空
    """
    with open('log.txt', 'r', encoding='utf8') as logfile:
        logtext = logfile.read()
    if logtext.find(f"'id': {str(id)}") != -1:
        print('getted!:', id)
        return
    return_dic = {
        'id': id,
        'name': '',
        'res': '',
        'url': '',
        'other': []
    }
    text = file.read()
    if text.find('产  地 日本') == -1 or text.find('语  言 日语') == -1:
        return
    res_re = re.compile('<b>分辨率:&nbsp;</b>(.*?)[pi]')
    try:
        return_dic['res'] = int(res_re.findall(text)[0])
    except:
        return_dic['res'] = 0
    other_re = re.compile('a href="https://www\.hdarea\.co/details\.php\?id=(.*?)&amp;hit=1"')
    return_dic['other'] = other_re.findall(text)
    name_re = re.compile('译  名 (.*?)<')
    name_list = name_re.findall(text)
    if name_list:
        if name_list[0].find('/') != -1:
            return_dic['name'] = name_list[0][:name_list[0].find('/')]
        else:
            return_dic['name'] = name_list[0]
    else:
        bad_name = re.compile('">副标题</td><td class="rowfollow" valign="top" align="left">(.*?)</td></tr>').findall(text)[0]
        return_dic['name'] = bad_name[:bad_name.find('/')]

    return_dic['url'] = f'https://www.hdarea.co/download.php?id={str(id)}&passkey=你自己的id~~~~~~~~'
    print(return_dic)
    with open('log.txt', 'a+', encoding='utf8') as logfile:
        logfile.write(str(return_dic)+'\n')
    # print(text)

def random_sleep(length):
    real_length = length + random.randint(-1000,1000) / 1000
    time.sleep(real_length)


if __name__ == '__main__':

    path = ''
    with open(path+'detail.html', encoding='utf8') as file:
        getdetail(file, 51665)
# hdarea_search.py

import requests
import re
import time
import random
from hdarea_detail import getdetail, random_sleep


def get_urls(file):
    """
    输入搜索页file对象,返回所有下载url的id
    :param file:
    :return:
    """
    return_list = []
    text = file.read()
    urls_re = re.compile('<a href="details\.php\?id=(.*?)&amp;hit=1&amp;')
    urls_re.findall(text)
    urls_re_return = urls_re.findall(text)
    for url in urls_re_return:
        if url not in return_list:
            return_list.append(url)
    print(return_list)
    print(len(return_list))
    return return_list

def get_all_info():

    header = {
        'Cookie': '你自己的cookie',
        'authority': 'www.hdarea.co',
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Safari/605.1.15'
    }

    path = ''
    with open(path+'search.html', 'r', encoding='utf8') as file:
        urls_list = get_urls(file)
    for id in urls_list:
        url = f'https://www.hdarea.co/details.php?id={str(id)}&hit=1'
        page = requests.get(url, headers=header)
        with open('detail.html', 'w', encoding='utf8') as detailfile:
            detailfile.write(page.text)
        with open('detail.html', 'r', encoding='utf8') as file:
            getdetail(file, int(id))
        random_sleep(1)


if __name__ == '__main__':
    get_all_info()
# hdarea.py

import requests
from hdarea_search import get_all_info
from hdarea_detail import random_sleep

header = {
    'Cookie': '你的cookie',
    'authority': 'www.hdarea.co',
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Safari/605.1.15'
}

for i in range(0, 36):
    url = f'你在该站点搜索需要的内容的时候上面的url'
    page = requests.get(url, headers=header)
    print(url)
    with open('search.html', 'w', encoding='utf8') as detailfile:
        detailfile.write(page.text)
    get_all_info()
    random_sleep(5)
# hdarea_qbittorrent.py

from qbittorrent import Client
import time


def connect_to_qbit():
    qb = Client('你的qbittorrent地址')

    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


def get_biggest(log_dic, id_num):
    """
    :param log_dic: 处理完成的id:信息 字典
    :param id_num: 待查找的id
    :return: 返回同类文件中清晰度最高的id
    """
    if not log_dic[id_num]['other']:
        return id_num
    else:
        biggest_res = -1
        return_id_num = 0
        for other_id_num in log_dic[id_num]['other']:
            try:
                if log_dic[other_id_num]['res'] > biggest_res:
                    return_id_num = other_id_num
            except:
                pass
        return return_id_num


def log_file_init():
    """
    :return:读取log.txt文件并将内容初始化成为id:内容的字典
    """
    log_list = []
    with open('log.txt', 'r', encoding='utf8') as file:
        lines = file.readlines()
        for line in lines:
            log_list.append(eval(line))
    log_dic = {}
    for log in log_list:
        log_dic.update({log['id']: log})
    return log_dic
    # 读入log文件,并将id作为字典的key,信息作为字典的值


def qbit_download(qb, log_keyarg, id_num):
    """
    :param qb: qb的client对象
    :param log_keyarg: 记录信息的字典
    :param id_num: 信息的id
    :return: no
    """
    savepath = f'/share/CACHEDEV4_DATA/movie/{log_keyarg["name"]}'  # 这是我希望的在nas内的存储位置
    qb.download_from_link(log_keyarg['url'], savepath=savepath)
    localtime = time.asctime(time.localtime(time.time()))
    with open('dl_log.txt', 'a', encoding='utf8') as dl_log_file:
        dl_log_file.write(str(id_num) + str(localtime) + '\n')
    print(f'download:{id_num}, time:{localtime},')


def qbit_main(start=0, end=0):
    qb, torrents = connect_to_qbit()
    log_dic = log_file_init()
    s = 0
    for id_num in log_dic.keys():
        if s < start:
            s += 1
            continue
        if id_num == get_biggest(log_dic, id_num):  # 这条就是最清楚的,可以下载!
            qbit_download(qb, log_dic[id_num], id_num)
        s += 1
        print(f'第{s}条任务:', log_dic[id_num])
        if s == end:
            break

if __name__ == '__main__':
    # qb, torrents = connect_to_qbit()
    qbit_main(0, 40)

每个文件实现的功能:

hdarea.py项目的最终main文件,在获得了log之后会控制直接读取log内的内容并将下载任务传到qbit的网页端
hdarea_search.py实现从搜索页提取详情页的功能,简单分析页面就可以写出来
hdarea_detail.py实现从详情页提取关键信息并输出到log文件的过程
hdarea_qbittorrent.py实现将下载任务传到qbit的网页端的过程

值得注意的是源代码中我隐藏了部分信息:

        一个是cookie,读者们注册完bt站之后访问可以从开发者选项中看到本次请求的cookie,把自己的cookie换过来就好,注意不要被其他人看到啦~

        另外一个就是torrent站的passkey,这个非常非常重要!它是torrent站识别身份的唯一信息,也就是说是谁在上传下载,纯靠这个passkey判定,如果被别人知道了,别人大概会拿你的账户猛下东西,你如果没来得及重制passkey,你大概就可以准备新账号了。

        第三个是看似没有那么重要的qbit的webui的账号密码,别人最多使用你的qbit客户端,但是之前有通过qbit客户端入侵机器锁定文件然后勒索的先例,也请大家注意不要泄露出去啦~

如果有源码使用和优化、以及其余问题欢迎直接在评论区交流~

封面

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python-qbittorrent+爬虫第二弹:爬取国内某bt站内容、分析页面,批量导入qbittorrent并下载归档 的相关文章

  • 7月编程排行榜来啦!这次有何新变化?

    每月编程排行榜可能会迟到 xff0c 但永远不缺席 7月的编程排行榜已出 xff0c 接下来一起看看有哪些看点吧 Tiobe编程排行榜前20名 Tiobe编程排行榜Top 10趋势 TIOBE Index编程社区指数是编程语言流行度的一个指
  • 操作系统 记录型信号量实现生产者消费者问题(完整代码)

    问题描述 用信号量模拟生产者 消费者问题的过程 生产者和消费者两个线程共享同一个缓冲区 xff0c 生产者不断向缓冲区中添加产品 xff0c 消费者从缓冲区中消费产品 要保证缓冲区满了之后生产者不能再继续添加产品 xff0c 需要等消费者至
  • 制版经验分享—使用AD18

    文章目录 前言一 封装二 走线三 注意细节四 制版流程五 制版细节总结 前言 在做一些培训题目时 xff0c 由于时间有限制 xff0c 在外面开板会花费好几天的制作和快递时间 xff0c 所以有时候就需要自己制版 xff0c 在这里我记录
  • Java打印九九乘法表

    1 使用双重for循环打印九九乘法表 Java源代码如下 xff1a for int i 61 0 i lt 61 9 i 43 43 for int j 61 1 j lt 61 i j 43 43 System out print i
  • 解决selenium打开Chrome浏览器自动退出的问题

    好不容易安装好selenium和对应的浏览器驱动器后终于可以运行程序了 xff0c 结果发现一运行程序后浏览器打开就自动退出了 xff0c 但是我在Python代码中并没有写driver quit 方法 xff0c 上网查了查发现原来是我的
  • 在Java应用中嵌入sshd服务

    这个应用需要依赖apache mina的子项目sshd xff0c 项目主页http mina apache org sshd project index html xff0c 当前版本号为0 8 0 这里的sshd和Linux下的sshd
  • openssl开发库安装时的踩坑指南

    序 前几天用linux编译一个提权脚本的时候报错 openssl opensslv h 没有那个文件或目录 的问题 无论如何也解决不了 xff0c 这下我记录一个踩坑指南防止下一个人掉进坑里 操作 总体介绍 首先介绍一下 xff0c 这个报
  • 性能测试脚本用例【模板】

    产品名称Product name 密级Confidentiality level 秘密 产品版本Product version Total 12pages 共12页 性能测试脚本用例 仅供内部使用 拟制 日期 xff1a 审核 日期 xff
  • Java常见的集合类

    我们常见的Java集合类有List Set Map List 1 接口可以被继承 2 接口可以被多次实现 3 List和ArrayList package List import java util ArrayList import jav
  • WIN7我的电脑右键管理打不开

    问题现象 xff1a 我的电脑右键点击管理无法正常打开 xff0c 会弹出下面的报错信息 首先打开注册表 xff0c 打开运行 xff0c 输入regedit 选择路径 xff1a HKEY LOCAL MACHINE SOFTWARE C
  • LIKE的用法

    我们来谈谈关于like运算符的理解 xff1a 下面是like的语法 xff0c 以后使用到like运算符的都必须根据这个语法使用 LIKE 运算符是用来匹配通配符指定模式的文本值 如果搜索表达式与模式表达式匹配 xff0c LIKE 运算
  • 从0开始详细安装archlinux(UEFI启动)

    隔了一周没更新 xff0c 前阵子把电脑windows卸了装了个archlinux xff0c 不得不说arch是真的香 xff0c 但是坑也是真的多 xff0c 刚踩完所有的坑 xff0c 滚回来写blog了 注 xff1a 本贴为UEF
  • archlinux开机无法联网问题,以及安装archlinuxcn和yay管理器

    前一篇已经安装完了archlinux系统 xff0c 不过真正难的其实并不是安装 xff0c 你的路现在才开始 xff0c 哈哈 添加用户 建议 xff0c 不然使用登录管理器的时候不支持root用户 span class token fu
  • archlinux安装kde桌面和sddm登录管理器

    前几篇已经配置好了archlinuxcn软件仓库 xff0c 网络和nvidia驱动 xff0c 现在来给你的archlinux安装一个kde桌面 xff08 kde玩法有很多 xff0c 可以自己去搜一搜美化教程 xff09 xff0c
  • Spring框架学习

    目录 目录 学习内容 xff1a IoC java中创建对象有哪些方式 xff1a ioc的体现 xff1a DI 是ioc的技术实现 spring的第一个核心功能 ioc Spring 八大模块 Spring的特点 xff1a Sprin
  • CenOs6.7不能使用yum命令

    因为官方不维护了所以 先用更换源 wget O etc yum repos d CentOS Base repo https mirrors aliyun com repo Centos vault 6 10 repo https deve
  • PowerMock注解PowerMockIgnore的使用方法

    故事要从一个异常开始 xff0c 某天我在开发一个加密 解密特性 xff0c 算法使用的是3DES xff0c 样例代码如下 package org jackie study powermock import java io Unsuppo
  • 如何写一棵AVL树

    二叉查找树 二叉查找树有一个缺陷就是查询效率跟树的高度有关 在极端情况下 xff0c 查询效率为n 如何解决二叉查找树效率低问题 xff1f 要增加查询效率 xff0c 高效的方案是在插入的时候对树进行一下平衡操作 xff0c 降低树的高度
  • 点击超链接下载.pdf文件

    上代码 span class token keyword package span span class token class name Servlet span span class token punctuation span res
  • SpringTemplate增删改查及其事务控制基本使用

    一 JdbcCRUD操作 1 导入坐标包 span class token generics span class token punctuation lt span dependency span class token punctuat

随机推荐