• 学堂在线视频字幕抓取1_分析数据接口


    写在最前:互联网并非法外之地,爬虫仅供技术交流

    运行环境

    • python 3.7.4
    • requests 2.10.0

    爬取目标

    • EDA技术与应用(2020秋)1.1.2 EDA技术概述 教学视频

    分析视频字幕接口

    找接口就只能凭借经验去network里面翻找,或者借助于浏览器调试,没有过多的技巧。

    一、从资源回溯寻找接口

    • 带有视频接口的json文件URL分析

      https://www.xuetangx.com/api/v1/lms/service/playurl/7ED5FE6BE6C6DAC39C33DC5901307461/?appid=10000

      跟其他视频比较,可以得出:

      有一个请求参数,这个参数似乎是固定的,所以不用管。

      7ED5FE6BE6C6DAC39C33DC5901307461是一个路径变量,不同视频有着不同的该参数。

    • 带有字幕接口的json文件URL分析

      https://www.xuetangx.com/api/v1/lms/service/s_t_g_p/

      这个数据是通过POST请求的,数据查看后发现需要一个json对象

      {"c_d":"7ED5FE6BE6C6DAC39C33DC5901307461"}
      

      而且这个c_d与上文视频的路径变量一致。

      所以最后得出请求方案:

      c_d = val
      # method: GET
      # 视频动态URL
      url_video = "https://www.xuetangx.com/api/v1/lms/service/playurl/{}/?appid=10000".format(c_d)
      # method: POST
      # 字幕URL
      url_subtitle = "https://www.xuetangx.com/api/v1/lms/service/s_t_g_p/"
      data = {"c_d":"7ED5FE6BE6C6DAC39C33DC5901307461"}
      
    • 视频接口和字幕接口URL分析

      上面的两个json文件直接提供的视频和字幕的接口URL,所以即使他们的URL还带了其它的参数,我们也不再需要关心这些。

      可能会担心的就是鉴权问题,但是我已经尝试过了,字幕和视频的接口以及这两个json文件都不需要专门的头部信息进行鉴权。

      我们只要找到上面的两个文件,就可进行视频字幕的下载。

      所以我们现在需要找到c_d

    二、从未知变量回溯寻找接口

    • 带有c_d(ccid)的json文件

      我们可以在这个文件下的data中的content_info中的media下找到一个ccidc_d相同,所以我们可以把这里获得的ccid当成变量给下游的URL。

      同时我们还在这个文件下找到了视频相关附件的链接,https://qn-next.xuetangx.com/15679498483925.pptx,同样不需要鉴权就可以下载。

    • 带有c_d(ccid)的json文件URL分析

      https://www.xuetangx.com/api/v1/lms/learn/leaf_info/4227236/6195112/?sign=NCIAE08091001906

      我们可以看到这个新的路径给爬取增加了不少难度,它多出了两个路径变量(4227236/6195112)和一个请求参数(sign=NCIAE08091001906`)。

      而且从这里开始就已经需要鉴权了,头文件得带上相应的参数才可以进行访问。

    • 带有id的json文件

      https://www.xuetangx.com/api/v1/lms/learn/leaf_info/4227236/6195112/?sign=NCIAE08091001906中的6195112是这个文件的leaf_list中每一个json对象的id。我们成功的解决了下游URL的一个变量。

    • 带有c_d(ccid)的json文件URL分析

      https://www.xuetangx.com/api/v1/lms/learn/course/chapter?cid=4227236&sign=NCIAE08091001906

      很幸运的是,下游URL的两个未解决变量在这里出现了,经过这个URL,总体的未知变量没有增多。

      经过两个路由后,我们最后可以得出这样的请求方案:

      cid = val1
      sign = val2
      # method: GET
      # 章节动态URL
      url_chapter = "https://www.xuetangx.com/api/v1/lms/learn/course/chapter?cid={}&sign={}".format(cid, sign)
      leaf_id = response(url_chapter)
      # method: GET
      # 小节动态URL
      url_leaf = "https://www.xuetangx.com/api/v1/lms/learn/leaf_info/{}/{}/?sign={}".format(cid, vid, sign)
      

    三、回溯到头再顺流而下

    • 未解决的问题

      1. "NCIAE08091001906"到底是什么?cid是课程id吗?

        我们可以通过退出再登录,使用其它账户来判断它们是否与用户身份相关;通过等待一段时间看它们是否改变,判断是否与时间有关。我们会发现它们既与用户身份无关也与时间无关

        我们还可以通过浏览器的调试模式去判断这一点。

        最后我们可以得出sign和cid都是课程识别码。

        虽然你可以在进入这门课程学习后,在顶上的URL找到这两个参数。但我依旧想更清楚的解释它们是什么,sign(course_sign)是一门课程的标识,而cid(classroom_id)是一门课程每个学期的标识。这些信息都可以在更高的源头追溯到。

        但这次我们就先追溯到这里。

      2. 关于鉴权的问题。

        我们在爬虫的时候需要考虑清楚地告诉对方服务器我们是什么?

        所以我们需要去看浏览器为我们生成的请求头和其它请求条件呢,这我们可以自己搭一个本地服务,去看requests的请求头和浏览器的有什么区别。

        再通过不断试错,找到当前请求需要的请求头和其它请求条件。

        很庆幸的是,学堂在线我们需要补充修改的请求头参数非常简单。示例如下:

        • 方式一

          # 这里的代码请不要尝试,sessionid我已经安全退出,失去效力。
          # 没有安全退出的话可以保存两周,在此期间可以任意爬取。当然这也跟浏览器的设置有关。
          headers = { "xtbz": "xt" }
          cookies = { "sessionid": "z3rvy7fpp4tqbc4opmzkq1amlvmqde7d" }
          requests.get("https://www.xuetangx.com/api/v1/lms/learn/leaf_info/4227236/6195112/?sign=NCIAE08091001906",headers=headers,cookies=cookies)
          
        • 方式二

          # 方式一直接带上cookie是更好的选择,至少在学堂在线是这样的。
          headers = { "xtbz": "xt", "cookies": "sessionid=z3rvy7fpp4tqbc4opmzkq1amlvmqde7d" }
          requests.get("https://www.xuetangx.com/api/v1/lms/learn/leaf_info/4227236/6195112/?sign=NCIAE08091001906",headers=headers,cookies=cookies)
          
    • 正式顺流而下

      1. 找到sign和cid

        img

      2. 找到cookies

        img

        只需要sessionid就好,其它浏览器找cookies自行百度。

      3. 根据sign和cid请求数据

        import json,requests,time
        
        cid = "4227236"
        sign = "NCIAE08091001906"
        
        # 请求头 仅供参考
        headers = { "xtbz": "xt" }
        cookies = { "sessionid": "z3rvy7fpp4tqbc4opmzkq1amlvmqde7d" }
        
        # 章节信息
        url_chapter = "https://www.xuetangx.com/api/v1/lms/learn/course/chapter?cid={}&sign={}".format(cid, sign)
        time.sleep(0.2)
        chapter = json.loads(requests.get(url_chapter,headers=headers,cookies=cookies).content)
        ## 第一章的第一节的所有小节
        leaf_list = chapter['data']['course_chapter'][0]['section_leaf_list'][0]['leaf_list']
        ## 第一章的第一节的所有视频小节
        video_leaf_list = list(filter(lambda item:item['leaf_type']==0, leaf_list))
        ## 第一章的第一节的第一个视频小节的id
        vid = video_leaf_list[0]['id']
        
        # 视频小节信息
        url_leaf = "https://www.xuetangx.com/api/v1/lms/learn/leaf_info/{}/{}/?sign={}".format(cid, vid, sign)
        time.sleep(0.2)
        video = json.loads(requests.get(url_leaf,headers=headers,cookies=cookies).content)
        
        ## ppt等附件
        url_file = video['data']['content_info']['download'][0]['file_url']
        time.sleep(0.2)
        file = requests.get(url_file).content
        with open('1.pptx','wb') as f:
          f.write(file)
        
        ccid = video['data']['content_info']['media']['ccid']
        ## 视频
        time.sleep(0.2)
        url_video = json.loads(requests.get("https://www.xuetangx.com/api/v1/lms/service/playurl/{}/?appid=10000".format(ccid)).content)['data']['sources']['quality10'][0]
        time.sleep(0.2)
        content_video = requests.get(url_video).content
        with open('1.mp4','wb') as f:
          f.write(content_video)
        ## 字幕
        time.sleep(0.2)
        url_subtitle = json.loads(requests.post("https://www.xuetangx.com/api/v1/lms/service/s_t_g_p/",data={"c_d": ccid},headers=headers).content)['data'][0]['data']
        time.sleep(0.2)
        content_subtitle = requests.get(url_subtitle).text
        with open('1.txt','w') as f:
          f.write(content_subtitle)
        

    写在最后

    上面的代码主要是提供一个思路,实际只用于抓取EDA技术与应用(2020秋)第一章的第一节的第一个视频小节,因为我们不可以保证每一门课的第一章的第一节都有视频小节,也不能保证每一个小节都有附件,每一个视频都有字幕,爬取其它视频还要做容错处理。

    如果想一次爬所有视频也可以实现,用for循环就可以。请记得不要过度频繁地发送请求,会给服务器造成巨大的压力,服务器针对此也有很多的反爬手段。

    爬取的字幕是json数据,想要变成字幕文件还得做相应处理。

    这篇文章还有后续,会继续完善相应功能。

  • 相关阅读:
    计算机硬件知识整理
    cf689d ST表RMQ+二分
    hdu5289 ST表+二分
    hdu5443 ST表裸题:求区间最大
    poj3264 倍增法(ST表)裸题
    cf932d 树上倍增
    zoj3195 联通树上三个点的路径长
    hdu6107 倍增法st表
    hdu2586 lca倍增法
    poj1470 LCA倍增法
  • 原文地址:https://www.cnblogs.com/xuanyu-10-18/p/13731539.html
Copyright © 2020-2023  润新知