2021141 2021-2022-2 《Python程序设计》实验四报告

课程:《Python程序设计》
班级: 2114
姓名: 杨云泰
学号:20211401
实验教师:wzq
实验日期:2022年5月23日
必修/选修: 公选课

1.实验要求

Python综合应用:爬虫、数据处理、可视化、机器学习、神经网络、游戏、网络安全等。
课代表和各小组负责人收集作业(源代码、视频、综合实践报告)

注:在华为ECS服务器(OpenOuler系统)和物理机(Windows/Linux系统)上使用VIM、PDB、IDLE、Pycharm等工具编程实现。

批阅:注意本次实验不算做实验总分,前三个实验每个实验10分,累计30分。本次实践算入综合实践,打分为25分。
评分标准:
(1)程序能运行,功能丰富。(需求提交源代码,并建议录制程序运行的视频)10分
(2)综合实践报告,要体现实验分析、设计、实现过程、结果等信息,格式规范,逻辑清晰,结构合理。10分。
(3)在实践报告中,需要对全课进行总结,并写课程感想体会、意见和建议等。5分

(4)如果没有使用华为云服务(ECS或者MindSpore均可),本次实践扣10分。

注意:每个人的实验不能重复,课代表先统计大家做的内容并汇总,有重复的需要自行协商。

2.实验分析及设计过程

  • 主要内容:爬取91看剧网视频、解密ts片段、合并上千条ts文件成、MP4文件。(用异步协程的方式)

    一、分析,编程

1、爬取下载91视频网

1.1分析91视频网源代码,做出爬取策略获得m3u8文件。
  • m3u8文件作用:用来存储每一个视频片段url的文件,包含了上千个.ts文件地址。

分析网页源代码

发现有两处有m3u8的url,经过验证发现url":"https://iqiyi.sd-play.com/20211117/BjOG4OZ8/index.m3u8",为本个视频的m3u8的url。
访问该url发现其指向的是另一个m3u8的部分url(如图)

发现只要把这一部分url第一个m3u8文件的url进行合并剪接可获得第二个么m3u8文件url。

访问该url发现找到了.ts下载路径

  • 访问每一个url可获得一个小片段的.ts文件

如果仅使用单线程,由于需要上千次的oi操作会导致下载速度极慢,故需要用异步协程的方式加快下载速度。
又由于异步协程方式是乱序下载切所给url没有任何规律可言,故需重新命名排序,避免片段混乱无法合并。

  • 流程图如下

    看似很简单,实则会碰到很多困难。

1.2代码实现

  • 使用的库
import requests
import re
import aiohttp
import aiofiles
import asyncio
  • 本次由于程序复杂,使用了函数进行包装,程序如下(点击打开):
主函数
if __name__=='__main__':
    url = 'http://91kj.vip/vodplay/180551-4-1.html'
    main(url)

def main(url):
    m3u8_f_url=get_m3u8_url(url)
    get_m3u8(m3u8_f_url)
    m3u8url = dow_m3u8(m3u8_f_url)
    asyncio.run(aio_download())
访问网址获得源代码,正则提取m3u8 url地址
def get_m3u8_url(url):
    res = requests.get(url)
    obj = re.compile(r'"},"url":"(?P<uur>.*?)","url_next":',re.S)
    ul = obj.search(res.text).groups('uur')
    ul=clean(ul)
    return ul
下载第一个m3u8文件,保存在本地
def get_m3u8(url):
    res = requests.get(url)
    with open('first.m3u8',mode='wb') as f:
        f.write(res.content)
拼接获取第二个m3u8 url,下载第二个文件
def dow_m3u8(url):
    with open('first.m3u8',mode='r') as f:
        for i in f:
            if i.startswith("#"):
                continue
            else:
                i.split()
                url_hou=i.split('/',3)[3]
                url_qian=url.split('index.m3u8')[0]
                urlre= url_qian+url_hou
                
    with open("second.m3u8",mode="wb") as f:
        hed = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36 Edg/97.0.1072.62',
        }
        resp = requests.get(urlre,headers=hed)
        f.write(resp.content)
    return urlre
异步协程下载ts文件,并重新命名,生成名字目录list.txt
def modify_text():
    with open('list.txt', "r+") as f:
        f.seek(0)
        f.truncate()

def write(list):
    with open ("list.txt",mode="a+") as f:
        f.write(list)
    
async def download_ts(url,name,session):
    async with session.get(url) as resp:
        async with aiofiles.open(f"lyb/{name}",mode='wb') as f:
            await f.write(await resp.content.read())
    print(f'{name}下载完毕')
    
async def aio_download():
    """执行异步操作 """
    n = 1
    tasks = []
    async with aiohttp.ClientSession() as session:
        async with aiofiles.open('second.m3u8',mode='r',encoding='utf-8') as f:
            modify_text()
            async for line in f:
                    line = line.strip()
                    if line.startswith('#'):
                        continue
                    name = f"{n}.ts"
                    names = name+"\n"
                    write(names)
                    n += 1
                    task = asyncio.create_task(download_ts(line,name,session))
                    tasks.append(task)
            await asyncio.wait(tasks)
  • 第一部分完成。

2、解密ts文件

2.1 分析

打开第二个m3u8文件可见:

ts文件被进行了加密
打开key的url可见:

其中有密钥

  • 流程图如下

2.2代码实现

  • 使用的库
import requests
import re
import aiohttp
import aiofiles
import asyncio
from Crypto.Cipher import AES

  • AES用来解密
    代码:
得到key的url
key_url = m3u8url.split('index.m3u8')[0]+"key.key"

(点击打开)

访问爬取key
def get_ket(url):
    res = requests.get(url)
    res.encoding="utf-8"
    return res.text
异步解密
async def aio_dec(key):
    tasks=[]
    async with aiofiles.open("list.txt",mode="r") as f:
        async for i in f:
            i= i.strip()
            task = asyncio.create_task(dec_ts(i,key))
            tasks.append(task)
            
        await asyncio.wait(tasks)
            

async def dec_ts(name,key):
    aes = AES.new(key=key.encode('utf-8'),  IV=b"0000000000000000",mode=AES.MODE_CBC)
    async with aiofiles.open(f"lyb/{name}",mode="rb") as f1,\
        aiofiles.open(f"temp_lyb/{name}",mode="wb") as f2:
            
            bs = await f1.read()
            await f2.write(aes.decrypt(bs))
        
            print(f"{name}完成")

3、合并ts文件

这部分我是用的是windows的cmd命令进行合并
mac也可找到相应de命令
由于ts文件有上千个,如果一次合成会导致命令过长,运行不成功,经过测试发现在500左右的文件是刚好的。
进行分批合并后再进行合并,生成完整视频。

  • 代码如下(点击打开):
代码
def make(list,name):
    s = '+'.join(list)
    os.system(f"cd temp_lyb & copy /b {s} {name}.mp4")
    print(f"over{name}")

def merge_ts():
    lst = []
    lst2 = []
    n=1
    with open("list.txt",mode="r",encoding="utf-8") as f:
        for i in f:
            i = i.strip()
            lst.append(f'{i}')
            if len(lst)==650:
                make(lst,n)
                n+=1
                lst = []
        make(lst,n)
        for j in range(n):
            j+=1
            lst2.append(f'{j}.mp4')
            make(lst2,'over')

代码运行

调试华为云

  • 1.创建新的华为云
  • 2.在华为云上下载python3.9版本

  • 3.安装对应的库

  • 4.运行结果


在华为云上的文件:

未解密的:

加密后的:

3.实验过程中的问题:

1.第二个m3u8文件中的url没有顺序,爬到的无法排序。

重新名命排序,生成命名后的文件进行传递。

2.在合并第二个m3u8文件时无法用re截取到对应的url

改变方法,用split()

3.在下载ts文件时,异步模块报错但能下载到所有ts文件

发现在Linux上面运行正常不报错,研究了两天,还不知道咋错了,但可以爬到内容,可能是库的问题,就这样了。

4.发现华为云上python是2.7版本,无法使用

网上找升级的教程,重新安装python3.9

5.在爬取别的一些视频时发现第二个m3u8文件的url正确但无法爬取

经过反复测试,不同源的视频有些无法爬到,闪电在线的源可完全正常使用。

6.合并视频的代码过长,无法运行。

进行分段合并让后再合并一次得到完整视频。

4.课程体会

在本学期的课上,老师教了python的基础语法:

  • 变量赋值
  • 运算符及其优先级
  • 基本数据类型
  • 循环语句
  • 列表、元组、字典、集合
  • 字符串与正则表达式
  • 函数
  • 面向对象程序设计
  • 文件操作及异常处理
    也学了一些对于python的应用:
  • Python操作数据库
  • Python爬虫
  • Socket套接字(TCP/UDP)进行通信

对于python的学习,我从上学期已经开始了,在假期也一直再学习python,也看了一些关于python的书,也按照书上的内容,自己制作了一个pygame的小游戏,在这过程中使我受益匪浅。也在开学之后的蓝桥杯python比赛中,获得了名次。
而这个课程对于我来说,课上的内容我已经都学完了,但这个课让我更一次巩固了我的python知识,这门课老师从由浅入深,逐步讲解,相较自学而言更加有系统和条理,能让新手知道从何入手,怎样学习。对于我而言,这门课使我更加深入的学习了爬虫的一些相关知识,学了re正则表达,bs4查找以及lxml的应用,并且初步尝试了异步操作,使我受益良多。

对于课堂的建议:
1.我觉得可以在增加课上测试,在讲完之后直接用云班课考察,及时知道自己的不足。
2.增加课下实践的此数,比如增加一些编程小作业,来增加编程的熟练度。
3.建议老师给一些学习路径,比如要学爬虫或机器学习等时,要从何学起,推荐一些基础的书籍来给新手入门,增加一些学习路径。

  • 人生苦短,我用python
  • 人生苦短,我用python
  • 人生苦短,我用python