【Python工具】Python实现一款支持各大平台的视频下载器 | 附源码
生活随笔
收集整理的這篇文章主要介紹了
【Python工具】Python实现一款支持各大平台的视频下载器 | 附源码
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
相關(guān)文件
想學(xué)Python的小伙伴可以關(guān)注小編的公眾號(hào)【Python日志】
有很多的資源可以白嫖的哈,不定時(shí)會(huì)更新一下Python的小知識(shí)的哈!!
需要源碼的小伙伴可以在公眾號(hào)回復(fù)視頻下載器
簡(jiǎn)介
一款簡(jiǎn)單易用的視頻下載器,目前支持的平臺(tái)如下:
開發(fā)環(huán)境
Python版本:3.7.8
相關(guān)模塊:
requests模塊;
tqdm模塊;
pyfreeproxy模塊;
pyecharts模塊;
以及一些python自帶的模塊。
環(huán)境搭建
安裝Python并添加到環(huán)境變量,pip安裝需要的相關(guān)模塊即可。
效果展示
直接輸入我們的一個(gè)視頻鏈接就可以直接下載到文件夾downloaded中
復(fù)制嗶哩嗶哩視頻鏈接
b站視頻鏈接
https://www.bilibili.com/video/BV1si4y1y76f?spm_id_from=333.999.0.0
然后就可以直接播放我們的視頻啦!!
代碼實(shí)現(xiàn)過(guò)程
主代碼
import sys import copy import json import click if __name__ == '__main__':from modules import *from __init__ import __version__ else:from .modules import *from .__init__ import __version__'''basic info''' BASICINFO = '''************************************************************ Function: 視頻下載器 V%s 微信公眾號(hào): Python日志 操作幫助:輸入r: 重新初始化程序(即返回主菜單)輸入q: 退出程序 視頻保存路徑:當(dāng)前路徑下的%s文件夾內(nèi) ************************************************************''''''視頻下載器''' class videodl():def __init__(self, configpath=None, config=None, **kwargs):assert configpath or config, 'configpath of config should be given...'self.config = loadConfig(configpath) if config is None else configself.logger_handle = Logger(self.config['logfilepath'])self.supported_sources = self.initializeAllSources()'''非開發(fā)人員外部調(diào)用'''def run(self):print(BASICINFO % (__version__, self.config.get('savedir')))while True:# 視頻鏈接輸入user_input = self.dealInput('請(qǐng)輸入視頻鏈接: ')# 判斷視頻鏈接類型是否支持解析下載source = self.findsource(user_input)if source is None:self.logger_handle.warning('暫不支持解析視頻鏈接: %s...' % user_input)continue# 實(shí)例化client = source(self.config, self.logger_handle)# 視頻鏈接解析videoinfos = client.parse(user_input)# 視頻下載client.download(videoinfos)'''判斷視頻源'''def findsource(self, url):for key, source in self.supported_sources.items():if source.isurlvalid(url): return sourcereturn None'''初始化所有支持的搜索/下載源'''def initializeAllSources(self):supported_sources = {'ted': Ted,'cntv': CNTV,'mgtv': MGTV,'migu': Migu,'pipix': Pipix,'acfun': AcFun,'zhihu': Zhihu,'xigua': Xigua,'iqiyi': Iqiyi,'douyin': Douyin,'haokan': Haokan,'bilibili': Bilibili,'pipigaoxiao': Pipigaoxiao,}return supported_sources'''處理用戶輸入'''def dealInput(self, tip=''):user_input = input(tip)if user_input.lower() == 'q':self.logger_handle.info('ByeBye...')sys.exit()elif user_input.lower() == 'r':self.initializeAllSources()self.run()else:return user_input'''cmd直接運(yùn)行''' @click.command() @click.option('-i', '--url', default=None, help='想要下載的視頻鏈接, 若不指定, 則進(jìn)入videodl終端版') @click.option('-l', '--logfilepath', default='videodl.log', help='日志文件保存的路徑') @click.option('-p', '--proxies', default='{}', help='設(shè)置的代理') @click.option('-s', '--savedir', default='videos', help='視頻保存的文件夾') def videodlcmd(url, logfilepath, proxies, savedir):config = {'logfilepath': logfilepath,'proxies': json.loads(proxies),'savedir': savedir,}dl_client = videodl(config=config)if url is None:dl_client.run()else:source = dl_client.findsource(url)client = source(dl_client.config, dl_client.logger_handle)videoinfos = client.parse(url)client.download(videoinfos)'''run''' if __name__ == '__main__':import osrootdir = os.path.split(os.path.abspath(__file__))[0]dl_client = videodl(os.path.join(rootdir, 'config.json'))dl_client.run()bilibili代碼
''' Function:B站視頻下載器類 ''' import re import time from .base import Base from ..utils.misc import *'''B站視頻下載器類''' class Bilibili(Base):def __init__(self, config, logger_handle, **kwargs):super(Bilibili, self).__init__(config, logger_handle, **kwargs)self.source = 'bilibili'self.__initialize()'''視頻解析'''def parse(self, url):response = self.session.get(url, headers=self.headers)bv = re.compile('BV..........').search(url).group()response = self.session.get(self.pagelist_url.format(bv), headers=self.headers)response_json = response.json()cid_list = [item['cid'] for item in response_json['data']]titles = [item.get('part', f'視頻走丟啦_{time.time()}') for item in response_json['data']]download_urls = []for cid in cid_list:response = self.session.get(self.play_url.format(cid, bv), headers=self.headers)response_json = response.json()for item in response_json['data']['durl']:download_urls.append(item['url'])assert len(titles) == len(download_urls)videoinfos = []for idx, download_url in enumerate(download_urls):videoinfo = {'source': self.source,'download_url': download_url,'savedir': self.config['savedir'],'savename': '_'.join([self.source, filterBadCharacter(titles[idx])]),'ext': 'mp4',}videoinfos.append(videoinfo)return videoinfos'''初始化'''def __initialize(self):self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36',}self.pagelist_url = 'https://api.bilibili.com/x/player/pagelist?bvid={}&jsonp=jsonp'self.play_url = 'http://api.bilibili.com/x/player/playurl?&cid={}&bvid={}&qn=80&fnval=0&fnver=0&fourk=1''''判斷視頻鏈接是否屬于該類'''@staticmethoddef isurlvalid(url):valid_hosts = ['bilibili.com/video']for host in valid_hosts:if host in url: return Truereturn False抖音代碼
''' Function:抖音視頻下載器類 ''' import re import json import time import random import requests from .base import Base from ..utils.misc import *'''抖音視頻下載器類''' class Douyin(Base):def __init__(self, config, logger_handle, **kwargs):super(Douyin, self).__init__(config, logger_handle, **kwargs)self.source = 'douyin'self.__initialize()'''視頻解析'''def parse(self, url):url = re.findall(r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', url)[0]response = self.session.get(url)if response.url[:28] == 'https://www.douyin.com/user/':videoinfos = self.multiparse(response)else:videoinfos = self.singleparse(response)return videoinfos'''批量下載用戶的視頻'''def multiparse(self, response):videoinfos = []key = re.findall(r'/user/(.*?)\?', str(response.url))[0]if not key: key = response.url[28: 83]page_count, max_cursor = 35, 0while True:url = self.uid_url.format('post', key, page_count, max_cursor)response = self.session.get(url, headers=self.headers)response_json = json.loads(response.content.decode())max_cursor, aweme_list = response_json['max_cursor'], response_json['aweme_list']if max_cursor == 0: breakfor idx in range(min(page_count, len(aweme_list))):download_url = str(aweme_list[idx].get('video', {}).get('play_addr', {}).get('url_list', [''])[0])videoinfo = {'source': self.source,'aweme_id': aweme_list[idx].get('aweme_id', None),'download_url': download_url,'savedir': self.config['savedir'],'savename': '_'.join([self.source, filterBadCharacter(str(aweme_list[idx].get('desc', f'視頻走丟啦_{time.time()}')))]),'ext': 'mp4',}if videoinfo['download_url']: videoinfos.append(videoinfo)time.sleep(random.random() + 0.2)return videoinfos'''下載單個(gè)視頻'''def singleparse(self, response):url = self.iteminfo_url.format(re.findall(r'video/(\d+)?', str(response.url))[0])response_json = json.loads(self.session.get(url, headers=self.headers).text)try: download_url = str(response_json['item_list'][0]['video']['play_addr']['url_list'][0]).replace('playwm','play')except: return []videoinfo = {'source': self.source,'download_url': download_url,'savedir': self.config['savedir'],'savename': '_'.join([self.source, filterBadCharacter(str(response_json.get('item_list', [{}])[0].get('desc', f'視頻走丟啦_{time.time()}')))]),'ext': 'mp4',}return [videoinfo]'''初始化'''def __initialize(self):self.headers = {'User-Agent': 'Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Mobile Safari/537.36 Edg/87.0.664.66',}self.iteminfo_url = 'https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids={}'self.uid_url = 'https://www.iesdouyin.com/web/api/v2/aweme/{}/?sec_uid={}&count={}&max_cursor={}&aid=1128&_signature=PDHVOQAAXMfFyj02QEpGaDwx1S&dytk=''''判斷視頻鏈接是否屬于該類'''@staticmethoddef isurlvalid(url):valid_hosts = ['v.douyin.com']for host in valid_hosts:if host in url: return Truereturn False皮皮搞笑視頻
import re import json from .base import Base from ..utils.misc import *'''皮皮搞笑視頻下載器類''' class Pipigaoxiao(Base):def __init__(self, config, logger_handle, **kwargs):super(Pipigaoxiao, self).__init__(config, logger_handle, **kwargs)self.source = 'pipigaoxiao'self.__initialize()'''視頻解析'''def parse(self, url):pattern = re.compile(r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', re.S)url = re.findall(pattern, url)[0]self.headers['Referer'] = urltry:mid = re.findall('mid=(\d+)', url, re.S)[0]pid = re.findall('pid=(\d+)', url, re.S)[0]except:mid = ''pid = url.split('/')[-1]data = {'mid': int(mid) if mid else 'null','pid': int(pid),'type': 'post',}response = self.session.post(self.content_url, data=json.dumps(data), headers=self.headers)response_json = response.json()download_url = response_json['data']['post']['videos'][str(response_json['data']['post']['imgs'][0]['id'])]['url']title = response_json['data']['post']['content'].replace('\n', '')videoinfo = {'source': self.source,'download_url': download_url,'savedir': self.config['savedir'],'savename': '_'.join([self.source, filterBadCharacter(title)]),'ext': 'mp4',}return [videoinfo]'''初始化'''def __initialize(self):self.headers = {'Host': 'share.ippzone.com','Origin': 'http://share.ippzone.com','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36',}self.content_url = 'https://h5.ippzone.com/ppapi/share/fetch_content''''判斷視頻鏈接是否屬于該類'''@staticmethoddef isurlvalid(url):valid_hosts = ['h5.ippzone.com', 'share.ippzone.com']for host in valid_hosts:if host in url: return Truereturn False代碼量太多,小編就不全部展示啦
代碼獲取可以關(guān)注小編公眾號(hào):Python日志
在公眾號(hào)中回復(fù):視頻下載器就可以領(lǐng)取啦
總結(jié)
以上是生活随笔為你收集整理的【Python工具】Python实现一款支持各大平台的视频下载器 | 附源码的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: MES系统读取MySQL数据_MES系统
- 下一篇: websocket python爬虫_p