通过 PyQt 给妹子图网的Python爬虫做一个交互界面,从而对 PyQt 有初步的理解,并学会如何使用 Qt Creater 做界面以及实现基础功能。课程分为三个部分:
这是本课程的第一次实验。在这里先给大家看看,学完这三节课之后,最后我们要完成的效果:
本课程难度属于一般,属于初级级别课程,适合具有 Python 基础的用户,熟悉 Python 基础知识加深巩固。
通过本次实验,学会如何在如何结合 PyQt 以及 Python, 完成图片预览以及元素列表两个Demo。
本实验环境采用带桌面的 Ubuntu Linux 环境,实验中会用到的程序:
进入系统后,如果 Linux 中默认的 python3 为 3.5 版本,可以通过以下指令切换到 3.4:
$ sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.4 70 --slave /usr/bin/python3m python3m /usr/bin/python3.4m
更新 apt-get 的链接:
$ sudo apt-get update
安装 Qt Creater 以及 PyQt5 相关组件:
$ sudo apt-get install qtcreator pyqt5-dev-tools
安装 beautifulsoup(bs4):
$ sudo apt-get install python3-bs4
在写爬虫之前,我们先来看看妹子图网的首页。页面的主要内容是由24个图框组成,查看页面的源代码(View page source),我们可以轻易知道其网页的构造,每一个li
节点里面包含每一个链接里面包含:标题、原图链接、跳转链接、发布时间以及浏览次数。如果要翻下一页,只需要更改网址后缀,即在链接后面加入/page/(page_number)就可以了,page_number是相应的页数,妹子图的详细爬虫教程可以参考这个大大的文章。
class Mzitu():
def __init__(self, url):
self.url = url
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36',
'Host': 'www.mzitu.com'}
response = requests.get(self.url, headers = headers)
content = BeautifulSoup(response.text, 'lxml')
linkblock = content.find('div', class_="postlist")
self.linklist = linkblock.find_all('li')
def printli(self):
linklist = self.linklist
linksum = list()
for link in linklist:
url = link.a.get('href')
picurl = link.img.get('data-original')
linkid = re.search(r'(\d+)', url).group()
firstspan = link.span
titleword = firstspan.get_text()
secondspan = firstspan.find_next_sibling('span')
uploadtime = secondspan.get_text()
thirdspan = secondspan.find_next_sibling('span')
viewcount = thirdspan.get_text()
linksum.append((linkid, titleword, uploadtime, viewcount, picurl))
return linksum
首先是制作ui界面,拖曳3个Push Button 分别作为翻页的上页(pushButton_uppage)和下页(pushButton_nextpage)以及获得链接的开关(pushButton),拖曳Table Widget作为我们放置页面内容(tableWidget),拖曳2个Label分别作为页数显示(label_pagenum)以及图片输出(label),拖曳Text Browser作为我们链接输出(textBrowser)。
保存后好,对ui文件的进行加载:
import re, requests
from bs4 import BeautifulSoup
from PyQt5.QtWidgets import QApplication, QCheckBox, QPushButton, QHeaderView
from PyQt5.QtGui import QPixmap
import PyQt5.uic
ui_file = 'Demo5.ui'
(class_ui, class_basic_class) = PyQt5.uic.loadUiType(ui_file)
主类先继承 form class 以及 qt base class ,然后调用爬虫的 class 来生成首页内容的列表,根据首页的内容数量来确定 Table Widget 的行数,并设定相应列宽以及行高,最后是将 Check Box 以及 Push Button 放置在 Table Widget 中,并且对其中的 Push Button 与相应的功能函数进行关联:
class Window(class_basic_class, class_ui):
def __init__(self):
super(Window, self).__init__()
self.url = "http://www.mzitu.com/"
self.setupUi(self)
totlist = Mzitu(self.url).printli()
self.tableWidget.setRowCount(len(totlist))
self.tableWidget.setColumnCount(2)
self.tableWidget.setColumnWidth(0, 435)
verticalHeader = self.tableWidget.verticalHeader()
verticalHeader.setSectionResizeMode(QHeaderView.Fixed)
verticalHeader.setDefaultSectionSize(30)
self.textBrowser.setOpenExternalLinks(True) ##隐藏列表头
self.page = 1 ##设定初始的页面数,为后面做翻页器做准备
self.label_pagenum.setNum(self.page)
self.checkBoxs = [self._addCheckbox(index, item[0], item[1]) for index, item in enumerate(totlist)]
self.pushButtons = [self._addpushButtonpic(index, item[0], item[4]) for index, item in enumerate(totlist)]
self.pushButton.clicked.connect(self.getSelList)
self.pushButton_nextpage.clicked.connect(lambda: self._nextPage(1))
self.pushButton_uppage.clicked.connect(lambda: self._nextPage(-1))
_addCheckbox 用于生成 Check Box 单元,并将单元通过 setCellWidget 关联到 Table Widget 对应位置中。每一个 Check Box 最终都用 isChecked() 函数来判断是否有被勾选上,getSelList 是用来在 textBrowser 中输出对应内容的名称以及链接,注意链接这里我为了可以直接点开,而不需要复制到浏览器里面才能打开,所以采用 html 文本书写,以达到超级链接的效果:
def _addCheckbox(self, index, idd, boxtitle):
checkBox = QCheckBox()
checkBox.setObjectName(idd)
checkBox.setText(boxtitle)
self.tableWidget.setCellWidget(index, 0, checkBox) ##setCellWidget前面两个数字分别代表行和列,最后是需要关联的元素
return checkBox
def getSelList(self):
selList = [(item.objectName(), item.text()) for item in self.checkBoxs if item.isChecked() == True]
for item in selList:
url = 'http://www.mzitu.com/'+item[0]
self.textBrowser.append(item[1])
self.textBrowser.append('%s' % (url, url)) ##此处输出超级链接
return selList
_addpushButton 是用于在 Table Widget 中关联 Push Button,方法和上述 Check Box 类似。注意 Push Button 关联函数那里,我使用了 Lambda 表达式。_showpic 就是一个在 Label 中输出图片的功能,具体在之前 Demo 那里已经做过叙述:
def _addpushButtonpic(self, index, idd, href):
pushButton = QPushButton()
pushButton.setObjectName(idd)
pushButton.setText(idd)
self.tableWidget.setCellWidget(index, 1, pushButton)
pushButton.clicked.connect(lambda: self._showpic(idd, href))
return pushButton
def _showpic(self, idd, href):
pic = requests.get(href).content
pixmap = QPixmap()
pixmap.loadFromData(pic)
self.label.setPixmap(pixmap)
_nextPage 是实现翻页器功能,一开始是考虑只做下一页的,但使用中发现不方便。所以需要增加向上翻的功能,这是通过将翻页数分别设定为+1改成-1来实现的。更换了页码之后,需要重新通过爬虫 class 获得新页面的内容,并重新用 _addCheckbox 以及 _addpushButto n函数来更新 Check Box 以及 Push Button 的内容,最后输出新的 self.checkboxs 以及 self.pushButtons:
def _nextPage(self, page):
self.page += page
self.label_pagenum.setNum(self.page)
url = self.url + '/page/' + str(self.page)
totlist = Mzitu(url).printli()
newcheckBoxs = []
newpushButtons = []
for index, item in enumerate(totlist):
newcheckbox = self._addCheckbox(index, item[0], item[1])
newpushbutton = self._addpushButtonpic(index, item[0], item[4])
newcheckBoxs.append(newcheckbox)
newpushButtons.append(newpushbutton)
self.checkBoxs = newcheckBoxs
self.pushButtons = newpushButtons
最后我们来看看最终效果图。
最后,我们完整的程序就完成了,后面可以通过py2exe转化是window实际可以操作的执行程序,限于篇幅这里没有写道,整个 Table Widget 还可以加入浏览数、新增时间以及全选等功能,来完善整个体验。最后相信精明的老司机已经发现,既然获得链接,通过爬虫可以进一步获得链接后面的图片,然后通过筛选就可以将喜欢的图片下载到自己的硬盘里面了。