近期,《哪吒之魔童降世》在各大視頻軟件可以看了,然而卻是一貫的套路,非會員謝絕觀看!!!只能從國內那些五花八門的視頻網站上找着看了,或者通過之前本人說的 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="width: 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="width: 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。
聲明:上面的代碼只是一個簡單的實現思路,代碼中如有不妥之處請大神批評指正!同時本人嚴正聲明尊重知識產權和版權,對於上面的敏感信息不做任何商業用途,如有侵權問題請及時聯系本人,蟹蟹!!!