PyQt5+爬虫打造磁力链接搜索工具

PyQt5结合爬虫制作一个磁力链接搜索工具的可视化界面,具体效果如下图所示,输入框内输入要搜索的内容,点击搜索按钮,下面的大框内显示搜索结果,双击搜索结果可以自动调用电脑上的迅雷下载,清除按钮用来清除搜索结果。


在这里插入图片描述

1. GUI设计

使用QT designer设计该界面,新建一个widget窗口,把控件从左边拖进来摆放好位置,这里主要用到三个控件,分别是LineEdit、PushButton以及ListWidget。在这里插入图片描述
界面设计好后保存到本地,会有一个.ui文件的产生,我们需要把这个文件转换为.py文件,在.ui文件目录下打开终端,输入pyuic5 -o magnet_serach_ui.py magnet_serach.ui即可,其中的ui文件是designer保存下来的,py文件时转换后我们需要用的文件。
magnet_serach_ui.py:

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'magnet_search.ui'
#
# Created by: PyQt5 UI code generator 5.13.0
#
# WARNING! All changes made in this file will be lost!


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(700, 300)
        Form.setMinimumSize(QtCore.QSize(700, 300))
        Form.setMaximumSize(QtCore.QSize(16777215, 300))
        self.verticalLayout = QtWidgets.QVBoxLayout(Form)
        self.verticalLayout.setSpacing(0)
        self.verticalLayout.setObjectName("verticalLayout")
        self.frame = QtWidgets.QFrame(Form)
        self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame.setObjectName("frame")
        self.horizontalLayout = QtWidgets.QHBoxLayout(self.frame)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.lineEdit = QtWidgets.QLineEdit(self.frame)
        self.lineEdit.setMinimumSize(QtCore.QSize(0, 30))
        font = QtGui.QFont()
        font.setPointSize(12)
        self.lineEdit.setFont(font)
        self.lineEdit.setClearButtonEnabled(True)
        self.lineEdit.setObjectName("lineEdit")
        self.horizontalLayout.addWidget(self.lineEdit)
        self.pushButton = QtWidgets.QPushButton(self.frame)
        self.pushButton.setMinimumSize(QtCore.QSize(0, 30))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(12)
        self.pushButton.setFont(font)
        self.pushButton.setObjectName("pushButton")
        self.horizontalLayout.addWidget(self.pushButton)
        self.pushButton_2 = QtWidgets.QPushButton(self.frame)
        self.pushButton_2.setMinimumSize(QtCore.QSize(0, 30))
        font = QtGui.QFont()
        font.setFamily("宋体")
        font.setPointSize(12)
        self.pushButton_2.setFont(font)
        self.pushButton_2.setObjectName("pushButton_2")
        self.horizontalLayout.addWidget(self.pushButton_2)
        self.verticalLayout.addWidget(self.frame)
        self.frame_2 = QtWidgets.QFrame(Form)
        self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_2.setObjectName("frame_2")
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.frame_2)
        self.horizontalLayout_2.setContentsMargins(-1, 0, -1, -1)
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.listWidget = QtWidgets.QListWidget(self.frame_2)
        self.listWidget.setObjectName("listWidget")
        self.horizontalLayout_2.addWidget(self.listWidget)
        self.verticalLayout.addWidget(self.frame_2)
        self.verticalLayout.setStretch(0, 1)
        self.verticalLayout.setStretch(1, 8)

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Form"))
        self.pushButton.setText(_translate("Form", "搜索"))
        self.pushButton_2.setText(_translate("Form", "清除"))

2. 通过爬虫爬取磁力链接

首先我们新建一个spider.py,导入xpath和requests库,并定义一个MagnetSpider类。

from lxml import etree
import requests

class MagnetSpider(object):
    def __init__(self, url):
    	# 设置请求头模拟浏览器
        self.header = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'}
        # 我们要爬取的网址
        self.url = url  # https://findcl.com

复制上面的网址打开,在搜索框中随便搜索几个东西,在这里插入图片描述
在这里插入图片描述
我们发现地址栏都是https://findcl.com/list?q=“你输入的内容”,是有规律的,我以复仇者联盟4为例,在GUI中搜索结果的每一栏标题以[文件名][文件大l类型][文件大小]命名,所以,需要爬取的内容如下图红框所示。在这里插入图片描述
在该界面按F12打开开发者工具,点击开发者工具左上角的图标,再点击需要爬取的内容,底部网页源代码便可以直接定位到该内容,
在这里插入图片描述
在底部网页源代码的红框部分右击鼠标选择copy,再选择copy xpath,复制出来可以看到以下内容:

//*[@id="app"]/div[1]/div[2]/div[1]/div[1]/div[2]/div[1]/div[2]

这个xpath语法只是定位得到了这一整行内容,我们只需要获取其中的黑色文本内容,即复仇者联盟4:终局之战.Avengers.Endgame.2019.1080p.WEB-DL.DD5.1.H264-中英双字-RARBT,所以我们需要在最后加上/text()来获取该内容,完整语法如下:

//*[@id="app"]/div[1]/div[2]/div[1]/div[1]/div[2]/div[1]/div[2]/text()

该页面的文件大小,文件类型以及磁力链接的获取方式如出一辙,因此可以在MagnetSerach类中添加一个函数,获取单个文件的信息:

    def _get_one_info(self, _url):
        '''获取单个文件的标题和磁力链接'''
        # resquests.get得到网页内容
        reponse = requests.get(_url, headers=self.header)
        # xpath解析网页内容
        html = etree.HTML(reponse.text)
        try:
            # 获取磁力链接
            magnet = html.xpath('//*[@id="app"]/div[1]/div[2]/div[1]/div[2]/div[2]/code/text()')[0]
        except IndexError:
            magnet = '磁力链接获取失败'
        # 获取文件类型
        file_type = html.xpath('//*[@id="app"]/div[1]/div[2]/div[1]/div[1]/div[2]/div[3]/div[2]/text()')[0]
        # 获取文件大小
        file_size = html.xpath('//*[@id="app"]/div[1]/div[2]/div[1]/div[1]/div[2]/div[2]/div[2]/text()')[0]
        # 字节型转换为GB
        file_size = (int(file_size)/(1024**3))
        try:
            # 获取资源名称
            file_title = html.xpath('//*[@id="app"]/div[1]/div[2]/div[1]/div[1]/div[2]/div[1]/div[2]/text()')[0]
        except IndexError:
            file_title = '文件名获取失败'
        # 拼接标题
        title = '[{}][{}][{:.1f}GB]'.format(file_title, file_type, file_size)
        return title, magnet

现在我们将网站回退到上一页,如下所示,刚刚是获取的第一条资源的信息,现在我们需要得到整页资源的信息。首先获取到该页面下的所有资源的链接,再使用刚刚编写的_get_one_info函数遍历所有链接便得到了整页的资源名称和标题。
在这里插入图片描述
每一条资源链接获取和上面的方式一样,使用开发者工具左上角的图标点击网页中的名称。
在这里插入图片描述
在MagnetSpider类中继续添加一个函数:

    def _get_one_page_all_file_url(self, _url):
        '''获取一页的文件链接'''
        # 定义一个空列表存放整页资源链接
        one_page_files_url = []
        reponse = requests.get(_url, headers=self.header)
        html = etree.HTML(reponse.text)
        # 获取该页有多少条资源
        one_page_num = len(html.xpath('//*[@id="app"]/div[1]/div[2]/div/div[1]/ul/li'))
        # for循环将每一条资源链接添加进列表
        for i in range(one_page_num):
            one_url = html.xpath('//*[@id="app"]/div[1]/div[2]/div/div[1]/ul/li[%d]/a//@href'%(i+1))[0]
            one_url = r'https://findcl.com' + one_url
            one_page_files_url.append(one_url)
        return one_page_files_url

同理,上面获取了一页的链接,接下来需要获取所有页的资源链接,原理和上面类似,主要通过“下一页”按钮是否可用来得到所有页的信息:

    def _get_all_pages_url(self, _url):
        '''获取所有页的链接'''
        pages_url = []
        pages_url.append(_url)
        temp_url = _url
        while True:
            # 这里为1意味着只获取第一页的链接,把下面两行注释了就获取所有页的链接
            if len(pages_url) >= 1:
                break
            reponse = requests.get(temp_url, headers=self.header)
            html = etree.HTML(reponse.text)
            next_page_idx = len(html.xpath('//*[@id="app"]/div[1]/div[2]/div/div[1]/div/ul/li'))
            try:
                next_page_url = html.xpath('//*[@id="app"]/div[1]/div[2]/div/div[1]/div/ul/li[%d]/a//@href'%next_page_idx)[0]
                next_page_url = r'https://findcl.com' + next_page_url
            except IndexError:
                break
            pages_url.append(next_page_url)
            temp_url = next_page_url
        # print(pages_url)
        return pages_url

接下来写一个run函数调用上面的方法:

    def run(self):
        magnets = []
        titles = []
        pages_url = self._get_all_pages_url(self.url)
        for page_url in pages_url:
            one_page_files_url = self._get_one_page_all_file_url(page_url)
            for one_page_file_url in one_page_files_url:
                title, magnet = self._get_one_info(one_page_file_url)
                titles.append(title)
                magnets.append(magnet)
        return titles, magnets

spider.py全部代码:

from lxml import etree
import requests


class MagnetSpider(object):
    def __init__(self, url):
        self.header = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'}
        self.url = url  # https://findcl.com

    def run(self):
        magnets = []
        titles = []
        pages_url = self._get_all_pages_url(self.url)
        for page_url in pages_url:
            one_page_files_url = self._get_one_page_all_file_url(page_url)
            for one_page_file_url in one_page_files_url:
                title, magnet = self._get_one_info(one_page_file_url)
                titles.append(title)
                magnets.append(magnet)
        return titles, magnets

    def _get_all_pages_url(self, _url):
        '''获取所有页的链接'''
        pages_url = []
        pages_url.append(_url)
        temp_url = _url
        while True:
            # 这里为1意味着只获取第一页的链接,把下面两行注释了就获取所有页的链接
            if len(pages_url) >= 1:
                break
            reponse = requests.get(temp_url, headers=self.header)
            html = etree.HTML(reponse.text)
            next_page_idx = len(html.xpath('//*[@id="app"]/div[1]/div[2]/div/div[1]/div/ul/li'))
            try:
                next_page_url = html.xpath('//*[@id="app"]/div[1]/div[2]/div/div[1]/div/ul/li[%d]/a//@href'%next_page_idx)[0]
                next_page_url = r'https://findcl.com' + next_page_url
            except IndexError:
                break
            pages_url.append(next_page_url)
            temp_url = next_page_url
        # print(pages_url)
        return pages_url

    def _get_one_page_all_file_url(self, _url):
        '''获取一页的文件链接'''
        # 定义一个空列表存放整页资源链接
        one_page_files_url = []
        reponse = requests.get(_url, headers=self.header)
        html = etree.HTML(reponse.text)
        # 获取该页有多少条资源
        one_page_num = len(html.xpath('//*[@id="app"]/div[1]/div[2]/div/div[1]/ul/li'))
        # for循环将每一条资源链接添加进列表
        for i in range(one_page_num):
            one_url = html.xpath('//*[@id="app"]/div[1]/div[2]/div/div[1]/ul/li[%d]/a//@href'%(i+1))[0]
            one_url = r'https://findcl.com' + one_url
            one_page_files_url.append(one_url)
        return one_page_files_url

    def _get_one_info(self, _url):
        '''获取单个文件的标题和磁力链接'''
        # resquests.get得到网页内容
        reponse = requests.get(_url, headers=self.header)
        # xpath解析网页内容
        html = etree.HTML(reponse.text)
        try:
            # 获取磁力链接
            magnet = html.xpath('//*[@id="app"]/div[1]/div[2]/div[1]/div[2]/div[2]/code/text()')[0]
        except IndexError:
            magnet = '磁力链接获取失败'
        # 获取文件类型
        file_type = html.xpath('//*[@id="app"]/div[1]/div[2]/div[1]/div[1]/div[2]/div[3]/div[2]/text()')[0]
        # 获取文件大小
        file_size = html.xpath('//*[@id="app"]/div[1]/div[2]/div[1]/div[1]/div[2]/div[2]/div[2]/text()')[0]
        # 字节型转换为GB
        file_size = (int(file_size)/(1024**3))
        try:
            # 获取资源名称
            file_title = html.xpath('//*[@id="app"]/div[1]/div[2]/div[1]/div[1]/div[2]/div[1]/div[2]/text()')[0]
        except IndexError:
            file_title = '文件名获取失败'
        # 拼接标题
        title = '[{}][{}][{:.1f}GB]'.format(file_title, file_type, file_size)
        return title, magnet


if __name__ == '__main__':
    import time
    bigin_time = time.time()
    magnet_spider = MagnetSpider('https://findcl.com/list?q=ipx')
    a, b = magnet_spider.run()
    end_time = time.time()
    print(end_time-bigin_time)
    print(a)
    print(b)

3. GUI+爬虫

直接看代码吧。
main.py:

from PyQt5.Qt import *
from magnet_search_ui import Ui_Form
from spider import MagnetSpider


class Window(QWidget, Ui_Form):
    def __init__(self):
        super(Window, self).__init__()
        self.setupUi(self)
        self.magnets_list = []
        self.btn_connect()

    def btn_connect(self):
        '''绑定槽函数'''
        # 绑定搜索按钮
        self.pushButton.clicked.connect(self._show_result)
        # 绑定清除按钮
        self.pushButton_2.clicked.connect(self._clear)
        # 绑定双击事件
        self.listWidget.doubleClicked.connect(self._open_magnet)

    def _show_result(self):
        '''显示搜索结果'''
        # 获取输入框的内容
        input_info = self.lineEdit.text()
        url = 'https://findcl.com/list?q=' + input_info
        # 得到文件名和磁力链接
        titles_list, magnets_list = MagnetSpider(url).run()
        self.magnets_list = magnets_list
        # 显示结果前先清空旧结果
        self.listWidget.clear()
        # 显示搜索结果
        self.listWidget.addItems(titles_list)
        # 添加鼠标提示
        self.listWidget.setToolTip('双击使用迅雷下载')

    def _open_magnet(self):
        '''双击使用迅雷下载'''
        # 获取鼠标当前的item的行号
        index = self.listWidget.currentRow()
        # 获取对应的磁力链接
        magnet_url = self.magnets_list[index]
        # 使用迅雷打开该磁力链接
        QDesktopServices.openUrl(QUrl(magnet_url))

    def _clear(self):
        '''清空搜索结果'''
        self.listWidget.clear()


if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())

全部代码见GitHub

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值