Python+PyQt5实现美剧爬虫可视工具的方法


Posted in Python onApril 25, 2019

美剧《权力的游戏》终于要开播最后一季了,作为马丁老爷子的忠实粉丝,为了能够看得懂第八季复杂庞大的剧情架构,本人想着将前几季再稳固一下,所以就上美剧天堂下载来看,可是每次都上去下载太麻烦了,于是干脆自己写个爬虫爬下来得了。

话不多说,先上图片。

Python+PyQt5实现美剧爬虫可视工具的方法

本人才疏学浅,就写了个简单的可视化软件,关键是功能实现就行了嘛。

实现语言:Python ,版本 3.7.1

实现思路:首先运用 Python 工具爬取到数据再实现图形化软件。

由于这里只是实现简单的爬取数据,并没有牵扯到 cookie 之类的敏感信息,也没有设置代理,所以在选择 Python 库上并没有引入 Selenium 或者更高级的 Scrapy 框架,只是拿到数据就可以了,没必要那么麻烦。

所以选择了 urllib 这个库,在 Python 2.X 中应该是 urllib 和 urllib2 同时引入,由于本人选用的版本的 Python 3.X ,在 Python 3.X 中上面两个库已经被合并为 urllib 一个库,语法上有些不同,但语言这种东西都是大同小异的嘛。

先贴代码,缓和一下尴尬的气氛。

import urllib.request
from urllib import parse
from lxml import etree
import ssl
from PyQt5.QtWidgets import QApplication, QWidget, QLineEdit, QTextEdit, QVBoxLayout, QPushButton, QMessageBox
import sys

# 取消代理验证
ssl._create_default_https_context = ssl._create_unverified_context

class TextEditMeiJu(QWidget):
 def __init__(self, parent=None):
  super(TextEditMeiJu, self).__init__(parent)
  # 定义窗口头部信息
  self.setWindowTitle('美剧天堂')
  # 定义窗口的初始大小
  self.resize(500, 600)
  # 创建单行文本框
  self.textLineEdit = QLineEdit()
  # 创建一个按钮
  self.btnButton = QPushButton('确定')
  # 创建多行文本框
  self.textEdit = QTextEdit()
  # 实例化垂直布局
  layout = QVBoxLayout()
  # 相关控件添加到垂直布局中
  layout.addWidget(self.textLineEdit)
  layout.addWidget(self.btnButton)
  layout.addWidget(self.textEdit)
  # 设置布局
  self.setLayout(layout)
  # 将按钮的点击信号与相关的槽函数进行绑定,点击即触发
  self.btnButton.clicked.connect(self.buttonClick)

 # 点击确认按钮
 def buttonClick(self):
  # 爬取开始前提示一下
  start = QMessageBox.information(
   self, '提示', '是否开始爬取《' + self.textLineEdit.text() + "》",
   QMessageBox.Ok | QMessageBox.No, QMessageBox.Ok
  )
  # 确定爬取
  if start == QMessageBox.Ok:
   self.page = 1
   self.loadSearchPage(self.textLineEdit.text(), self.page)
  # 取消爬取
  else:
   pass

 # 加载输入美剧名称后的页面
 def loadSearchPage(self, name, page):
  # 将文本转为 gb2312 编码格式
  name = parse.quote(name.encode('gb2312'))
  # 请求发送的 url 地址
  url = "https://www.meijutt.com/search/index.asp?page=" + str(page) + "&searchword=" + name + "&searchtype=-1"
  # 请求报头
  headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"}
  # 发送请求
  request = urllib.request.Request(url, headers=headers)
  # 获取请求的 html 文档
  html = urllib.request.urlopen(request).read()
  # 对 html 文档进行解析
  text = etree.HTML(html)
  # xpath 获取想要的信息
  pageTotal = text.xpath('//div[@class="page"]/span[1]/text()')
  # 判断搜索内容是否有结果
  if pageTotal:
   self.loadDetailPage(pageTotal, text, headers)
  # 搜索内容无结果
  else:
   self.infoSearchNull()

 # 加载点击搜索页面点击的本季页面
 def loadDetailPage(self, pageTotal, text, headers):
  # 取出搜索的结果一共多少页
  pageTotal = pageTotal[0].split('/')[1].rstrip("页")
  # 获取每一季的内容(剧名和链接)
  node_list = text.xpath('//a[@class="B font_14"]')
  items = {}
  items['name'] = self.textLineEdit.text()
  # 循环获取每一季的内容
  for node in node_list:
   # 获取信息
   title = node.xpath('@title')[0]
   link = node.xpath('@href')[0]
   items["title"] = title
   # 通过获取的单季链接跳转到本季的详情页面
   requestDetail = urllib.request.Request("https://www.meijutt.com" + link, headers=headers)
   htmlDetail = urllib.request.urlopen(requestDetail).read()
   textDetail = etree.HTML(htmlDetail)
   node_listDetail = textDetail.xpath('//div[@class="tabs-list current-tab"]//strong//a/@href')
   self.writeDetailPage(items, node_listDetail)
  # 爬取完毕提示
  if self.page == int(pageTotal):
   self.infoSearchDone()
  else:
   self.infoSearchContinue(pageTotal)

 # 将数据显示到图形界面
 def writeDetailPage(self, items, node_listDetail):
  for index, nodeLink in enumerate(node_listDetail):
   items["link"] = nodeLink
   # 写入图形界面
   self.textEdit.append(
    "<div>"
     "<font color='black' size='3'>" + items['name'] + "</font>" + "\n"
     "<font color='red' size='3'>" + items['title'] + "</font>" + "\n"
     "<font color='orange' size='3'>第" + str(index + 1) + "集</font>" + "\n"
     "<font color='green' size='3'>下载链接:</font>" + "\n"
     "<font color='blue' size='3'>" + items['link'] + "</font>"
     "<p></p>"
    "</div>"
   )

 # 搜索不到结果的提示信息
 def infoSearchNull(self):
  QMessageBox.information(
   self, '提示', '搜索结果不存在,请重新输入搜索内容',
   QMessageBox.Ok, QMessageBox.Ok
  )

 # 爬取数据完毕的提示信息
 def infoSearchDone(self):
  QMessageBox.information(
   self, '提示', '爬取《' + self.textLineEdit.text() + '》完毕',
   QMessageBox.Ok, QMessageBox.Ok
  )

 # 多页情况下是否继续爬取的提示信息
 def infoSearchContinue(self, pageTotal):
  end = QMessageBox.information(
   self, '提示', '爬取第' + str(self.page) + '页《' + self.textLineEdit.text() + '》完毕,还有' + str(int(pageTotal) - self.page) + '页,是否继续爬取',
   QMessageBox.Ok | QMessageBox.No, QMessageBox.No
  )
  if end == QMessageBox.Ok:
   self.page += 1
   self.loadSearchPage(self.textLineEdit.text(), self.page)
  else:
   pass


if __name__ == '__main__':
 app = QApplication(sys.argv)
 win = TextEditMeiJu()
 win.show()
 sys.exit(app.exec_())

以上是实现功能的所有代码,可以运行 Python 的小伙伴直接复制到本地运行即可。都说 Python 是做爬虫最好的工具,写完之后发现确实是这样。

我们一点点分析代码:

import urllib.request
from urllib import parse
from lxml import etree
import ssl
from PyQt5.QtWidgets import QApplication, QWidget, QLineEdit, QTextEdit, QVBoxLayout, QPushButton, QMessageBox, QLabel
import sys

以上为我们引入的所需要的库,前 4 行是爬取 美剧天堂 官网所需要的库,后两个是实现图形化应用所需的库。

我们先来看一下如何爬取网站信息。

由于现在 美剧天堂 使用的是 https 协议,进入页面需要代理验证,为了不必要的麻烦,我们干脆取消代理验证,所以用到了 ssl 模块。

然后我们就可以正大光明的进入网站了:

Python+PyQt5实现美剧爬虫可视工具的方法

令人遗憾的是 url 链接为https://www.meijutt.com/search/index.asp,显然没有为我们提供任何有用的信息,当我们刷新页面时,如下图:

Python+PyQt5实现美剧爬虫可视工具的方法

当我们手动输入 ulr 链接https://www.meijutt.com/search/index.asp进行搜索时:

Python+PyQt5实现美剧爬虫可视工具的方法

很明显了,当我们在首页输入想看的美剧并搜索时网站将我们的请求表单信息隐藏了,并没有给到 url 链接里,但是本人可不想每次都从首页进行搜索再提交表单获取信息,很不爽,还好本人发现了一个更好的方法。如下图:

Python+PyQt5实现美剧爬虫可视工具的方法

在页面顶部有一个页面跳转的按钮,我们可以选择跳转的页码,当选择跳转页码后,页面变成了如下:

Python+PyQt5实现美剧爬虫可视工具的方法

url 链接已经改变了:https://www.meijutt.com/search/index.asp?page=&searchword=%C8%A8%C1%A6%B5%C4%D3%CE%CF%B7&searchtype=-1

我们再将 page 中动态添加为page=1,页面效果不变。

经过搜索多个不同的美剧的多次验证发现只有 page 和 searchword 这两个字段是改变的,其中 page 字段默认为 1 ,而其本人搜索了许多季数很长的美剧,比如《老友记》、《生活大爆炸》、《邪恶力量》,这些美剧也就一页,但仍有更长的美剧,比如《辛普森一家》是两页,《法律与秩序》是两页,这就要求我们对页数进行控制,但是需要特别注意的是如果随意搜索内容,比如在搜索框只搜索了一个 ”i“,整整搜出了219页,这要扒下来需要很长的时间,所以就需要对其搜索的页数进行控制。

我们再来看一下 searchword 字段,将 searchword 字段解码转成汉字:

Python+PyQt5实现美剧爬虫可视工具的方法

Python+PyQt5实现美剧爬虫可视工具的方法

没错,正是我们想要的,万里长征终于实现了第一步。

# 加载输入美剧名称后的页面
def loadSearchPage(self, name, page):
 # 将文本转为 gb2312 编码格式
 name = parse.quote(name.encode('gb2312'))
 # 请求发送的 url 地址
 url = "https://www.meijutt.com/search/index.asp?page=" + str(page) + "&searchword=" + name + "&searchtype=-1"
 # 请求报头
 headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"}
 # 发送请求
 request = urllib.request.Request(url, headers=headers)
 # 获取请求的 html 文档
 html = urllib.request.urlopen(request).read()
 # 对 html 文档进行解析
 text = etree.HTML(html)
 # xpath 获取想要的信息
 pageTotal = text.xpath('//div[@class="page"]/span[1]/text()')
 # 判断搜索内容是否有结果
 if pageTotal:
  self.loadDetailPage(pageTotal, text, headers)
 # 搜索内容无结果
 else:
  self.infoSearchNull()

接下来我们只需要将输入的美剧名转化成 url 编码格式就可以了。如上代码,通过 urllib 库对搜索的网站进行操作。

其中我们还需要做判断,搜索结果是否存在,比如我们搜索 行尸跑肉,结果不存在。

Python+PyQt5实现美剧爬虫可视工具的方法

当搜索结果存在时:

Python+PyQt5实现美剧爬虫可视工具的方法

Python+PyQt5实现美剧爬虫可视工具的方法

我们通过谷歌的 xpath 插件对页面内的 dom 进行搜索,发现我们要选取的 class 类名。

我们根据获取到的页数,找到所有页面里我们要搜索的信息:

# 加载点击搜索页面点击的本季页面
def loadDetailPage(self, pageTotal, text, headers):
 # 取出搜索的结果一共多少页
 pageTotal = pageTotal[0].split('/')[1].rstrip("页")
 # 获取每一季的内容(剧名和链接)
 node_list = text.xpath('//a[@class="B font_14"]')
 items = {}
 items['name'] = self.textLineEdit.text()
 # 循环获取每一季的内容
 for node in node_list:
  # 获取信息
  title = node.xpath('@title')[0]
  link = node.xpath('@href')[0]
  items["title"] = title
  # 通过获取的单季链接跳转到本季的详情页面
  requestDetail = urllib.request.Request("https://www.meijutt.com" + link, headers=headers)
  htmlDetail = urllib.request.urlopen(requestDetail).read()
  textDetail = etree.HTML(htmlDetail)
  node_listDetail = textDetail.xpath('//div[@class="tabs-list current-tab"]//strong//a/@href')
  self.writeDetailPage(items, node_listDetail)
 # 爬取完毕提示
 if self.page == int(pageTotal):
  self.infoSearchDone()
 else:
  self.infoSearchContinue(pageTotal)

我们根据获取到的链接,再次通过 urllib 库进行页面访问,即我们手动点击进入其中的一个页面,比如 权利的游戏第一季,再次通过 xpath 获取到我们所需要的下载链接:

Python+PyQt5实现美剧爬虫可视工具的方法

至此我们就将所有我们搜索到的 权力的游戏 的下载链接拿到手了,接下来就是写图形界面了。

本人选用了 PyQt5 这个框架,它内置了 QT 的操作语法,对于本人这种小白用起来也很友好。至于如何使用本人也都在代码上添加了注释,在这儿做一下简单的说明,就不过多解释了。

from PyQt5.QtWidgets import QApplication, QWidget, QLineEdit, QTextEdit, QVBoxLayout, QPushButton, QMessageBox, QLabel
import sys

将获取的信息写入搜索结果内:

# 将数据显示到图形界面
def writeDetailPage(self, items, node_listDetail):
 for index, nodeLink in enumerate(node_listDetail):
  items["link"] = nodeLink
  # 写入图形界面
  self.textEdit.append(
   "<div>"
    "<font color='black' size='3'>" + items['name'] + "</font>" + "\n"
    "<font color='red' size='3'>" + items['title'] + "</font>" + "\n"
    "<font color='orange' size='3'>第" + str(index + 1) + "集</font>" + "\n"
    "<font color='green' size='3'>下载链接:</font>" + "\n"
    "<font color='blue' size='3'>" + items['link'] + "</font>"
    "<p></p>"
   "</div>"
  )

因为可能有多页情况,所以我们得做一次判断,提示一下剩余多少页,可以选择继续爬取或停止,做到人性化交互。

# 搜索不到结果的提示信息
def infoSearchNull(self):
 QMessageBox.information(
  self, '提示', '搜索结果不存在,请重新输入搜索内容',
  QMessageBox.Ok, QMessageBox.Ok
 )

# 爬取数据完毕的提示信息
def infoSearchDone(self):
 QMessageBox.information(
  self, '提示', '爬取《' + self.textLineEdit.text() + '》完毕',
  QMessageBox.Ok, QMessageBox.Ok
 )

# 多页情况下是否继续爬取的提示信息
def infoSearchContinue(self, pageTotal):
 end = QMessageBox.information(
  self, '提示', '爬取第' + str(self.page) + '页《' + self.textLineEdit.text() + '》完毕,还有' + str(int(pageTotal) - self.page) + '页,是否继续爬取',
  QMessageBox.Ok | QMessageBox.No, QMessageBox.No
 )
 if end == QMessageBox.Ok:
  self.page += 1
  self.loadSearchPage(self.textLineEdit.text(), self.page)
 else:
  pass

demo 图形化软件操作如下:

在搜索框内输入要搜索的美剧名,点击确认。提示一下是否要爬取,点击 No 不爬取,点击 OK 爬取。

Python+PyQt5实现美剧爬虫可视工具的方法

判断一下是否存在搜索结果,比如吧 ”辛普森一家“ 换成了 ”吉普森一家“,搜索内容不存在。

Python+PyQt5实现美剧爬虫可视工具的方法

如果搜索内容存在,在搜索完成第一页后提示一下是否需要继续爬取,点击 No 表示停止爬取,点击 OK 表示继续爬取。

Python+PyQt5实现美剧爬虫可视工具的方法

最后爬取完毕后提示爬取完毕:

Python+PyQt5实现美剧爬虫可视工具的方法

由于本人对 Python 了解不深,代码中有很多不足之处,需要不断学习改进,代码中有任何要改进的地方请各位大佬批评指教!

最后本人做了一套包含 Mac 和 windows 版的图形化美剧天堂抓包程序,只需要在对应电脑上点击运行即可,需要的小伙伴可以在本人的公众号后台回复美剧天堂就可以拿到了,注:在 windows 上打包生成的 .exe 软件第一打开时被 360 阻止,大家允许操作就可以了,Mac 无此提示。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python和php通信乱码问题解决方法
Apr 15 Python
python两种遍历字典(dict)的方法比较
May 29 Python
在Python的Django框架下使用django-tagging的教程
May 30 Python
python+selenium实现登录账户后自动点击的示例
Dec 22 Python
python实现列表中由数值查到索引的方法
Jun 27 Python
Python OpenCV 使用滑动条来调整函数参数的方法
Jul 08 Python
python selenium爬取斗鱼所有直播房间信息过程详解
Aug 09 Python
django-rest-swagger的优化使用方法
Aug 29 Python
工程师必须了解的LRU缓存淘汰算法以及python实现过程
Oct 15 Python
python爬虫爬取淘宝商品比价(附淘宝反爬虫机制解决小办法)
Dec 03 Python
Python3使用Selenium获取session和token方法详解
Feb 16 Python
python中的被动信息搜集
Apr 29 Python
详解用python实现基本的学生管理系统(文件存储版)(python3)
Apr 25 #Python
Python基础教程之if判断,while循环,循环嵌套
Apr 25 #Python
python3通过selenium爬虫获取到dj商品的实例代码
Apr 25 #Python
NumPy 数组使用大全
Apr 25 #Python
Python+OpenCV采集本地摄像头的视频
Apr 25 #Python
python利用selenium进行浏览器爬虫
Apr 25 #Python
python3人脸识别的两种方法
Apr 25 #Python
You might like
Mysql数据库操作类( 1127版,提供源码下载 )
2010/12/02 PHP
PHP中preg_match函数正则匹配的字符串长度问题
2015/05/27 PHP
PHP中文竖排转换实现方法
2015/10/23 PHP
wordpress网站转移到本地运行测试的方法
2017/03/15 PHP
php 截取中英文混合字符串的方法
2018/05/31 PHP
微信公众号开发之获取位置信息php代码
2018/06/13 PHP
php基于协程实现异步的方法分析
2019/07/17 PHP
IE6下通过a标签点击切换图片的问题
2010/11/14 Javascript
Jquery中的CheckBox、RadioButton、DropDownList的取值赋值实现代码
2011/10/12 Javascript
jquery获取div宽度的实现思路与代码
2013/01/13 Javascript
JavaScript改变HTML元素的样式改变CSS及元素属性
2013/11/12 Javascript
js Object2String方便查看js对象内容
2014/11/24 Javascript
浅析JavaScript Array和string的转换(推荐)
2016/05/20 Javascript
Ajax跨域实现代码(后台jsp)
2017/01/21 Javascript
js实现倒计时效果(小于10补零)
2017/03/08 Javascript
VueJs单页应用实现微信网页授权及微信分享功能示例
2017/07/26 Javascript
vue自定义键盘信息、监听数据变化的方法示例【基于vm.$watch】
2019/03/16 Javascript
vue配置nprogress实现页面顶部进度条
2019/09/21 Javascript
js脚本中执行java后台代码方法解析
2019/10/11 Javascript
JavaScript实现简单贪吃蛇效果
2020/03/09 Javascript
VueJS实现用户管理系统
2020/05/29 Javascript
前端vue如何使用高德地图
2020/11/05 Javascript
解决Element中el-date-picker组件不回填的情况
2020/11/07 Javascript
[46:27]DOTA2上海特级锦标赛主赛事日 - 1 胜者组第一轮#2LGD VS MVP.Phx第一局
2016/03/02 DOTA
python 布尔操作实现代码
2013/03/23 Python
Python中几种操作字符串的方法的介绍
2015/04/09 Python
使用pandas对矢量化数据进行替换处理的方法
2018/04/11 Python
python3解析库pyquery的深入讲解
2018/06/26 Python
python绘制彩虹图
2019/12/16 Python
解决pycharm修改代码后第一次运行不生效的问题
2021/02/06 Python
自考生自我评价分享
2014/01/18 职场文书
学生顶撞老师的检讨书
2014/09/17 职场文书
党的群众路线教育实践活动对照检查材料范文
2014/09/24 职场文书
《清澈的湖水》教学反思
2016/02/17 职场文书
高中数学课堂教学反思
2016/02/18 职场文书
数据库连接池
2021/04/06 MySQL