爬虫爬取电影,下载ts并合并ts实例
采用协程方式来爬取ts文件,大大提高了爬取的效率
本次爬取电影内容有key加密,对ts文件进行了解密,并将ts文件合并成mp4视频
代码如下:建议从下往上看
import asyncio #协程的模块
import requests
import re
from Crypto.Cipher import AES #安装pycryptodome,用来解密的模块
import aiofiles #用来协程打开文件
import aiohttp #用来协程请求url
import os
def craw_m3u8(m3u8_url):
'''
抓取m3u8文件,将里面内容写入文件里
'''
headers={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36'
}
#https://play.subokk.com/play/QbYL1EOa/index.m3u8
# return "https:\/\/play.subokk.com\/play\/QbYL1EOa\/index.m3u8"
rep=requests.get(m3u8_url,headers=headers) #访问m3u8的url
with open('m3u8.txt','w',encoding='utf-8') as f:
f.write(rep.text)
return 'm3u8.txt'
async def download(line,session):
''' 下载一个ts视频 '''
filename = line.split('/')[-1] #取文件名
async with session.get(line) as r:
async with aiofiles.open(f'vide/{filename}','wb') as f:
await f.write(await r.content.read()) #因为文件写入还是文件读取都是异步的,所以需要await
# print(f'{filename}ok')
async def craw_ts(file):
''' 读取文件里的每一个ts并访问,将视频下载到新的文件里'''
async with aiohttp.ClientSession() as session: #在这里创建requests模块,这样只需要创建一次,如果在download里面创建则每一次循环都得创建一次
tasks=[]
async with aiofiles.open(file,'r',encoding='utf-8') as f:
async for line in f:
line=line.strip() #去掉空格跟换行符号
if line.startswith('#'):
continue
#异步协程下载每一个视频内容
task=asyncio.create_task(download(line,session)) #download函数是下载一个视频
tasks.append(task)
await asyncio.wait(tasks)
def get_key(key_url):
'''解析key的url,拿到key的内容'''
re=requests.get(key_url)
return re.text
async def dec_ts(filename,key):
'''解密单个视频并写入文件'''
key=bytes(key,'utf-8') #aes.new()里面的key,IV都是传入字节形式
aes=AES.new(key=key,IV=bytes("0000000000000000",'utf-8'),mode=AES.MODE_CBC) #IV中的0个数是看key的长度
async with aiofiles.open(f'vide/{filename}','rb') as f1,\
aiofiles.open(f'vide/tem_{filename}','wb') as f2:
bs=await f1.read() #从源文件里读取内容
await f2.write(aes.decrypt(bs)) #把解密好的东西写入f2中
print(f'{filename},ok')
async def aio_dec(key):
'''解密 异步携程操作'''
tasks=[]
async with aiofiles.open('m3u8.txt','r',encoding='utf-8') as f:
async for line in f:
if line.startswith('#'):
continue
line=line.strip()
filename = line.split('/')[-1]
task=asyncio.create_task(dec_ts(filename,key)) #dec_ts()函数是解密一个ts文件视频
tasks.append(task)
await asyncio.wait(tasks)
def merge_ts():
'''
将ts合并成mp4视频
windows:copy /b 1.ts+2.ts+3.ts xxx.mp4
'''
lst=[]
with open('m3u8.txt','r',encoding='utf-8') as f:
for line in f:
if line.startswith('#'):
continue
line=line.strip()
filename=line.split('/')[-1]
lst.append(f'vide/tem_{filename}')
s="+".join(lst)
os.system(f"copy /b {s} movie.mp4")
print('ok')
def merger():
''' 将所有ts文件合成视频MP4文件'''
with open("vide/movie.mp4", "wb") as f: #创建一个mp4文件,将ts以二进制格式写入
with open("m3u8.txt", "r") as f1:
for line in f1:
if line.startswith("#"):
continue
line = line.strip()
name = line.split('/')[-1]
with open(f'vide/tem_{name}', "rb") as f2: #以二进制格式读取ts文件
f.write(f2.read())
def main(url):
'''
1.访问url,得到页面源码
2.解析源码拿到m3u8的url
3.访问m3u8的url,将内容写入文件
4.拿到文件里的每一个ts的url,请求并以二进制下载ts文件
5.拿到密钥url,访问url并拿到密钥的内容
6.对ts进行解密
7.将所有解密好的ts文件进行合并成mp4文件
'''
r=requests.get(url)
obj=re.compile(r'4f5c"},"url":"(?P<url_>.*)","url_next',re.S) #提取m3u8的地址
m3u8_url=obj.search(r.text).group('url_').replace("\/",'/')
m3u8=craw_m3u8(m3u8_url) #抓取m3u8的文件,将内容写入文件里
#下载所有的ts视频文件
# craw_ts(m3u8)
loop = asyncio.get_event_loop()
loop.run_until_complete(craw_ts(m3u8)) #异步协程来下载所有ts文件视频
#拿到密钥
key_url=os.path.dirname(m3u8_url)+'/enc.key' #密钥key的url
key=get_key(key_url) #访问并拿到key文件里的内容
#解密
asyncio.run(aio_dec(key)) #解密ts文件并生成另一些解密好的文件
#合并解密好的ts文件为mp4文件视频
merger() #我用了merge_ts()方法合并视频但没有用,所以我用二进制读取方式将每一个ts内容放在MP4文件里
#https://play.subokk.com/play/QbYL1EOa/enc.key
#https://play.subokk.com/play/QbYL1EOa/index.m3u8
if __name__=='__main__':
url='https://www.shuangbodb.com/98ju/47235-2-1.html'
main(url)