Python+Tornado+Tampermonkey 获取某讯等主流视频网站的会员视频解析播放

近期,《哪吒之魔童降世》在各大视频软件可以看了,然而却是一贯的套路,非会员谢绝观看!!!只能从国内那些五花八门的视频网站上找着看了,或者通过之前本人说的 Chrome 的油猴插件,传送门 https://www.cnblogs.com/weijiutao/p/10608107.html,进行观看。

经过分析,通过油猴插件观看某奇艺等主流视频网站的方法其实就是在视频网页链接的前面加上一个视频解析的链接地址,如下:

播放传送门

 http://jx.618g.com/?url=http://www.iqiyi.com/lib/m_217405614.html?src=search

                                      http://www.iqiyi.com/lib/m_217405614.html?src=search

通过上面的分析,本人萌生了一个将 Tampermonkey 和 主流视频网站 联系起来的一个小工具,通过自己输入想要观看的视频,然后通过油猴插件里面的视频解析网站解析出来,效果如下:

首先我们要做的就是从某奇艺等网站上获取到我们想要的视频信息,如海报,电影名,演员,导演,简介和播放链接等信息。

本人选用了 Python 语言开发,结合 Tornado 框架将想要的信息呈现到 web 页面上。目录结构如下:

项目的主入口为 app.py ,代码如下:

 1 import tornado.web
 2 import tornado.ioloop
 3 import tornado.httpserver
 4 import tornado.options
 5 import os
 6 
 7 import spider.tv.tencent
 8 import spider.tv.aiqiyi
 9 
10 import spider.movie.tencent
11 import spider.movie.aiqiyi
12 
13 import spider.variety.tencent
14 import spider.variety.aiqiyi
15 
16 from tornado.options import options
17 from tornado.web import RequestHandler, StaticFileHandler
18 
19 tornado.options.define("port", type=int, default=8000, help="服务器端口")
20 
21 
22 class IndexHandler(RequestHandler):
23 
24     # 主页处理类
25     def get(self):
26         self.render("index.html")
27 
28     def post(self):
29         self.render("index.html")
30 
31 
32 class TvpalyHandler(RequestHandler):
33     def post(self):
34         name = self.get_argument("name")
35         type = self.get_argument("type")
36         if type == '1':
37             resultTencent = spider.tv.tencent.tencents(self, name)
38             resultAiqiyi = spider.tv.aiqiyi.aiqiyi(self, name)
39             data = {
40                 "tencent": resultTencent,
41                 "aiqiyi": resultAiqiyi,
42             }
43             self.write(data)
44         elif type == '2':
45             resultTencent = spider.movie.tencent.tencents(self, name)
46             resultAiqiyi = spider.movie.aiqiyi.aiqiyi(self, name)
47             data = {
48                 "tencent": resultTencent,
49                 "aiqiyi": resultAiqiyi,
50             }
51             self.write(data)
52         elif type == '3':
53             resultTencent = spider.variety.tencent.tencents(self, name)
54             resultAiqiyi = spider.variety.aiqiyi.aiqiyi(self, name)
55             data = {
56                 "tencent": resultTencent,
57                 "aiqiyi": resultAiqiyi,
58             }
59             self.write(data)
60 
61 
62 if __name__ == '__main__':
63     tornado.options.parse_command_line()
64     current_path = os.path.dirname(__file__)
65     app = tornado.web.Application(
66         [
67 
68             (r'/', IndexHandler),
69             (r'/api/tvplay', TvpalyHandler),
70             (r'/(.*)', StaticFileHandler, {
71                 "path": os.path.join(current_path, "statics/html"),
72                 "default_filename": "index.html"
73             }),
74         ],
75         static_path=os.path.join(current_path, "static"),
76         template_path=os.path.join(current_path, "template"),
77         debug=True,
78         autoescape=None
79     )
80 
81     http_server = tornado.httpserver.HTTPServer(app)
82     http_server.listen(options.port)
83     tornado.ioloop.IOLoop.current().start()

由于本人没有经过系统的 Python 学习,完全都是自学而来,所以代码中如有什么不妥之处请大神批评指正。

在上面的代码中,我们做的内容其实是接收前端发来的 POST 请求,并通过 type 类型去目录 spider 中调用不同类型的内容(电影,电视剧,综艺),上面我们在 web 页面搜索 哪吒 其实就是 type == 2 时所要做的处理,即调用目录 spider->movie 下的 aiqiyi.py 和 tencent.py,由于某酷的web页面全是动态js加载的,内容不好做处理,这里就忽略了。

我们以 aiqiyi.py 为例,tencent.py 代码其实大同小异,思路一样。代码如下:

 1 from urllib import request, parse
 2 from lxml import etree
 3 import ssl
 4 
 5 # 取消 https 代理验证
 6 ssl._create_default_https_context = ssl._create_unverified_context
 7 
 8 
 9 def aiqiyi(self, name):
10     # 报头
11     user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36'
12     headers = {'User-Agent': user_agent}
13     url = "https://so.iqiyi.com/so/q_" + parse.quote(name)
14     req = request.Request(url, headers=headers)
15     try:
16         response = request.urlopen(req)
17         # 获取每页的HTML源码字符串
18         html = response.read().decode('utf-8')
19         # 解析html 为 HTML 文档
20         selector = etree.HTML(html)
21 
22         # 来源
23         source = "爱奇艺视频"
24 
25         # 剧照
26         pic = 'https:' + 
27               selector.xpath('//ul[@class="mod_result_list"]/li[1]/a//img/@src')[0]
28 
29         # 导演
30         director = selector.xpath(
31             "//ul[@class='mod_result_list']/li[1]//div[@class='info_item'][1]/div[@class='result_info_cont result_info_cont-half'][1]/a[@class='result_info_link']/text()")
32         # 主演
33         actor = selector.xpath(
34             "//ul[@class='mod_result_list']/li[1]//div[@class='info_item'][1]/div[@class='result_info_cont result_info_cont-half'][2]/a[@class='result_info_link']/text()")
35 
36         # 简介
37         desc = selector.xpath(
38             "//ul[@class='mod_result_list']/li[@class='list_item'][1]//div[@class='info_item'][2]//span[@class='result_info_txt']/text()")[
39             0]
40 
41         # 链接
42         link = selector.xpath('//ul[@class="mod_result_list"]/li[1]/a/@href')[0]
43         defalut_result = {
44             "source": source,
45             "name": name,
46             "pic": pic,
47             "director": director,
48             "actor": actor,
49             "desc": desc,
50             "list": [{'title': '播放', 'link': link}]
51         }
52         return defalut_result
53     except Exception:
54         print(url, Exception)
55         data = {"code": -1, "message": "error", "data": None}
56         return data

我们要解析的页面其实是 'https://so.iqiyi.com/so/q_' + 要搜索的内容,如下图所示:

然后我们就可以通过 python 爬虫来抓取页面中的内容信息了,从上面的页面截图可以发现我们输入的搜索字其实搜索到了一些其他的信息,这些信息在提取过程中会出现很多复杂情况,所以再这里本人就只提取了第一个内容,即可以播放的 哪吒之魔童降世 的完整视频。

本人选用的是通过 xpath 的形式来抓取,具体 dom 抓取操作可以看本人之前的文章,传送门 

https://www.cnblogs.com/weijiutao/p/10879871.html

https://www.cnblogs.com/weijiutao/p/10880805.html

https://www.cnblogs.com/weijiutao/p/10614694.html

通过 aiqiyi.py 我们就爬取到了我们想要的视频内容,然后将获取到的信息返回给前端页面即可,

前端页面 teplate->index.html 代码如下:

  1 <!DOCTYPE html>
  2 <html lang="en">
  3 <head>
  4     <meta charset="UTF-8">
  5     <title>video</title>
  6     <link rel="stylesheet" href="/static/css/element.css">
  7     <link rel="stylesheet" href="/static/css/style.css">
  8     <script src="/static/js/common/vue.js"></script>
  9     <script src="/static/js/common/axios.js"></script>
 10     <script src="/static/js/common/element.js"></script>
 11     <script src="/static/js/common/qs.js"></script>
 12     <script src="/static/js/common/request.js"></script>
 13     <script src="/static/js/common/jquery.js"></script>
 14 </head>
 15 <body>
 16 <div id="app" v-cloak>
 17 
 18 
 19     <el-container>
 20         <el-header>
 21             <template v-for="item in apiLink">
 22                 <el-button type="text" @click="openLinkClick(item.link)">接口[[item.id]]</el-button>
 23             </template>
 24         </el-header>
 25         <el-container class="main_container">
 26             <el-aside width="200px">
 27                 <div class="friends_link">
 28                     <h3>友情链接</h3>
 29                     <template v-for="(item,index) in friendsLink">
 30                         <template v-if="index%3 ==0">
 31                             <a :href="item.link" target="_blank">
 32                                 <el-tag type="warning">[[item.name]]</el-tag>
 33                             </a>
 34                         </template>
 35                         <template v-else-if="index%4 ==0">
 36                             <a :href="item.link" target="_blank">
 37                                 <el-tag type="success">[[item.name]]</el-tag>
 38                             </a>
 39                         </template>
 40                         <template v-else-if="index%5 ==0">
 41                             <a :href="item.link" target="_blank">
 42                                 <el-tag type="primary">[[item.name]]</el-tag>
 43                             </a>
 44                         </template>
 45                         <template v-else-if="index%7 ==0">
 46                             <a :href="item.link" target="_blank">
 47                                 <el-tag type="danger">[[item.name]]</el-tag>
 48                             </a>
 49                         </template>
 50                         <template v-else>
 51                             <a :href="item.link" target="_blank">
 52                                 <el-tag type="info">[[item.name]]</el-tag>
 53                             </a>
 54                         </template>
 55                     </template>
 56                 </div>
 57 
 58             </el-aside>
 59             <el-container>
 60                 <el-main>
 61                     <el-link type="success">将主流网站,如腾讯、爱奇艺、优酷等网站上的播放视频页的 url 链接复制在下方,然后选择接口,点击播放即可</el-link>
 62                     <el-form :inline="true" :model="formCopyLink">
 63                         <el-form-item>
 64                             <el-input v-model="formCopyLink.copyLink" placeholder="请输入内容"></el-input>
 65                         </el-form-item>
 66                         <el-form-item>
 67                             <el-select style=" 120px;" v-model="formCopyLink.apiLink" placeholder="请选择">
 68                                 <el-option
 69                                         v-for="item in apiLink"
 70                                         :key="item.id"
 71                                         :label="'接口'+item.id"
 72                                         :value="item.link"
 73                                 >
 74                                 </el-option>
 75                             </el-select>
 76                         </el-form-item>
 77                         <el-form-item>
 78                             <el-button type="primary" @click="openCopyLinkPlayClick">播放</el-button>
 79                         </el-form-item>
 80                     </el-form>
 81                     <el-link type="success">目前只支持爱奇艺,腾讯视频简单搜索,然后选择视频类型,点击搜索即可,后续功能完善中...</el-link>
 82                     <el-form :inline="true" :model="formTv">
 83                         <el-form-item>
 84                             <el-input v-model="formTv.name" placeholder="请输入内容"></el-input>
 85                         </el-form-item>
 86                         <el-form-item>
 87                             <el-select style=" 120px;" v-model="formTv.type" placeholder="请选择">
 88                                 <el-option label="电视剧" value="1"></el-option>
 89                                 <el-option label="电影" value="2"></el-option>
 90                                 <el-option label="综艺" value="3"></el-option>
 91                             </el-select>
 92                         </el-form-item>
 93                         <el-form-item>
 94                             <el-button type="primary" @click="requestGetTvPlay">搜索</el-button>
 95                         </el-form-item>
 96                     </el-form>
 97 
 98 
 99                     <tv-movie
100                             :tvMovie="aiqiyiData"
101                             @select-link="selectLinkClick"
102                     ></tv-movie>
103 
104                     <tv-movie
105                             :tvMovie="tencentData"
106                             @select-link="selectLinkClick"
107                     ></tv-movie>
108 
109                 </el-main>
110                 <el-footer></el-footer>
111             </el-container>
112         </el-container>
113     </el-container>
114 
115 
116 </div>
117 </body>
118 <script>
119 
120 
121     Vue.component('tv-movie', {
122         delimiters: ["[[", "]]"],
123         props: ['tvmovie'],
124         data: function () {
125             return {}
126         },
127         methods: {
128             selectLinkChange(link) {
129                 this.$emit('select-link', link)
130             }
131         },
132         template: `
133             <div class="tv_movie">
134                 <template v-if="tvmovie">
135                     <h3 class="tv_movie_source">[[tvmovie.source]]</h3>
136                     <div class="tv_movie_content">
137                         <div class="tv_movie_content_left">
138                             <el-image :src="tvmovie.pic"></el-image>
139                         </div>
140                         <div class="tv_movie_content_right">
141                             <div>
142                                 <p>[[tvmovie.name]]</p>
143                             </div>
144                             <div>
145                                 <p>导演:[[tvmovie.director]]</p>
146                                 <p>演员:[[tvmovie.actor]]</p>
147                             </div>
148                             <div>
149                                 <p>简介:[[tvmovie.desc]]</p>
150                             </div>
151                             <div>
152                                 <template v-for="item in tvmovie.list">
153                                     <el-button size="mini" @click="selectLinkChange(item.link)">[[item.title]]
154                                     </el-button>
155                                 </template>
156                             </div>
157                         </div>
158                     </div>
159                 </template>
160             </div>
161 
162         `
163     })
164 
165     let app = new Vue({
166         delimiters: ["[[", "]]"],
167         el: "#app",
168         data: {
169             formCopyLink: {
170                 copyLink: "",
171                 apiLink: "",
172             },
173             formTv: {
174                 name: "",
175                 type: "1",
176             },
177             apiLink: [],
178             friendsLink: [],
179             aiqiyiData: null,
180             tencentData: null,
181             selectLink: null,
182         },
183         mounted() {
184             this.requestGetMockApiLink();
185             this.requestGetMockFriendsLink();
186         },
187         methods: {
188             requestGetTvPlay() {
189                 if (!this.formTv.name) return this.$message.warning("请输入要播放的内容");
190                 let data = {...this.formTv};
191                 requestFunc(null, '/api/tvplay', data, (data) => {
192                     if (!data.aiqiyi) this.$message.warning("爱奇艺没搜到数据");
193                     if (!data.tencent) this.$message.warning("腾讯没搜到数据");
194                     this.aiqiyiData = data.aiqiyi;
195                     this.tencentData = data.tencent;
196                 })
197             },
198             requestGetMockApiLink() {
199                 requestFunc('get', '/static/mock/apiLink.json', null, (data) => {
200                     this.apiLink = data;
201                 })
202             },
203             requestGetMockFriendsLink() {
204                 requestFunc('get', '/static/mock/friendsLink.json', null, (data) => {
205                     this.friendsLink = data;
206                 })
207             },
208             selectLinkClick(link) {
209                 this.selectLink = link;
210             },
211             openLinkClick(link) {
212                 if (!this.selectLink) return this.$message.warning("请选择要播放的剧集");
213                 window.open(link + this.selectLink, '_blank');
214             },
215             openCopyLinkPlayClick() {
216                 if (!this.formCopyLink.copyLink) return this.$message.warning("请输入要播放 url 链接");
217                 if (!this.formCopyLink.apiLink) return this.$message.warning("请选择要播放的接口");
218                 window.open(this.formCopyLink.apiLink + this.selectLink, '_blank');
219             }
220 
221         },
222     });
223 
224 </script>
225 </html>

在上面的代码中,我们使用了 vue+elementUi 来写前端的代码,并且引入了一些本人所知道的一些五花八门的视频网站的友情链接,其中这些友情链接和 Tampermonkey 中的视频解析链接存在了本地的文件 static->mock 的 json 文件中。

就此,一个简单的破解VIP视频的小工具就完成了。有需要代码可以去码云上查看:https://gitee.com/vijtor/video

声明:上面的代码只是一个简单的实现思路,代码中如有不妥之处请大神批评指正!同时本人严正声明尊重知识产权和版权,对于上面的敏感信息不做任何商业用途,如有侵权问题请及时联系本人,蟹蟹!!!

原文地址:https://www.cnblogs.com/weijiutao/p/11677932.html