729 发表于 2020-11-23 14:33

中国大学 MOOC 免费课程及课件爬虫

本帖最后由 729 于 2020-11-23 19:10 编辑

该源码 获取的是下载地址(免费的课程视频以及课件付费课程的PDF文件 视频是经过加密的) 没有进行下载 需要下载的可以调用返回的下载地址即可
老实说 我不会排版 也是第一次写分析过程 所以有啥问题就不要见怪了哈
# 分析过程
## PDF链接分析
> 进入课程主页并全程使用fiddler进行监视
---


> 随便点击文档 在网页右下角中有对应的文档下载 获取下载链接
---


> 使用fiddler 进行搜索查找链接的源头
---


>找到下载链接的源头 获取其头部信息 进行分析
---


>查找两个数据的来源 分析信息
---

>1.分析信息得知 返回的数据是分段的 并且当contentType=3的时候 对应的是PDF文件 其中数据中有许多参数各有其他使用(name之类的) 可以自行判断
>2.分析头部信息
---


>获取termID
---


>PDF:
>1.在访问课程主页的时候获取termID
>2.使用termID获取所用的课程PDF文件对应的contentID已经s.x.id POST访问(https://www.icourse163.org/dwr/call/plaincall/CourseBean.getLastLearnedMocTermDto.dwr)
>3.获取对应的contentID以及s.x.id后POST访问('https://www.icourse163.org/dwr/call/plaincall/CourseBean.getLessonUnitLearnVo.dwr')即可获得对应的下载链接
---
#视频链接获取
>随便点击一个视频进行观看 之前的抓包可以不用清理那么快 因为也需要
>获取对应的视频下载URL(使用的是IDM下载器 所以我这直接出现 )
---

>如果没有IDM直接获取到的也可以进行分析
>当视频播放的时候fidell可以抓包到连续的访问 类型相同的
---


>分析他们的链接 看着相似 找出不同部分进行搜索,发现全部来自同一个访问的返回值
---


>对访问的URL进行查找(实际上这个URL与IDM下载器抓取到的URL是一致的 )里面有好几个URL 对应的是不同的视频清晰度以及格式 可以全部下载试一下
---

>发现其中的URL是简单的GET访问 分析其数据来源 VIDEOID signature
>发现VideoID也属于上面PDF之前的全部课程ID里面 对应contentId
---


>进行sigature头部数据分析
>进行搜索csrfkey来自访问官网时候得到的cookies里面的NTESSTUDYSI值
>bizId是contentI对应的s.x.id

>视频URL获取:
>1.进行官网访问获取csrfkey值
>2获取所有课程contentId 以及对应的s.x.id(文件ID)
>3.根据s.x.id获取对应的signature签名
>4.根据获取到的signature获取所有清晰度以及格式的视频下载链接 打开即可下载
---

# 获取课程主ID##课程主页termId
>key_id=re.search(r'\d+',re.search(r'id : ".+"',requests.get('课程主页URL').text).group()).group()`
>
---               
               
# 获取视频目录以及ID
>payloaddata={'callCount':1,
>    'scriptSessionId':'${scriptSessionId}190',
>    'c0-scriptName':'CourseBean',
>    'c0-methodName':'getMocTermDto',
>    'c0-id':'a',
>    'c0-param0':1207358202,##课程目录ID
>    'c0-param1':0,
>    'c0-param2':'true',
>    'batchId':'1605715313492'}
>   r=requests.post('https://www.icourse163.org/dwr/call/plaincall/CourseBean.getLastLearnedMocTermDto.dwr',data=payloaddata)
>   r.text#这是获得课程的所有视频的ID以及所有文档的ID
>contentType=null##一个章节
>contentType=3##获得的是文档
>contentType=2##单元测试或其他(反正不是文件)
>contentType=1##获取视频


---

# 文档下载可直接获得
>data={
>    'callCount':1,
>    'scriptSessionId':'${scriptSessionId}190',
>    'c0-scriptName':'CourseBean',
>    'c0-methodName':'getLessonUnitLearnVo',
>    'c0-id':0,
>    'c0-param0':'1214812409',##contentId
>    'c0-param1':3,
>    'c0-param2':0,
>    'c0-param3':'1216200842',##s.x.id
>    'batchId':'1605720752677',}
>    url='https://www.icourse163.org/dwr/call/plaincall/CourseBean.getLessonUnitLearnVo.dwr'
>    r=requests.post('url',data=data)##取得其中的textOrigUrl即是下载链接

---


# 视频地址获取步骤:
    1.进入官网获取cookie 其中cookie中的NTESSTUDYSI值是csrfkey值 这是官网防止跨域访问(https://www.icourse163.org)
    2.获取对应的signature   ('https://www.icourse163.org/web/j/resourceRpcBean.getResourceToken.rpc?csrfKey='+csrfkey)##POST访问
      data={'bizId':1260493290,#s.x.id
               'bizType':1,
               'contentType':1}
    3.获取对应的视频m3u8的URL ('https://vod.study.163.com/eds/api/v1/vod/video?videoId='+contentId+'&signature='+signature+'&clientType=1')#GET获取
                clienType=1 #按照上面的获取来说应该是一个视频的标志
                返回值需要的有:videoUrl以及ak 里面有好几个videoUrl对应不同的清晰度以及格式
# 源码
#encoding:utf-8
import requests
import re
from requests import Session
import json

class Mooc:

    def __init__(self,url):
      self.url=url
      self.termId=re.search(r'\d+',re.search(r'termId : ".+"',requests.get(url).text).group()).group()
      self.__GetAllId()

    def __GetAllId(self):
      self.dic={}##总字典
      dic_con={}##每个小章节字典
      file_number=0##每个小章节的文件数
      AllId_url='https://www.icourse163.org/dwr/call/plaincall/CourseBean.getLastLearnedMocTermDto.dwr'##返回课程文件ID以及内容ID
      payloaddata={'callCount':1,
                     'scriptSessionId':'${scriptSessionId}190',
                     'c0-scriptName':'CourseBean',
                     'c0-methodName':'getMocTermDto',
                     'c0-id':'a',
                     'c0-param0':self.termId,##课程目录ID
                     'c0-param1':0,
                     'c0-param2':'true',
                     'batchId':'1605715313492'}##随便啦长度一样的数字吧大概
      r=requests.post(AllId_url,data=payloaddata)##
      list_re=re.compile(r'contentId=.+').findall(r.text)##将返回的数据进行处理分段
      for d in list_re:##遍历每段数据 获取参数值
            contentId=re.search(r'contentId=\d+',d)
            contentType=re.search(r'\d+',re.search(r'contentType=\d',d).group()).group()##文件格式
            file_id=re.search(r'\d+',re.search(r'\.id=\d+',d).group()).group()##文件ID
            name=re.search(r'".+"',re.search(r'name=.+"',d).group()).group().encode('utf8').decode('unicode_escape')
            if contentId and not re.search(r'isTestChecked',d):##确认是否有内容ID 以及是否是课件或者视频
                file_number+=1
                contentId=re.search(r'\d+',contentId.group()).group()
                dic_con={'contentId':contentId,'contentType':contentType,'file_id':file_id,'name':name}
                self.dic=dic_con
            else:
                if re.search(r'published=true',d):##大章节的确认
                  name_all=name##大章节名字
                  self.dic={}
                else:
                  if re.search(r'isTestChecked=false',d):##小章节的确认
                        name_content=name##小章节名字
                        file_number=0##小章节文件数量
                        self.dic={}
#dic格式
#{'第一大章节名':{'第一小章节名':{1(文件数):{'contentId': '课程ID', 'contentType': '文件格式', 'file_id': '文件ID','name':'文件名'},...},
#               '第二小章节名':...},
# '第二章大章节名':...}

                        
    def GetPdf(self):
      pdf_dic={}
      Pdf_url='https://www.icourse163.org/dwr/call/plaincall/CourseBean.getLessonUnitLearnVo.dwr'
      data={
      'callCount':1,
      'scriptSessionId':'${scriptSessionId}190',
      'c0-scriptName':'CourseBean',
      'c0-methodName':'getLessonUnitLearnVo',
      'c0-id':0,
      'c0-param0':'contentId',##contentId
      'c0-param1':3,
      'c0-param2':0,
      'c0-param3':'文件ID',##文件ID
      'batchId':'1606049296413',}
      for p in self.dic.items():
            for d in p.items():
                for f in d.items():
                  if f['contentType']=='3':
                        data['c0-param0']=f['contentId']
                        data['c0-param3']=f['file_id']
                        r=requests.post(Pdf_url,data=data)##取得其中的textOrigUrl即是下载链接
                        pdf_dic]=re.search(r'textUrl:".+"',r.text).group()
      return pdf_dic
## pdf_dic格式
## pdf_dic={'PDF文件名':下载地址,...}返回的是下载地址 没有进行下载 需要的可以自己写一个用来下载的即可

    def GetTs(self):
      ts_dic={}
      s=Session()
      s.get('https://www.icourse163.org')
      csrfkey=s.cookies['NTESSTUDYSI']
      data={'bizId':1260493290,#contentId
               'bizType':1,
               'contentType':1}   
      for v in self.dic.items():#dic.keys()每个大章节的名字 v.keys()每个小章节的名字
            for i in v.items():
                for d in i.items():
                  if d['contentType']=='1':
                        ts_list=[]
                        data['bizId']=d['file_id']
                        ts_url=s.post('https://www.icourse163.org/web/j/resourceRpcBean.getResourceToken.rpc?csrfKey='+csrfkey,data=data)
                        signature=json.loads(ts_url.text)['result']['videoSignDto']['signature']
                        vide_urls=json.loads(s.get('https://vod.study.163.com/eds/api/v1/vod/video?videoId='+d['contentId']+'&signature='+signature+'&clientType=1').text)
                        videos=vide_urls['result']['videos']
                        for url in videos:
                            ts_list.append(url['videoUrl'])
                        ts_dic['name']]=ts_list
      return ts_dic
## ts_dic格式
## ts_dic={'视频文件名':[下载地址1,下载地址2,下载地址3],...}返回的是下载地址 没有进行下载 需要的可以自己写一个用来下载的即可
##使用方法:1.复制代码 创建一个类然后使用其中的方法即可 MOOC.GetPdf()和MOOC.GetTs()返回的是字典调用接口就可以啦

729 发表于 2020-11-24 20:38

Hangjau 发表于 2020-11-24 20:13
老哥贴个链接呢 我也是在论坛下的一个 有点不稳定 有时直接就卡了。

https://www.52pojie.cn/forum.php?mod=viewthread&tid=1027221&highlight=fiddler当时我大概是下载了这个 我看版本信息是一样的 我没更新过 应该是这个了

729 发表于 2020-11-23 15:39

tianyagd 发表于 2020-11-23 15:32
论坛 也有专门的批量下载工具。

嗯嗯确实有了 也用过 不过好像论坛的那个是要登录的 现在的代码只是用PYTHON实现了一次且不需要登录 批量下载的话懒得写上 不过已经有链接就好下载了

yzqhj 发表于 2020-11-23 14:37

楼主可以讲一下分析过程么?

729 发表于 2020-11-23 14:40

yzqhj 发表于 2020-11-23 14:37
楼主可以讲一下分析过程么?

需要分析过程吗?我等等编辑上去吧

yzqhj 发表于 2020-11-23 14:43

729 发表于 2020-11-23 14:40
需要分析过程吗?我等等编辑上去吧

嗯嗯,感谢,最近也在学,想学习一下,分析的过程!

lile2960817 发表于 2020-11-23 14:47

收藏准备学习下

Not小新 发表于 2020-11-23 14:48

收藏学习

鱼小七七七七七 发表于 2020-11-23 14:57

谢谢分享

Lyle61 发表于 2020-11-23 14:59

谢谢分享

Wanggle 发表于 2020-11-23 15:02

谢谢楼主,准备学习下

joshuazm 发表于 2020-11-23 15:05

学习了,谢谢楼主!
页: [1] 2 3 4 5
查看完整版本: 中国大学 MOOC 免费课程及课件爬虫