采用tkinter可视化GUI编写的界面,感兴趣的自行查找相关资料学习。
python代码:
import asyncio
import os
import re
import time
import threading
import winreg
from tkinter import *
from urllib import parse
import requests
from lxml import etree
# 127万能音乐下载器
class Music:
def __init__(self):
self.init_Menu()
def init_Menu(self):
self.top = Tk()
self.top.geometry("400x400")
self.top.title("Author:xuhao QQ:916295795 Email:[email protected]")
self.show_main_frame()
def show_main_frame(self):
self.frame = Frame(self.top)
self.label = Label(self.frame,
text='万能音乐下载器V2.0')
self.label.pack()
# 设置数据库地址
self.windowlabel = Label(self.frame,
text='消息栏')
self.windowlabel.pack()
self.cwd = StringVar(self.frame)
self.cwd.set("快输入歌曲信息叭!(*^▽^*)")
# frame容器
self.dirfm = Frame(self.frame)
# 下滑框
self.dirsb = Scrollbar(self.dirfm)
self.dirsb.pack(side=RIGHT, fill=Y)
self.v = StringVar()
self.main = Listbox(self.dirfm, listvariable=self.v, height=15,
width=50, yscrollcommand=self.dirsb.set)
self.dirsb.config(command=self.main.yview)
self.main.pack(side=LEFT, fill=BOTH)
self.dirfm.pack()
# 装载了StringVar
self.dirn = Entry(self.frame, width=50,
textvariable=self.cwd)
self.dirn.pack()
# 又是一个容器
self.bfm = Frame(self.frame)
self.getdata_btn = Button(self.bfm, text='查找歌曲',
command=self.getmusicdata,
activeforeground='white',
activebackground='blue')
self.download_btn = Button(self.bfm, text='下载歌曲',
command=self.selectdownloaddata,
activeforeground='white',
activebackground='blue')
self.clear = Button(self.bfm, text='清空输入',
command=self.clearInput,
activeforeground='white',
activebackground='green')
self.openfiledir = Button(self.bfm, text='歌曲位置',
command=self.openfd,
activeforeground='white',
activebackground='green')
self.quit = Button(self.bfm, text='退出程序',
command=self.top.quit,
activeforeground='white',
activebackground='red')
self.getdata_btn.pack(side=LEFT)
self.download_btn.pack(side=LEFT)
self.clear.pack(side=LEFT)
self.openfiledir.pack(side=LEFT)
self.quit.pack(side=LEFT)
self.bfm.pack()
self.frame.pack()
self.data = []
self.music_path = get_desktop() + '\music\\'
self.insert('☺' * 40)
self.insert('欢迎使用127music音乐下载软件!')
self.insert('☺' * 40)
self.insert('使用步骤:')
self.insert('1.输入歌曲信息')
self.insert('2.点击“查找歌曲”')
self.insert('3.在消息栏中选中歌曲,点击“下载歌曲”开始下载')
self.insert('4.下载成功,歌曲自动保存到桌面上的music文件夹中')
self.insert('5.支持选择多首歌曲同时下载')
self.insert('6.支持断点续传,网络中断后再次下载继承原下载进度')
self.insert('☺' * 40)
def openfd(self):
os.system("start explorer %s" % self.music_path)
def insert(self, str):
self.data.append(str)
self.v.set(self.data)
# 在最底部更新
self.main.see(END)
def deleteAll(self):
self.data = []
self.v.set(self.data)
def refresh(self, str, point):
# 删除全部内容,使用delete指定第一个索引值0和最后一个参数END,即可
# self.main.delete(0,END)
self.data[point] = str
self.v.set(self.data)
# 在最底部更新
# self.main.see(END)
def selectdownloaddata(self):
try:
if len(self.namelist):
if not re.search(r'\d+', self.main.get(ACTIVE)[0:3]).group().isdigit():
self.insert("选择有误呐!o(╥﹏╥)o")
else:
name = self.namelist[int(re.search(r'\d+', self.main.get(ACTIVE)).group()) - 1]
url = self.urllist[int(re.search(r'\d+', self.main.get(ACTIVE)).group()) - 1]
try:
if self.music_path not in os.listdir():
os.makedirs(self.music_path)
if not self.data.__contains__("开始下载=>>>>%s" % name.replace(self.music_path, "")):
self.insert("开始下载=>>>>%s" % name.replace(self.music_path, ""))
self.insert('')
self.insert('')
thread_it(self.download, name, url, len(self.data) - 1)
else:
self.insert('任务已存在队列中')
except FileExistsError:
if not self.data.__contains__("开始下载=>>>>%s" % name.replace(self.music_path, "")):
self.insert("开始下载=>>>>%s" % name.replace(self.music_path, ""))
self.insert('')
self.insert('')
thread_it(self.download, name, url, len(self.data) - 1)
else:
self.insert('任务已存在队列中')
else:
self.insert('请确定选中歌曲喔!o(╥﹏╥)o')
except AttributeError:
self.insert('请确定选中歌曲喔!o(╥﹏╥)o')
def init_music(self):
self.base_url = "http://qcc.flash127.com/sou/"
self.search_url = self.base_url + parse.quote(self.cwd.get()) + ".html"
self.download_url = "http://qcc.flash127.com/public/x.html?id="
self.result_list = []
self.deleteAll()
self.search_music()
def getmusicdata(self):
if len(self.cwd.get()):
self.init_music()
else:
self.insert('输入不能为空呐!o(╥﹏╥)o')
# 清空输入
def clearInput(self):
self.cwd.set("")
def search_music(self):
headers = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate",
"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",
"Cache - Control": "max - age = 0",
"Connection": "keep-alive",
"Cookie": "security_session_verify=834a600229f490fc3016d5915f78a48b; PHPSESSID=0842n462448oq7lf6h6m2v7074; _state=1; qun=4; Hm_lvt_756d7a4b826c7cb664be2d218d441885=1571908857; Hm_lpvt_756d7a4b826c7cb664be2d218d441885=1571910142",
"CSRFCOOKIE": "9D55488F828C0C4B8924A1E5BF41CE02710021DD",
"Host": "qcc.flash127.com",
"Referer": self.search_url,
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0",
}
try:
respose = requests.get(self.search_url, headers=headers)
except Exception:
respose = requests.get(self.search_url, headers=headers)
# print(respose.text)
# print(self.search_url)
result_tip = etree.HTML(respose.text).xpath('//a[@class="moren"]/text()')[0]
self.insert(result_tip)
music_data = etree.HTML(respose.text).xpath('//div[@class="bk_lists"]//li')
for music_item in music_data:
name = music_item.xpath('.//a[@class="m_t"]/@title')[0] + ".mp3"
url = self.download_url + re.findall(r'http:.*?play/(.*?).html',
music_item.xpath('.//a[@class="m_t"]/@href')[0])[0]
item = {"music_name": name, "music_url": url}
self.result_list.append(item)
else:
self.namelist = []
self.urllist = []
for item in self.result_list:
# respose = requests.get(item["music_url"])
# if respose.text != '404!':
self.namelist.append(self.music_path + item["music_name"])
self.urllist.append(item["music_url"])
for i in range(len(self.namelist)):
self.insert(str(i + 1) + "." + self.namelist[i].replace(self.music_path, ""))
else:
if len(self.namelist):
self.insert("请选中下载的歌曲")
else:
self.insert("未搜索到相关结果哟!(ಥ﹏ಥ)")
def download(self, name, url, point):
headers = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate",
"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",
"Cookie": "security_session_verify=212445fef54d2c1beb70138e5d8e382c; Hm_lvt_756d7a4b826c7cb664be2d218d441885=1571908857,1571968691; PHPSESSID=0c2cb1ts7csj2735cung76q8c0; _state=1; qun=4; Hm_lpvt_756d7a4b826c7cb664be2d218d441885=1571969281",
"CSRFCOOKIE": "9D55488F828C0C4B8924A1E5BF41CE02710021DD",
"Host": "qcc.flash127.com",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0",
}
response = requests.get(url, headers=headers)
# 读取本地已下载文件大小
if os.path.exists(name):
finishlength = os.path.getsize(name) # 本地已经下载的文件大小
else:
finishlength = 0
newheaders = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate",
"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",
"Host": "data.flash127.com",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0"
}
# 第一次请求获取文件总长度
newresponse = requests.get(response.url, stream=True, headers=newheaders)
chunksize = 1024
# 每次写入文件的大小
readsize = 1024 * 32
# 获取完整文件大小,单位MB
totallength = int(newresponse.headers['Content-Length'])
filesize = float('%.2f' % (totallength / (chunksize ** 2)))
# 实现断点续传
newheaders['Range'] = 'bytes=%d-' % finishlength
# 添加了新的header,第二次请求下载文件从finishlength开始读取文件
newresponse = requests.get(response.url, stream=True, headers=newheaders)
# 统计下载时间
time_start = time.time() # 开始计时
# "ab"表示追加形式写入文件
with open(name, 'ab') as f:
download_size = 0
download_rate = 0
download_starttime = time.time()
for data in newresponse.iter_content(chunk_size=readsize):
f.write(data)
# 刷新文件
f.flush()
finishlength += len(data)
now_jd = float('%.2f' % (finishlength / totallength)) * 100
fin_num = int(finishlength / (1024 * 256))
# fin_str = '▮' * int(finishlength / (1024 * 256))
tot_str = '▯' * int(totallength / (1024 * 256))
if time.time() - download_starttime > 2:
download_rate = int((((finishlength - download_size) / chunksize) / 2))
download_size = finishlength
download_starttime = time.time()
if download_rate > 0:
self.refresh("大小:%sMB,下载速度:%sKB/s,预计下载时间:%s秒" % (filesize,
download_rate, int(
((totallength - finishlength) / chunksize) / download_rate)),
point - 1)
else:
self.refresh("大小:%sMB,下载速度:%sKB/s,预计下载时间:计算中..." % (filesize, download_rate),
point - 1)
self.refresh(
"下载进度:%s %d%%" % (
tot_str.replace(tot_str[0:fin_num], tot_str[0:fin_num].replace('▯', '▮'), 1),
now_jd,
), point)
time_end = time.time() # 结束计时
f.close()
time_c = time_end - time_start
self.insert("%s下载完成!(✿◡‿◡)实际下载时间%s秒" % (name.replace(self.music_path, ""), int(time_c)))
def thread_it(func, *args):
'''将函数打包进线程'''
# 创建
t = threading.Thread(target=func, args=args)
# 守护 !!!
t.setDaemon(True)
# 启动
t.start()
# 阻塞--卡死界面!
# t.join()
# loops = asyncio.get_event_loop()
# loops.run_until_complete(main(loops, namelist, urllsit))
# 异步下载文件
# async def download(session, name, url):
# file = await session.get(url)
# filecode = await file.read()
# with open(name, 'wb') as f:
# # 写入文件
# f.write(filecode)
# return str(url)
#
#
# async def main(loop, NAME, URL):
# async with aiohttp.ClientSession() as session:
# # 建立会话session
# try:
# tasks = [loop.create_task(download(session, NAME[_], URL[_])) for _ in range(len(URL))]
# # 建立所有任务
# finished, unfinished = await asyncio.wait(tasks)
# # 触发await,等待任务完成
# all_results = [r.result() for r in finished]
# # 获取所有结果
# self.insert("下载结果:" + str(all_results))
# except aiohttp.ClientResponseError as s:
# return s
# 获取桌面路径
def get_desktop():
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders')
return winreg.QueryValueEx(key, "Desktop")[0]
def main():
Music()
mainloop()
if __name__ == '__main__':
main()
程序可能存在部分bug,欢迎交流指正。