当前位置 博文首页 > 用python制作个视频下载器

    用python制作个视频下载器

    作者:不正经的kimol君 时间:2021-07-29 18:48

    目录
    • 前言
    • 一、爬虫分析
      • 1.视频搜索
      • 2.视频下载
    • 二、我的代码
      • 写在最后

        前言

        某个夜深人静的夜晚,夜微凉风微扬,月光照进我的书房~
        当我打开文件夹以回顾往事之余,惊现许多看似杂乱的无聊代码。我拍腿正坐,一个想法油然而生:“生活已然很无聊,不如再无聊些叭”。
        于是,我决定开一个专题,便称之为kimol君的无聊小发明。
        妙…啊~~~

        众所周知,视频是一个学习新姿势知识的良好媒介。那么,如何利用爬虫更加方便快捷地下载视频呢?本文将从数据包分析到代码实现来进行一个相对完整的讲解。

        一、爬虫分析

        本次选取的目标视频网站为某度旗下的好看视频:

        https://haokan.baidu.com
        

        1.视频搜索

        进入主页后,我们可以看到一个搜索框历历在目:

        当我们点击搜索按钮之后,会出现与关键字(ps.这里要考,大家仔细看😋)相匹配的视频,我们需要做的便是抓包来分析其中的请求数据。

        关于抓包工具,可以选择三方工具(如Fiddler或者Burpsuit等),当然也可以选择浏览器自带的调试工具(在浏览器中按F12即可打开)。
        在这里我选择了后者,打开F12调试工具,选择网络:

        在点击搜索按钮之后我们可以看到相应的网络请求出现在下面的工具框中:

        通过简单的查找之后我们可以很容易地发现对应的搜索请求(红框标出部分),其对应的地址为:

        https://haokan.baidu.com/videoui/page/search?query=kimol君666
        

        那么,我们通过requests库来模拟该请求,便可实现搜索视频的功能:

        import requests
        res = requests.get('https://haokan.baidu.com/videoui/page/search?query=xxxxx')# xxxxx表示你需要搜索的关键字
        

        注:这里不需要用到请求头headers,但是不能一概而论。是否需要请求头要根据具体网站分析哦~

        你没有看错,我只用了2行代码便实现了视频网站的搜索功能。有时候,爬虫就是这么简单😉!
        在得到请求后,接下来我们要对这个请求返回的数据进行分析,同样是在F12调试工具中点击右侧的响应便可以看到请求的响应:

        很显然,这里返回的是一个HTML格式的数据,我们只需要通过re库或是bs4库等将我们需要的数据提取出来即可。至此,关于视频搜索的分析基本算是完成了。
        然而!细心的小伙伴会发现,我们现在可以获得搜索结果,但是没办法选择页面呀。对嚯~那咋办呀?

        同样,我们继续抓包分析不就可以了嘛~ 我倒要看看你是怎么翻页的。果然,下滑鼠标之后我们得到了新的请求:

        其请求地址变为了:

        https://haokan.baidu.com/videoui/page/search?pn=2&rn=10&_format=json&tab=video&query=kimol君666

        请求多了pn、rn、_format、tab等参数,而且请求返回的格式也变为了JSON格式(岂不美哉?更方便提取想要的数据了)。通过简单测试可以知道,这些参数分别代表:

        参数 说明
        pn 请求的页码
        rn 每次请求返回的数据量
        _format 请求返回的数据格式
        tab 请求的标签类型

        那么,相应的代码可以改为:

        import requests
        page = 1
        keyword = 'xxxxx' # xxxxx为搜索的关键字
        url = 'https://haokan.baidu.com/videoui/page/search?pn=%d&rn=10&_format=json&tab=video&query=%s'%(page,keyword)
        res = requests.get(url)
        data = res.json()
        

        至此,视频搜索部分的分析算是告于段落了。

        2.视频下载

        视频下载的思路也很清晰,只需进入播放视频的界面找到相应的视频原文件地址即可。
        小手一点,我们便进到了一个视频的播放界面,我们可以发现其URL很有规律:它通过一个vid的参数来指向的相应视频。

        右键视频播放页面查看源码(或者通过右键视频检查元素也可),我们可以找到视频播放的src,其对应的正则表达式为:

        p = '<video class="video" src=(.*?)>'

        那么,我们可以定义一个函数来解析视频的原文件地址:

        def get_videoUrl(vid):
         '''
         提取视频信息中的视频源地址
         '''
         res = requests.get('https://haokan.baidu.com/v?vid=%s'%vid)
         html = res.text
         videoUrl = re.findall('<video class="video" src=(.*?)>',html)[0]
         return videoUrl
        

        输入视频的id参数,将返回视频的真正文件地址。有了视频的地址,要下载视频便是信手拈来:

        def download_video(vid):
         '''
         下载视频文件
         '''
         savePath = 'xxxxx.mp4' # 定义存储的文件名
         videoUrl = get_videoUrl(vid) # 获取视频下载地址 
         res = requests.get(videoUrl)
         with open(savePath,'wb') as f:
         f.write(res.content)

        至此,我们已经可以根据关键字搜索相关的视频,并且可以把视频下载到本地了。这也意味着:关于本次视频下载爬虫的介绍也就结束了,剩下的就是根据自己实际需求对代码进行包装即可。

        二、我的代码

        这里提供一个我自己的代码,仅供参考:

        # =============================================================================
        # 好看视频_v0.1
        # =============================================================================
        import re
        import os
        import time
        import queue
        import requests
        import threading
        import pandas as pd
        
        class Haokan:
         def __init__(self):
         self.url = 'https://haokan.baidu.com/videoui/page/search?pn=%d&rn=20&_format=json&tab=video&query=%s'
         self.headers = {
          'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0',
          'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
          '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',
          'Connection': 'keep-alive',
          'Upgrade-Insecure-Requests': '1',
          'TE': 'Trailers',
         }
         self.savaPath = './videos' # 视频存储路径
         
         def get_info(self,keywords,page):
         '''
         搜索关键字,获取相关视频信息
         '''
         self.result = [] # 相关视频信息
         for p in range(1,page+1):
          res = requests.get(self.url%(p,keywords),headers=self.headers)
          data = res.json()['data']['response']
          videos = data['list']
          self.result.extend(videos)
          print('"第%d页"爬取完成!'%(p+1))
         self.result = pd.DataFrame(self.result)
         self.result.to_excel('%s.xlsx'%keywords,index=False)
         # 定义队列,用于多线程下载视频
         self.url_queue = queue.Queue() 
         for vid,url in zip(self.result['vid'],self.result['url']):
          self.url_queue.put((vid,url))
         
         def get_videoUrl(self,url):
         '''
         提取视频信息中的视频源地址
         '''
         res = requests.get(url,headers=self.headers)
         html = res.text
         videoUrl = re.findall('<video class="video" src=(.*?)>',html)[0]
         return videoUrl
         
         def download_video(self,videoId,videoUrl):
         '''
         下载视频文件
         '''
         # 如果视频存储目录不存在则创建
         if not os.path.exists(self.savaPath):
          os.mkdir(self.savaPath)
         res = requests.get(videoUrl,headers=self.headers)
         with open('%s/%s.mp4'%(self.savaPath,videoId),'wb') as f:
          f.write(res.content)
          
         def run(self):
         while not self.url_queue.empty():
          t_s = time.time()
          vid,url = self.url_queue.get()
          try:
          video_url = self.get_videoUrl(url)
          self.download_video(vid,video_url)
          except:
          print('"%s.mp4"下载失败!'%vid)
          continue
          t_e = time.time()
          print('"%s.mp4"下载完成!(用时%.2fs)'%(vid,t_e-t_s))
          
        if __name__ == "__main__":
         keywords = '多啦A梦'
         page = 1 # 爬取页数,每页20条信息
         t_s = time.time()
         haokan = Haokan()
         haokan.get_info(keywords,page)
         N_thread = 3 # 线程数
         thread_list = []
         for i in range(N_thread):
         thread_list.append(threading.Thread(target=haokan.run))
         for t in thread_list:
         t.start()
         for t in thread_list:
         t.join()
         t_e = time.time()
         print('任务完成!(用时%.2fs)'%(t_e-t_s))
         
        

        运行代码,可以看到小频频全都来到我的碗里了😍~

        写在最后

        今天分享的视频下载算是最基础的了,它宛如一位慈祥的老奶奶,慈眉善目,面带笑容。它没有各种繁琐的反爬机制(甚至连headers都不进行验证),而且数据返回的格式也是极其友好的,就连视频格式也显得如此的温柔。

        我相信在“她”的陪伴下,我们可以走好学习爬虫的第一步。纵使日后我们还将面临IP验证、参数验证、验证码、行为检测、瑞数系统等等诸多反爬考验,也许还需应对视频格式转换等挑战。
        但是,请记住kimol君将始终陪伴在你们身边~

        最后,感谢各位大大的耐心阅读,咋们下次再会~

        jsjbwy
        下一篇:没有了