写这篇随笔时,代码已经写完好久了,最近一直在琢磨如何用pyinstaller打包,正好最近开始用博客园,现在才决定写一写(大佬不喜勿喷)
这有个前身版本,我写在CSDN上了,可以去看看,是关于api分析的(只是最后学校开学就断更了,不知道以后有没有机会补上)
好,现在可以进入正题了(●'◡'●)写了点注释供小白参考
下载酷我音乐:
def kuwo(tempath): songid = re.findall(r'.*?play_detail/(\d*)', songurl)[0] audiolink = json.loads( requests.get(f'http://m.kuwo.cn/newh5app/api/mobile/v1/music/src/{songid}').text)['data']['url'] audio = requests.get(audiolink, timeout=10).content # 获取信息 res = requests.get(f'https://m.kuwo.cn/newh5/singles/songinfoandlrc?musicId={songid}').text text = json.loads(res)['data']['songinfo'] name = text['songName'] artists = text['artist'].replace('&', '、') album = text['album'] lyric = '' for i in json.loads(res)['data']['lrclist']: lyric += '[{}:{}.{}]'.format('%02d' % math.floor(float(i['time']) / 60), '%02d' % math.floor(float(i['time']) % 60), ('%.2f' % math.modf(float(i['time']))[0])[2:]) lyric += i['lineLyric'] + '\n' # 保存文件 filename = re.sub(r"[\\/:*?\"<>|]", "", artists) + ' - ' + re.sub(r"[\\/:*?\"<>|]", "", name) with open(path + filename + '.aac', 'wb') as f1: f1.write(audio) f1.close() if len(lyric) != 0: with open(path + filename + '.lrc', 'w', encoding="UTF-8") as f2: f2.write(lyric) f2.close() strcmd = fr'"{tempath}\ffmpeg\bin\ffmpeg.exe" -i "{path + filename}.aac" -acodec libmp3lame "{path + filename}.mp3"' subprocess.call(strcmd, creationflags=0x08000000) os.remove(path + filename + '.aac') file = ID3(path + filename + '.mp3') file['TIT2'] = TIT2(encoding=3, text=name) file['TPE1'] = TPE1(encoding=3, text=artists) file['TALB'] = TALB(encoding=3, text=album) file.save() return f'《{name}》下载完成!'
这当中要注意的是酷我音乐下下来的歌曲文件是aac格式,我调用了ffmpeg把格式转换成了mp3,然后才能调用mutagen库写入歌曲信息,所以运行时要确保ffmpeg在tempath下哦(没有ffmpeg的小朋友请戳这里,当然也可以自己去官网找最新版)。
下载网易云音乐(无法试听的歌下不了):
def wangyi(): songid = re.findall(r'.*?id=(\d*)', songurl)[0] audiolink = requests.get(f'http://music.163.com/song/media/outer/url?id={songid}.mp3', headers={'user-agent': ''}).url if audiolink != 'https://music.163.com/404': audio = requests.get(audiolink).content # 获取信息 res = requests.get(f'https://music.163.com/api/song/detail/?ids=%5B{songid}%5D').text text = json.loads(res)['songs'][0] name = text['name'] album = text['album']['name'] artists = [] for artist in text['artists']: artists.append(artist['name']) artists = '、'.join(artists) lyric = '' lrctext = json.loads(requests.get(f'https://music.163.com/api/song/lyric?id={songid}&lv=1&tv=-1').text) if 'nolyric' not in lrctext: lrc = lrctext['lrc']['lyric'] tlrc = lrctext['tlyric']['lyric'] + '\n' for m in re.compile(r'(\[\d*:\d*.\d*])(.*?)\n').findall(lrc + '\n'): lyric += m[0] + m[1] + ' ' for n in re.compile(r'(\[\d*:\d*.\d*])(.*?)\n').findall(tlrc + '\n'): if n[0] == m[0] and n[1] != m[1]: lyric += n[1] lyric += '\n' # 保存文件 filename = re.sub(r"[\\/:*?\"<>|]", "", artists) + ' - ' + re.sub(r"[\\/:*?\"<>|]", "", name) with open(path + filename + '.mp3', 'wb') as f1: f1.write(audio) f1.close() if len(lyric) != 0: with open(path + filename + '.lrc', 'w', encoding="UTF-8") as f2: f2.write(lyric) f2.close() file = ID3(path + filename + '.mp3') file['TIT2'] = TIT2(encoding=3, text=name) file['TPE1'] = TPE1(encoding=3, text=artists) file['TALB'] = TALB(encoding=3, text=album) file.save() return f'《{name}》下载完成!' else: return f'暂不支持下载'
这里我干了一件有意思的事情,就是在处理歌词这一部分,如果有更好的匹配方法,欢迎留言哦。
最后整理整理,完整代码差不多像这样:
main.py
import requests import re import json from mutagen.id3 import ID3, TIT2, TPE1, TALB import getpass import math import subprocess import os import shutil import sys def kuwo(tempath): ... def wangyi(): ... if __name__ == '__main__': path = r'C:/Users/{}/Music/'.format(getpass.getuser()) tpath = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__))) print('欢迎使用...') songurl = input('请输入:\n') while songurl != 'exit': if 'music.163.com' in songurl: print(wangyi()) elif 'kuwo.cn' in songurl: print(kuwo(tpath)) songurl = input('请输入:\n') shutil.rmtree(tpath) print('感谢使用(* ̄▽ ̄*)')
顺带提一嘴如何使用pyinstaller打包软件,首先生成spec:
pyi-makespec -F -i {ico路径} -n {项目名} main.py
-F是打包成单文件的意思(默认多文件),如果省略-n,第一个脚本的主文件名将作为spec的名字。
然后找到生成的spec(我的在用户文件夹下)修改如下:
... datas=[('C:\\Users...\\ffmpeg', 'ffmpeg')] ...
第一个是资源文件夹的位置,第二个是生成临时目录的名称。如果和我不一样的注意上面的python代码不能照搬!
最后生成exe:
pyinstaller -F {文件名.spec}