在阅读文章前,可以去了解下ts视频,m3u8是什么,不然可能会影响阅读
英雄联盟的双城之战最近很火,尝试着在第三方视频网站下下载双层之战
目标url
url=https://www.315kc.com/dongman/yingxionglianmengshuangchengzhizhan1/2-1.html
进入网页简单分析一下,打开开发者工具,目的在于获取m3u8资源的来源:于是在快速搜索中搜索m3u8: 在js中匹配到一个url网址,这里我们可以先复制下来去网页看一看:
https:\/\/new.iskcd.com\/20211107\/16gRmf0E\/index.m3u8
进入以后发现下载了个文件,用文本浏览器打开该文件 发现第三行是一个不完整的url 再根据网页请求来看(我的理解是先进行第一次的请求,获取真正的m3u8的地址,再请求真正的m3u8文件的地址,这也是为什么没带“1400kb”的请求会比带了"1400kb”参数请求的要快) 可以尝试用这不完整的url与获取到的url拼接替换一下 得到新的url:
https:
访问该url后发现也是下载一个文件,打开该文件可以发现这就是我们要的ts文件的地址,而且这个地址没有加密,也不是只有部分连接,之后只要对每个链接发起请求就可以了。
整理下思路,我们的逻辑应该是这样的:
- 首先对视频链接发起请求,通过正则的方式匹配在js代码段的第一个m3u8的网址,得到第一个m3u8的文件
- .解析第一个m3u8文件,构造网址,在对获得的m3u8网址发起请求,得到第二个m3u8的网址并下载第二个m3u8文件
- 通过多线程对第二个m3u8文件中的链接分别发起请求并下载全部的ts文件。
- 通过命令将多个ts文件合并成一个ts文件,并且转换格式。(百度方法有很多 这里暂不涉及)
代码如下
import requests
import re
import os
import shutil
from urllib import parse
from lxml import etree
import json
import queue
import chardet
from requests.api import get, request
from random import sample
import codecs
import time
import threading
class HTMLdown(object):
def downurl(self,url):
if url is None:
print('url错误')
return None
while 1:
heads={
"User-Agent":sample(user_agent_list,1)[0]
}
try:
r=requests.get(url=url,headers=heads,timeout=5)
if r.status_code==200 :
return r
except BaseException:
print('url访问失败')
time.sleep(5)
class HTMLparses(object):
def get_first_m3u8_url(self,r):
gz=re.compile(r'"url":"(.*?)",',re.S)
first_m3u8_url=gz.search(r)
first_m3u8_url =first_m3u8_url.group(1)
return first_m3u8_url
def get_second_m3u8_url(self,first_m3u8_url):
with open('1.txt','r',encoding='utf-8') as f:
line_list=f.readlines()
for line in line_list:
if '#' in line:
continue
url_list=parse.urlparse(url=first_m3u8_url)
url_parmas = (url_list.scheme, url_list.netloc, '', '', '', '')
result = parse.urlunparse(url_parmas)
second_m3u8_url=parse.urljoin(result,line[:-1])
return second_m3u8_url
def down_ts(url_q):
global nums,num
while 1:
try:
url=url_q.get_nowait()
except BaseException:
break
re=requests.get(url)
with open('m3u8/'+num%nums,'wb') as ff:
ff.write(re.content)
nums+=1
print(num%nums+'下载完成')
first_url='https://www.315kc.com/dongman/yingxionglianmengshuangchengzhizhan1/2-1.html'
down=HTMLdown()
parses=HTMLparses()
r=down.downurl(first_url).text
first_m3u8_url=parses.get_first_m3u8_url(r).replace('\\','')
print(first_m3u8_url)
r=down.downurl(first_m3u8_url).content
with open('1.txt','wb') as f:
f.write(r)
second_m3u8_url=parses.get_second_m3u8_url(first_m3u8_url)
print(second_m3u8_url)
r=down.downurl(second_m3u8_url).content
with open('2.txt','wb') as f:
f.write(r)
path=r'2.txt'
num='%04d.ts'
nums=0
url_q=queue.Queue()
threads_list=[]
with open(path,'r') as f:
rb_list=f.readlines()
for rb in rb_list:
if '#' in rb:
continue
url_q.put(rb)
threadNum=5
start_time=time.time()
for i in range(threadNum):
t= threading.Thread(target=down_ts,args=(url_q,))
threads_list.append(t)
for t in threads_list:
t.start()
for t in threads_list:
t.join()
end_time=time.time()
print('下载完成 花费%s' % (end_time-start_time))
如果想要获取全集双城之战全集,只要分析出它每一集的网页构成,再完善m3u8文件的拼接,然后通过for循环就可以实现全集资源的获取了。
|