1. 程式人生 > 其它 >2021141 2021-2022-2 《Python程式設計》實驗四報告

2021141 2021-2022-2 《Python程式設計》實驗四報告

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