zoukankan      html  css  js  c++  java
  • 学堂在线视频字幕抓取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数据,想要变成字幕文件还得做相应处理。

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

  • 相关阅读:
    leetcode701. Insert into a Binary Search Tree
    leetcode 958. Check Completeness of a Binary Tree 判断是否是完全二叉树 、222. Count Complete Tree Nodes
    leetcode 110. Balanced Binary Tree
    leetcode 104. Maximum Depth of Binary Tree 111. Minimum Depth of Binary Tree
    二叉树
    leetcode 124. Binary Tree Maximum Path Sum 、543. Diameter of Binary Tree(直径)
    5. Longest Palindromic Substring
    128. Longest Consecutive Sequence
    Mac OS下Android Studio的Java not found问题,androidfound
    安卓 AsyncHttpClient
  • 原文地址:https://www.cnblogs.com/xuanyu-10-18/p/13731539.html
Copyright © 2011-2022 走看看