溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

在python中使用gui怎么實現(xiàn)一個視頻下載功能

發(fā)布時間:2020-11-21 14:56:13 來源:億速云 閱讀:160 作者:Leah 欄目:開發(fā)技術

本篇文章為大家展示了在python中使用gui怎么實現(xiàn)一個視頻下載功能,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

運行效果:

在python中使用gui怎么實現(xiàn)一個視頻下載功能

完整代碼:

# !/usr/bin/python
# -*- coding:utf-8 -*-
# time: 2019/07/02--08:12
__author__ = 'Henry'


'''
項目: B站視頻下載 - GUI版本
版本1: 加密API版,不需要加入cookie,直接即可下載1080p視頻
20190422 - 增加多P視頻單獨下載其中一集的功能
20190702 - 增加視頻多線程下載 速度大幅提升
20190711 - 增加GUI版本,可視化界面,操作更加友好
'''

import requests, time, hashlib, urllib.request, re, json
import imageio
imageio.plugins.ffmpeg.download()
from moviepy.editor import *
import os, sys, threading



from tkinter import *
from tkinter import ttk
from tkinter import StringVar
root=Tk()
start_time = time.time()

# 將輸出重定向到表格
def print(theText):
  msgbox.insert(END,theText+'\n')


# 訪問API地址
def get_play_list(start_url, cid, quality):
  entropy = 'rbMCKn@KuamXWlPMoJGsKcbiJKUfkPF_8dABscJntvqhRSETg'
  appkey, sec = ''.join([chr(ord(i) + 2) for i in entropy[::-1]]).split(':')
  params = 'appkey=%s&cid=%s&otype=json&qn=%s&quality=%s&type=' % (appkey, cid, quality, quality)
  chksum = hashlib.md5(bytes(params + sec, 'utf8')).hexdigest()
  url_api = 'https://interface.bilibili.com/v2/playurl?%s&sign=%s' % (params, chksum)
  headers = {
    'Referer': start_url, # 注意加上referer
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'
  }
  # print(url_api)
  html = requests.get(url_api, headers=headers).json()
  # print(json.dumps(html))
  video_list = []
  for i in html['durl']:
    video_list.append(i['url'])
  # print(video_list)
  return video_list


# 下載視頻
'''
 urllib.urlretrieve 的回調函數(shù):
def callbackfunc(blocknum, blocksize, totalsize):
  @blocknum: 已經(jīng)下載的數(shù)據(jù)塊
  @blocksize: 數(shù)據(jù)塊的大小
  @totalsize: 遠程文件的大小
'''


def Schedule_cmd(blocknum, blocksize, totalsize):
  speed = (blocknum * blocksize) / (time.time() - start_time)
  # speed_str = " Speed: %.2f" % speed
  speed_str = " Speed: %s" % format_size(speed)
  recv_size = blocknum * blocksize

  # 設置下載進度條
  pervent = recv_size / totalsize
  percent_str = "%.2f%%" % (pervent * 100)
  download.coords(fill_line1,(0,0,pervent*465,23))
  root.update()
  pct.set(percent_str)



def Schedule(blocknum, blocksize, totalsize):
  speed = (blocknum * blocksize) / (time.time() - start_time)
  # speed_str = " Speed: %.2f" % speed
  speed_str = " Speed: %s" % format_size(speed)
  recv_size = blocknum * blocksize

  # 設置下載進度條
  f = sys.stdout
  pervent = recv_size / totalsize
  percent_str = "%.2f%%" % (pervent * 100)
  n = round(pervent * 50)
  s = ('#' * n).ljust(50, '-')
  print(percent_str.ljust(6, ' ') + '-' + speed_str)
  f.flush()
  time.sleep(2)
  # print('\r')


# 字節(jié)bytes轉化K\M\G
def format_size(bytes):
  try:
    bytes = float(bytes)
    kb = bytes / 1024
  except:
    print("傳入的字節(jié)格式不對")
    return "Error"
  if kb >= 1024:
    M = kb / 1024
    if M >= 1024:
      G = M / 1024
      return "%.3fG" % (G)
    else:
      return "%.3fM" % (M)
  else:
    return "%.3fK" % (kb)


# 下載視頻
def down_video(video_list, title, start_url, page):
  num = 1
  print('[正在下載P{}段視頻,請稍等...]:'.format(page) + title)
  currentVideoPath = os.path.join(sys.path[0], 'bilibili_video', title) # 當前目錄作為下載目錄
  for i in video_list:
    opener = urllib.request.build_opener()
    # 請求頭
    opener.addheaders = [
      # ('Host', 'upos-hz-mirrorks3.acgvideo.com'), #注意修改host,不用也行
      ('User-Agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:56.0) Gecko/20100101 Firefox/56.0'),
      ('Accept', '*/*'),
      ('Accept-Language', 'en-US,en;q=0.5'),
      ('Accept-Encoding', 'gzip, deflate, br'),
      ('Range', 'bytes=0-'), # Range 的值要為 bytes=0- 才能下載完整視頻
      ('Referer', start_url), # 注意修改referer,必須要加的!
      ('Origin', 'https://www.bilibili.com'),
      ('Connection', 'keep-alive'),
    ]
    urllib.request.install_opener(opener)
    # 創(chuàng)建文件夾存放下載的視頻
    if not os.path.exists(currentVideoPath):
      os.makedirs(currentVideoPath)
    # 開始下載
    if len(video_list) > 1:
      urllib.request.urlretrieve(url=i, filename=os.path.join(currentVideoPath, r'{}-{}.flv'.format(title, num)),reporthook=Schedule_cmd) # 寫成mp4也行 title + '-' + num + '.flv'
    else:
      urllib.request.urlretrieve(url=i, filename=os.path.join(currentVideoPath, r'{}.flv'.format(title)),reporthook=Schedule_cmd) # 寫成mp4也行 title + '-' + num + '.flv'
    num += 1

# 合并視頻(20190802新版)
def combine_video(title_list):
  video_path = os.path.join(sys.path[0], 'bilibili_video') # 下載目錄
  for title in title_list:
    current_video_path = os.path.join(video_path ,title)
    if len(os.listdir(current_video_path)) >= 2:
      # 視頻大于一段才要合并
      print('[下載完成,正在合并視頻...]:' + title)
      # 定義一個數(shù)組
      L = []
      # 遍歷所有文件
      for file in sorted(os.listdir(current_video_path), key=lambda x: int(x[x.rindex("-") + 1:x.rindex(".")])):
        # 如果后綴名為 .mp4/.flv
        if os.path.splitext(file)[1] == '.flv':
          # 拼接成完整路徑
          filePath = os.path.join(current_video_path, file)
          # 載入視頻
          video = VideoFileClip(filePath)
          # 添加到數(shù)組
          L.append(video)
      # 拼接視頻
      final_clip = concatenate_videoclips(L)
      # 生成目標視頻文件
      final_clip.to_videofile(os.path.join(current_video_path, r'{}.mp4'.format(title)), fps=24, remove_temp=False)
      print('[視頻合并完成]' + title)
    else:
      # 視頻只有一段則直接打印下載完成
      print('[視頻合并完成]:' + title)

def do_prepare(inputStart,inputQuality):
  # 清空進度條
  download.coords(fill_line1,(0,0,0,23))
  pct.set('0.00%')
  root.update()
  # 清空文本欄
  msgbox.delete('1.0','end')
  start_time = time.time()
  # 用戶輸入av號或者視頻鏈接地址
  print('*' * 30 + 'B站視頻下載小助手' + '*' * 30)
  start = inputStart
  if start.isdigit() == True: # 如果輸入的是av號
    # 獲取cid的api, 傳入aid即可
    start_url = 'https://api.bilibili.com/x/web-interface/view?aid=' + start
  else:
    # https://www.bilibili.com/video/av46958874/?spm_id_from=333.334.b_63686965665f7265636f6d6d656e64.16
    start_url = 'https://api.bilibili.com/x/web-interface/view?aid=' + re.search(r'/av(\d+)/*', start).group(1)

  # 視頻質量
  # <accept_format><![CDATA[flv,flv720,flv480,flv360]]></accept_format>
  # <accept_description><![CDATA[高清 1080P,高清 720P,清晰 480P,流暢 360P]]></accept_description>
  # <accept_quality><![CDATA[80,64,32,16]]></accept_quality>
  quality = inputQuality
  # 獲取視頻的cid,title
  headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'
  }
  html = requests.get(start_url, headers=headers).json()
  data = html['data']
  cid_list = []
  if '&#63;p=' in start:
    # 單獨下載分P視頻中的一集
    p = re.search(r'\&#63;p=(\d+)',start).group(1)
    cid_list.append(data['pages'][int(p) - 1])
  else:
    # 如果p不存在就是全集下載
    cid_list = data['pages']
  # print(cid_list)
  # 創(chuàng)建線程池
  threadpool = []
  title_list = []
  for item in cid_list:
    cid = str(item['cid'])
    title = item['part']
    title = re.sub(r'[\/\\:*&#63;"<>|]', '', title) # 替換為空的
    print('[下載視頻的cid]:' + cid)
    print('[下載視頻的標題]:' + title)
    title_list.append(title)
    page = str(item['page'])
    start_url = start_url + "/&#63;p=" + page
    video_list = get_play_list(start_url, cid, quality)
    start_time = time.time()
    # down_video(video_list, title, start_url, page)
    # 定義線程
    th = threading.Thread(target=down_video, args=(video_list, title, start_url, page))
    # 將線程加入線程池
    threadpool.append(th)

  # 開始線程
  for th in threadpool:
    th.start()
  # 等待所有線程運行完畢
  for th in threadpool:
    th.join()
  
  # 最后合并視頻
  combine_video(title_list)

  end_time = time.time() # 結束時間
  print('下載總耗時%.2f秒,約%.2f分鐘' % (end_time - start_time, int(end_time - start_time) / 60))

  # 如果是windows系統(tǒng),下載完成后打開下載目錄
  currentVideoPath = os.path.join(sys.path[0], 'bilibili_video') # 當前目錄作為下載目錄
  if (sys.platform.startswith('win')):
    os.startfile(currentVideoPath)



def thread_it(func, *args):
  '''將函數(shù)打包進線程'''
  # 創(chuàng)建
  t = threading.Thread(target=func, args=args) 
  # 守護 !!!
  t.setDaemon(True) 
  # 啟動
  t.start()


if __name__ == "__main__":
  # 設置標題
  root.title('B站視頻下載小助手-GUI')
  # 設置ico
  root.iconbitmap('./Pic/favicon.ico')
  # 設置Logo
  photo = PhotoImage(file='./Pic/logo.png')
  logo = Label(root,image=photo)
  logo.pack()
  # 各項輸入欄和選擇框
  inputStart = Entry(root,bd=4,width=600)
  labelStart=Label(root,text="請輸入您要下載的B站av號或者視頻鏈接地址:") # 地址輸入
  labelStart.pack(anchor="w")
  inputStart.pack()
  labelQual = Label(root,text="請選擇您要下載視頻的清晰度") # 清晰度選擇
  labelQual.pack(anchor="w")
  inputQual = ttk.Combobox(root,state="readonly")
  # 可供選擇的表
  inputQual['value']=('1080P','720p','480p','360p')
  # 對應的轉換字典
  keyTrans=dict()
  keyTrans['1080P']='80'
  keyTrans['720p']='64'
  keyTrans['480p']='32'
  keyTrans['360p']='16'
  # 初始值為720p
  inputQual.current(1)
  inputQual.pack()
  confirm = Button(root,text="開始下載",command=lambda:thread_it(do_prepare,inputStart.get(), keyTrans[inputQual.get()] ))
  msgbox = Text(root)
  msgbox.insert('1.0',"對于單P視頻:直接傳入B站av號或者視頻鏈接地址\n(eg: 49842011或者https://www.bilibili.com/video/av49842011)\n對于多P視頻:\n1.下載全集:直接傳入B站av號或者視頻鏈接地址\n(eg: 49842011或者https://www.bilibili.com/video/av49842011)\n2.下載其中一集:傳入那一集的視頻鏈接地址\n(eg: https://www.bilibili.com/video/av19516333/&#63;p=2)")
  msgbox.pack()
  download=Canvas(root,width=465,height=23,bg="white")
  # 進度條的設置
  labelDownload=Label(root,text="下載進度")
  labelDownload.pack(anchor="w")
  download.pack()
  fill_line1 = download.create_rectangle(0, 0, 0, 23, width=0, fill="green")
  pct=StringVar()
  pct.set('0.0%')
  pctLabel = Label(root,textvariable=pct)
  pctLabel.pack()
  root.geometry("600x800")
  confirm.pack()
  # GUI主循環(huán)
  root.mainloop()  

上述內容就是在python中使用gui怎么實現(xiàn)一個視頻下載功能,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。

AI