【Python爬蟲】爬取雲班課資源,活動


寫在前面

最近學校好多老師使用雲班課,在一門課程結束后,想要看看同學們的作業(以活動形式提交的)怎么辦呢?雲班課並沒有給學生端提供批量下載這個功能。
再加上某位老師新發布的教學任務,居然設置了視頻不允許拖動不允許倍速😥,所以正好有時間,想寫個爬蟲再練練手,進行雲班課資源,活動的爬取。
下面將會較為詳細的介紹活動的爬取,這里是交的兩種格式的作業(word和pdf),並在最后給出完整的活動爬取代碼,以及類似的資源(也就是視頻格式的)爬取代碼。

登錄

當我企圖直接使用request庫訪問雲班課的活動頁面時,倒是返回200爬下來了一個html,但是誒怎么找不到想要的鏈接,於是我把這個爬下來的html本地復制了一下,發現如下圖:
在這里插入圖片描述
好吧,還沒有登錄。我們模仿這個登錄的過程有兩種方法,一種是獲得session,另一種是帶着cookies(關於這倆個東西是什么就不介紹啦,其實后文會發現本質都是相同的,相當於你的通行證)。

  • 獲取session:requests庫中已經封裝好了方法requests.session(),我們要做的事情就是

    • 獲取session
    • 根據登錄時發的包(這里需要自己去抓包分析格式),按同樣同樣封裝一個data和header(非必須,有些網站可能會有反爬蟲機制)
    • 讓該session向 登錄網頁(一定是登錄網頁,想想沒登陸的時候會自己重定向到的也是登錄的網頁) 發送這個包,也就是模擬登錄了
    def getsession(account_name, user_pwd):
        logURL = r'https://www.mosoteach.cn/web/index.php?c=passport&m=account_login'
        session = requests.session()
        logHeader = {
                    'Referer': 'https://www.mosoteach.cn/web/index.php?c=passport',
                    'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko'
                    }
        logData = { 
                    'account_name': account_name,
                    'user_pwd': user_pwd,
                    'remember_me': 'Y'            
                    }
        logRES = session.post(logURL, headers=logHeader, data=logData)
        return session
    

    這個時候,如果你print一下session中的屬性,會發現session中有一個字段叫做cookies,是這個樣子滴:
    在這里插入圖片描述
    我們模擬登錄獲取session也是為了讓它自身攜帶着這個cookie去完成后面的工作。

  • 帶着cookies:不用模擬登錄,直接在網頁版上登錄之后,得到自己的cookie

    header = {
        "Cookie": cookie,
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko',
        'Connection': 'Keep-Alive'
    }
    

獲取作業列表

我期望獲得的是這樣一個形式,{“文件名”:“下載url”},並且pdf和word分開下載。首先還是去檢查(網頁上右擊或者F12)一下,怎么才能得到這兩個信息:
在這里插入圖片描述
可能看不清,我給復制到這里來了:

<div class="homework-attachment-row" data-id="331982768" data-type="application/pdf" data-role="RESULT">
     <div class="download-attachment" title="下載"></div>
     <a style="background-image: url(https://static-cdn-oss.mosoteach.cn/mssvc/file-type-icons-v2/icon_res_pdf@2x.png)" target="_black" href="https://www.mosoteach.cn/web/index.php?c=interaction_homework&m=attachment_url&clazz_course_id=5CCEEEB9-7BA3-43EE-ACFD-3A17568924D0&id=331982768&type=VIEW"></a>                            		 
     <div class="attachment-name color-33" title="視覺信息處理與檢索課程報告2020秋 - 人名.pdf">視覺信息處理與檢索課程報告2020秋 - 人名.pdf</div>
</div>

可以發現,每個資源都存在一個類為homework-attachment-row<div>下,而我們用到的是homework-attachment-row下的兩個東西:

  • <a>對應的是url,但是如果點擊這個圖標,實際上是默認瀏覽的。查看“網絡”頁面,點擊下載一下pdf,會發現其真正的url是那一大串href,把最后的VIEW改成DOWNLOAD(哈哈其實我沒看http包的時候就直接猜中了)
  • attachment-name color-33對應的是名字,沒什么好說的

然后就是使用BeautifulSoup庫的一個元素處理和選擇啦,上代碼:

def getdic(url):
    pdfdic, worddic = {}, {}
    # 改成人眼可讀的編碼
    raw_data = session.get(url).content.decode('utf-8')
    data = BeautifulSoup(raw_data, 'html5lib')
    # 獲取每個資源框
    homeworks = data.select('.homework-attachment-row')
    # 對每個資源進行分解處理,獲取name和url
    for homework in homeworks:
        name = homework.select('.attachment-name')[0]['title']
        url = homework.select('a')[0]['href']
        if '.pdf' in name:
            pdfdic[name] = url
        elif ('.doc' in name):
            worddic[name] = url    
    worddic.pop('視覺信息處理與檢索課程報告2020秋 - XXX.doc')
    return pdfdic, worddic

這是我們獲取出來的樣子,結果發現,兩個列表長度不匹配(worddic中多了兩個),可以發現第一個資源中有老師上傳的doc模板,需要pop掉:
在這里插入圖片描述

另外一個。。。是因為當時我使用的是print(1 if ('.docx' or '.docx' in name) else 0),而python執行邏輯是先in再or,永遠為True,所以混進來了一個同學作業里交的視頻'test1_face_result.mp4',我點開一看,是個ai換臉的功能演示,樂半天,感受一下哈哈哈,就離譜。
在這里插入圖片描述

下載

最后,就是下載,對列表中的每一個元素的url發包,獲取bytes,然后按塊寫入!別忘了對url的一個處理,畢竟我們直接分析得到的是VIEW模式。

def download(dic, dir):
    os.makedirs(dir, exist_ok=True)
    for name, url in tqdm(dic.items()):
        url = url.replace("VIEW", "DOWNLOAD")
        # 像目標url地址發送get請求,返回一個response對象
        data = session.get(url=url, stream=True)
        with open(dir+"/"+name, "wb") as f:
            for chunk in data.iter_content(chunk_size=512):
                f.write(chunk)

加個優雅的進度條,看看效果:
在這里插入圖片描述
嗯,很讓人滿意。在這里插入圖片描述
在這里插入圖片描述

代碼

下載資源的(函數體上面已經給出)

import requests
import os
from bs4 import BeautifulSoup
from tqdm import tqdm

# 活動鏈接
inter_url = '填上你瀏覽器上的鏈接,一定是https://www.mosoteach.cn/web/index.php?c=interaction_homework&開頭的'
# 用戶名
account_name = '填上你的用戶名'
# 密碼
user_pwd = '填上你的密碼'
# 你想要保存在的文件夾地址
pdf_dir = "視覺信息處理與檢索報告/pdf"
word_dir = "視覺信息處理與檢索報告/word"

# 模擬登錄
session = getsession(account_name, user_pwd)
# 獲取資源列表
pdfdic, worddic = getdic(inter_url)
# 下載
download(pdfdic, pdf_dir)
download(worddic, word_dir)

下載視頻的

這個還是有點費勁的,因為它收發包的邏輯是這樣的:
在這里插入圖片描述
點擊視頻,發過去的是一個請求,返回的是m3u8文件的下載url,下載這個m3u8,然后用記事本打開,發現:
在這里插入圖片描述
這才是對應的視頻列表,每段10秒鍾左右,真的無語,可能檢測學生有沒有看也是通過這個有沒有請求到最后一個包來判斷的吧。
然后下面就是不斷的發包收包的過程,也是這個博主寫的使用m3u8爬取雲班課視頻的方法
但我老覺得一定有更簡單的途徑,譬如。。。這段html。之所以能找到,是因為有了前面扒活動的經驗,搜了一下DOWNLOAD,而不是按照它網絡中的收發包來檢查的,嘿嘿。
然后,開始行動吧。
在這里插入圖片描述

import requests
import os
from bs4 import BeautifulSoup
from tqdm import tqdm

# 資源鏈接
res_url = '填上你瀏覽器上的鏈接,一定是https://www.mosoteach.cn/web/index.php?c=res&開頭的'
# 用戶名
account_name = '填上你的用戶名'
# 密碼
user_pwd = '填上你的密碼'
# 你想要保存在的文件夾地址
mov_dir = "虛擬現實開發技術"


def getsession(account_name, user_pwd):
    logURL = r'https://www.mosoteach.cn/web/index.php?c=passport&m=account_login'
    session = requests.session()
    logHeader = {
                'Referer': 'https://www.mosoteach.cn/web/index.php?c=passport',
                'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko'
                }
    logData = { 
                'account_name': account_name,
                'user_pwd': user_pwd,
                'remember_me': 'Y'            
                }
    logRES = session.post(logURL, headers=logHeader, data=logData)
    return session

def getdic(url):
    movdic = {}
    # 改成人眼可讀的編碼
    raw_data = session.get(url).content.decode('utf-8')
    data = BeautifulSoup(raw_data, 'html5lib')
    # 獲取每個資源框
    movs = data.select('.res-row-open-enable')
    # 對每個資源進行分解處理,獲取name和url
    for mov in movs:
        name = mov.select('.res-info .overflow-ellipsis .res-name')[0].text
        url = mov['data-href']
        movdic[name] = url
    return movdic


def download(dic, dir):
    os.makedirs(dir, exist_ok=True)
    for name, url in tqdm(dic.items()):
        # 像目標url地址發送get請求,返回一個response對象
        data = session.get(url=url, stream=True)
        with open(dir+"/"+name, "wb") as f:
            for chunk in data.iter_content(chunk_size=512):
                f.write(chunk)

session = getsession(account_name, user_pwd)
movdic = getdic(res_url)
download(movdic, mov_dir)

更新:如何下載指定幾個資源

每次放出資源都要再爬一遍,比較慢,新加一個切片函數,對字典進行處理。

# 從第幾個視頻開始下載,下載到第幾個視頻,隔幾個下一次
# 如果全部下載直接注釋,下面參數不用填
start, end, step = 13, 28, 1

def dicslice(dic, start=None, end=None, step=None):
    return dict(list(dic.items())[start:end:])

session = getsession(account_name, user_pwd)
movdic = getdic(res_url)
resdic = dicslice(movdic, start-1, end)
download(resdic, mov_dir)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM