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 模块。
然后我们就可以正大光明的进入网站了:https://www.meijutt.com/
令人遗憾的是 url 链接为 https://www.meijutt.com/search/index.asp ,显然没有为我们提供任何有用的信息,当我们刷新页面时,如下图:
当我们手动输入 ulr 链接 https://www.meijutt.com/search/index.asp 进行搜索时:
很明显了,当我们在首页输入想看的美剧并搜索时网站将我们的请求表单信息隐藏了,并没有给到 url 链接里,但是本人可不想每次都从首页进行搜索再提交表单获取信息,很不爽,还好本人发现了一个更好的方法。如下图:
在页面顶部有一个页面跳转的按钮,我们可以选择跳转的页码,当选择跳转页码后,页面变成了如下:
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 字段解码转成汉字:
没错,正是我们想要的,万里长征终于实现了第一步。
- # 加载输入美剧名称后的页面
- 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 库对搜索的网站进行操作。
其中我们还需要做判断,搜索结果是否存在,比如我们搜索 行尸跑肉,结果不存在。
当搜索结果存在时:
我们通过谷歌的 xpath 插件对页面内的 dom 进行搜索,发现我们要选取的 class 类名,关于谷歌插件本人之前的文章讲过一些 https://www.cnblogs.com/weijiutao/p/10608107.html,这里就不多说了。
我们根据获取到的页数,找到所有页面里我们要搜索的信息:
- # 加载点击搜索页面点击的本季页面
- 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 获取到我们所需要的下载链接:
至此我们就将所有我们搜索到的 权力的游戏 的下载链接拿到手了,接下来就是写图形界面了。
本人选用了 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 爬取。
判断一下是否存在搜索结果,比如吧 ”辛普森一家“ 换成了 ”吉普森一家“,搜索内容不存在。
如果搜索内容存在,在搜索完成第一页后提示一下是否需要继续爬取,点击 No 表示停止爬取,点击 OK 表示继续爬取。
最后爬取完毕后提示爬取完毕:
由于本人对 Python 了解不深,代码中有很多不足之处,需要不断学习改进,代码中有任何要改进的地方请各位大佬批评指教!
最后本人做了一套包含 Mac 和 windows 版的图形化美剧天堂抓包程序,只需要在对应电脑上点击运行即可,需要的小伙伴可以在本人的公众号后台回复 美剧天堂 就可以拿到了,注:在 windows 上打包生成的 .exe 软件第一打开时被 360 阻止,大家允许操作就可以了,Mac 无此提示。
好记性不如烂笔头,特此记录,与君共勉!
Python + PyQt5 实现美剧爬虫可视工具的更多相关文章
- Python + PyQt5 实现美剧爬虫可视工具(二)
美剧<权力的游戏>终于开播最后一季了,在上周写了个简单的可视化美剧的爬虫软件来爬取美剧,链接:https://www.cnblogs.com/weijiutao/p/10614694.ht ...
- Python 爬虫批量下载美剧 from 人人影视 HR-HDTV
本人比較喜欢看美剧.尤其喜欢人人影视上HR-HDTV 的 1024 分辨率的高清双字美剧,这里写了一个脚本来批量获得指定美剧的全部 HR-HDTV 的 ed2k下载链接.并依照先后顺序写入到文本文件, ...
- Python爬虫爬取美剧网站
一直有爱看美剧的习惯,一方面锻炼一下英语听力,一方面打发一下时间.之前是能在视频网站上面在线看的,可是自从广电总局的限制令之后,进口的美剧英剧等貌似就不在像以前一样同步更新了.但是,作为一个宅diao ...
- 简单的抓取淘宝关键字信息、图片的Python爬虫|Python3中级玩家:淘宝天猫商品搜索爬虫自动化工具(第一篇)
Python3中级玩家:淘宝天猫商品搜索爬虫自动化工具(第一篇) 淘宝改字段,Bugfix,查看https://github.com/hunterhug/taobaoscrapy.git 由于Gith ...
- Python 爬虫的工具列表 附Github代码下载链接
Python爬虫视频教程零基础小白到scrapy爬虫高手-轻松入门 https://item.taobao.com/item.htm?spm=a1z38n.10677092.0.0.482434a6E ...
- Python 爬虫的工具列表大全
Python 爬虫的工具列表大全 这个列表包含与网页抓取和数据处理的Python库.网络 通用 urllib -网络库(stdlib). requests -网络库. grab – 网络库(基于pyc ...
- Node.js 爬虫批量下载美剧 from 人人影视 HR-HDTV
这两天发现了一个叫看知乎的站点.是知乎的苏莉安做的,当中爬虫使用的 Node.js.这里就针对上一篇博客中的美剧小爬虫,改用 nodejs 进行实现一下.体验一下强大的 Node.js. 假设之前没实 ...
- Python 爬虫的工具列表
Python 爬虫的工具列表 这个列表包含与网页抓取和数据处理的Python库 网络 通用 urllib -网络库(stdlib). requests -网络库. grab – 网络库(基于pycur ...
- python 爬取豆瓣的美剧
pc版大概有500条记录,mobile大概是50部,只有热门的,所以少一点 url构造很简单,主要参数就是page_limit与page_start,每翻一页,start+=20即可,tag是&quo ...
随机推荐
- util.go
packagesego import( "bytes" "fmt" ) //输出分词结果为字符串 // //有两种输出模式,以"中华人 ...
- 使用jvisualvm
jvisualvm是java开发,调试,监控,分析内存的一个可视化工具,可以在安装完JDK中找到,一般在bin目录下 之前调试tomca内存分配,现在总结下心得, windows下的tomcat修改c ...
- C++ 文件流的方式操作文件(一个简单的写入,读取)
新手学习c++哈,归纳的写了一下以 C++ 的方式写入读取文件,读文件到控制台,并加了行号.博客记录主要为了备忘.当然 ^_^ 喜欢同学的话可以拿走代码直接用.转帖注明出处哈.欢迎讨论,我一直认为:知 ...
- 【最小生成树+贪心】BZOJ1821: [JSOI2010]Group 部落划分 Group
Description 聪聪研究发现,荒岛野人总是过着群居的生活,但是,并不是整个荒岛上的所有野人都属于同一个部落,野人们总是拉帮结派形成属于自己的部落,不同的部落之间则经常发生争斗.只是,这一切都成 ...
- webpack下css/js/html引用图片的正确方式
在webpack的处理下,为了使引用的图片被打包编译(以把src的图片文件编译到dist中或者对src的文件进行base64编码),应使用如下引用方式: 1. 在html/ejs等中引用图片: 借助r ...
- layui导航栏和layui.layui.msg问题
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 危险 AI 花名册
简评:臭不要脸 AI 名单,another side of AI. 这是一个可怕的 AI 清单,上面的各种商用 AI 项目都用于一些很恶劣的目的.请大家保持警惕. 区别对待类 · HireVue - ...
- 为自己搭建一个分布式 IM(即时通讯) 系统
前言 大家新年快乐! 新的一年第一篇技术文章希望开个好头,所以元旦三天我也没怎么闲着,希望给大家带来一篇比较感兴趣的干货内容. 老读者应该还记得我在去年国庆节前分享过一篇<设计一个百万级的消息推 ...
- .NET Core + Ocelot + IdentityServer4 + Consul 基础架构实现
先决条件 关于 Ocelot 针对使用 .NET 开发微服务架构或者面向服务架构提供一个统一访问系统的组件. 参考 本文将使用 Ocelot 构建统一入口的 Gateway. 关于 IdentityS ...
- 解决vs2019中暂时无法为.net core WinForms使用 Designer 的临时方法
目录 解决vs2019中暂时无法为.net core WinForms使用 Designer 的临时方法 安装 vs 2019 professional/enterprise版本 在vs的设置里,勾选 ...