替朋友下载网课和刷课

作者: sunnnnnnnnnny | 来源:发表于2020-06-18 22:15 被阅读0次

    朋友在学习一个在线课程(http://www.zyyrcw.com/,我帮她将这个课程所有视频离线下载到本地,并替她将刷完了要求的课时。

    开发环境

    • vscode 编辑器
    • anaconda3 python3环境
    • ffmpeg 用来读取视频文件的长度
    • Firefox开放版 用来查看前后端交互的http请求

    爬取所有的视频地址

    课程列表
    #-*- coding:utf-8 -*-
    # 2020年6月18日21:31
    import time
    import json
    import requests,re,sys,pickle
    from bs4 import BeautifulSoup
    import pandas as pd
    
    
    #全局变量
    #reqeusts会话对象
    s = requests.Session()
    
    headers = {
        'User-Agent':"Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0"
    }
    
    #cookies字符串
    cookie_str ="xxx"
    cookies = {}
    
    #将cookies字符串转化成字典格式
    def load_cookies():
        global cookie_str,cookies
        for item in cookie_str.split(';'):
            sep_index = item.find('=') 
            cookies[item[:sep_index]] =item[sep_index+1:]
    
    data = []
    #获取课程视频的下载链接
    def get_video(title,url):
        r = s.get(url,headers = headers,cookies=cookies)
        if r.status_code ==  200:
            #通过正则表达式找到页面中的视频播放链接
            video_url = re.findall(r'"(http://www.zyyrcw.com/static/upfile/subject/.*?)"',r.text)[0]
            print(video_url)
            #将视频的名称,页面链接和下载链接添加到data中
            data.append({
                'title':title,
                'url':url,
                'donwload_url':video_url
            })
    
    
    
    def spider():
        global s,cookie_str,cookies,headers
        url = 'http://www.zyyrcw.com/member/Train'
        #加载cookie
        load_cookies()
        #课程列表7页,page_size=8
        for i in range(0,56,8):
            #课程列表
            url = 'http://www.zyyrcw.com/category/product/6?p=%d' % i
            r = s.get(url,headers = headers,cookies=cookies)
            if r.status_code ==  200:
                #使用bs库提取出每节课的名字和链接
                soup = BeautifulSoup(r.text,'lxml')
                ul = soup.findAll('ul',class_='details-page-02')[0]
                for li in ul.findAll('li'):
                    print(li.a['title'],li.a['href']) 
                    #获取课程视频的下载链接
                    get_video(li.a['title'],li.a['href'])
        #将结果保存为文件
        pickle.dump(data,open('data.db','wb'))
    
    main()
    

    下载所有的视频到本地

    #-*- coding:utf-8 -*-
    import requests
    import pickle
    
    headers = {
        'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0'
    }
    
    #打印出进度条
    def process_bar(percent, start_str='', end_str='', total_length=0):
        bar = '\r' + start_str + ' {:0>4.1f}%|'.format(percent*100) + end_str
        print(bar, end='', flush=False)
    
    #下载视频,video_url为视频的播放地址,filename为保存的文件路径
    def download(video_url,filename):
        with open(filename,'wb') as f:
            #下载视频文件
            r = requests.get(url = video_url, headers=headers,stream=True)
            content_length = int(r.headers['Content-Length'])
    
            download_bytes = 0
            with open(filename, "wb") as f:
                for chunk in r.iter_content(chunk_size=4096):
                    if chunk:
                        f.write(chunk)
                        download_bytes += len(chunk)
                        percent = float(download_bytes / content_length)
                        #print(download_bytes,content_length)
                        process_bar(percent, start_str=filename, end_str='100%', total_length=50)
            print('\n')
            
    
    
    def main():
        data = pickle.load(open('data.db','rb'))
        count = 1
        for item in data:
            #print(item)
            url = item['donwload_url']
            filename = '小儿推拿\\%d.%s%s' % (count, item['title'],url[url.rfind('.'):])
            download(item['donwload_url'],filename)
    
            count += 1
    
    main()
    

    下载器的效果


    image.png

    刷时长

    这个课需要在线时间达到要求的时长才能参加最后的考试,通过观察可以发现在线时长是通过一个post请求更新的。
    页面中有这个一段js。

    //触发页面关闭事件时候提交数据
    //每隔三分钟提交一次数据
    $(function () {
        var ntime, tm, tt;
        var view_id = $('#view_id').val();
        setInterval(function () {
            ntime = $('#time').val();
            tm = ntime.split('.');
            tt = Number(tm[0]);
    
            if (tt % 180 == 0 && tt != 0) {
                $.ajax({
                    type: "Post",
                    url: "/category/log_time",
                    data: { "time": 180, 'id': view_id },
                    error: function () { },
                    success: function (data, textStatus) { }
                });
            };
        }, 1000);
        //触发页面关闭事件时候提交数据
        window.onbeforeunload = function (event) {
            var time_length = $('#time').val() % 180;//提交3分钟以内的剩余时间
            var view_id = $('#view_id').val();
            if (time_length > 0) {
                $.ajax({
                    type: "Post",
                    url: "/category/log_time",
                    data: { "time": time_length, 'id': view_id },
                    error: function () { },
                    success: function (data, textStatus) { }
                });
            };
            //return '请保存好学习笔记!'; 
        };
    });
    

    这段js脚本的意思很简单,就是在视频播放的过程中,每隔3分钟会向后台发送一个post请求,当关闭页面时,会向发现剩下不到3分钟的时长。
    可以使用requests来模拟这个过程,来实现刷时长的功能。
    但是如何获取视频的长度,可以使用ffmpeg来实现,首先在ffmpeg的官网上下载安装包,里面有三个可执行文件,如下图所示。


    image.png

    可以使用下面的命令的来获取视频的长度,单位为秒

    ffprobe -i "xxx.mp4" -show_entries format=duration -v quiet -of csv="p=0"
    

    代码如下

    #-*- coding:utf-8 -*-
    import time
    import json,os
    import requests,re,sys,pickle
    
    #全局变量
    #headers_str中含有cookie,为用户的登录信息
    headers_str = """Host: www.zyyrcw.com
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.0
    Accept: */*
    Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
    Accept-Encoding: gzip, deflate
    Content-Type: application/x-www-form-urlencoded; charset=UTF-8
    X-Requested-With: XMLHttpRequest
    Origin: http://www.zyyrcw.com
    Connection: keep-alive
    Referer: http://www.zyyrcw.com/category/show_view/149
    Cookie: xxx
    Pragma: no-cache
    Cache-Control: no-cache"""
    
    headers = {}
    #headers字符串解析出字典类型
    for line in headers_str.strip().split('\n'):
        k,v = line.strip().split(': ')
        headers[k.strip()] = v.strip()
    print(headers)
    
    #使用ffprobe获取视频的长度
    def get_video_length(input_video):
        cmd = 'ffprobe -i "%s" -show_entries format=duration -v quiet -of csv="p=0"' % input_video
        output =os.popen(cmd,'r')
        output = output.read()
        return str(output).strip()
    
    #提交观看时长,id_为视频的id,video_len为视频的长度
    def post_login_time(id_,video_len):
        url = 'http://www.zyyrcw.com/category/log_time'
        video_len = int(float(video_len))
        #提交的次数
        count = video_len // 180 
        #每次提交3分钟
        for i in range(count):
            data = {
                'time':"180",
                'id':id_
            }
            r = requests.post(url,data = data,headers=headers)
            print(r)
            
        #获取剩下的时长
        t = video_len % 180
        if t:
            data = {
                'time':str(t),
                'id':id_
            }
            r = requests.post(url,data = data,headers=headers)
            print(r)
    #主函数
    def main():
        i = 1
        for item in pickle.load(open('data.db','rb')):
            title = item['title']
            print(title)
            download_url = item['donwload_url']
            url  =item['url']
            id_ = url[url.rfind('/')+1:]
            #视频的本地路径
            filename = '小儿推拿\\%d.%s.%s' % (i, title, download_url[download_url.rfind('.')+1:])
            #获取视频的长度
            video_len = get_video_length(filename)
            #提交观看时长
            post_login_time(id_,video_len)
            i+=1
    main()
    
    
    

    参考资料

    相关文章

      网友评论

        本文标题:替朋友下载网课和刷课

        本文链接:https://www.haomeiwen.com/subject/iehuxktx.html