1, 输入歌曲名,查找网站中存在的歌曲 idnode
2, 拿歌曲 id 下载歌词 lyricgit
简单的 url 拼接github
先用一个 POST 请求,拿 ID 取音频资源路径,web
再用 GET 请求,拿到音频资源json
搜索歌曲,获取歌词,获取音频资源路径,获取音频资源api
GET 请求,须要配置请求头,浏览器
POST 请求,须要配置请求头和请求体cookie
配置 Session,网络
有一个加解密,具体见 github repo.session
def __init__(self, timeout=60, cookie_path='.'): self.headers = { 'Accept': '*/*', 'Accept-Encoding': 'gzip,deflate,sdch', 'Accept-Language': 'zh-CN,zh;q=0.8,gl;q=0.6,zh-TW;q=0.4', 'Connection': 'keep-alive', 'Content-Type': 'application/x-www-form-urlencoded', 'Host': 'music.x.com', 'Referer': 'http://music.x.com/search/', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36' } self.session = requests.Session() self.session.headers.update(self.headers) self.session.cookies = cookiejar.LWPCookieJar(cookie_path) self.download_session = requests.Session() self.timeout = timeout self.ep = Encrypyed()
封装 Post 请求方法
def post_request(self, url, params): """ Post请求 :return: 字典 """ data = self.ep.encrypted_request(params) resp = self.session.post(url, data=data, timeout=self.timeout) result = resp.json() if result['code'] != 200: click.echo('post_request error') else: return result
def search(self, search_content, search_type, limit=9): """ 搜索API :params search_content: 搜索内容 :params search_type: 搜索类型 :params limit: 返回结果数量 :return: 字典. """ url = 'http://music.x.com/weapi/xxx/get/web?csrf_token=' params = {'s': search_content, 'type': search_type, 'offset': 0, 'sub': 'false', 'limit': limit} result = self.post_request(url, params) return result
拿到搜索结果:
result = self.search(song_name, search_type=1, limit=limit) if result['result']['songCount'] <= 0: click.echo('Song {} not existed.'.format(song_name)) else: songs = result['result']['songs'] if quiet: song_id, song_name = songs[0]['id'], songs[0]['name'] song = Song(song_id=song_id, song_name=song_name, song_num=song_num) return song
下载很简单
lyricUrl = 'http://music.x.com/api/song/lyric/?id={}&lv=-1&csrf_token={}'.format(song_id, csrf) lyricResponse = self.session.get(lyricUrl)
拿到一个 json ,获取里面的歌词,
lyricJSON = lyricResponse.json() lyrics = lyricJSON['lrc']['lyric'].split("\n") lyricList = [] for word in lyrics: time = word[1:6] name = word[11:] p = Node(time, name) lyricList.append(p) json_string = json.dumps([node.__dict__ for node in lyricList], ensure_ascii = False, indent = 4)
写入新建的本地文件
if not os.path.exists(folder): os.makedirs(folder) fpath = os.path.join(folder, str(song_num) + '_' + song_name + '.json') text_file = open(fpath, "w") n = text_file.write(json_string) text_file.close()
url = 'http://music.x.com/weapi/song/enhance/player/url?csrf_token=' csrf = '' params = {'ids': [song_id], 'br': bit_rate, 'csrf_token': csrf} result = self.post_request(url, params) # 歌曲下载地址 song_url = result['data'][0]['url'] # 歌曲不存在 if song_url is None: click.echo('Song {} is not available due to copyright issue.'.format(song_id)) else: return song_url
if not os.path.exists(fpath): resp = self.download_session.get(song_url, timeout=self.timeout, stream=True) length = int(resp.headers.get('content-length')) label = 'Downloading {} {}kb'.format(song_name, int(length/1024))
一边下载,一边看进度
with click.progressbar(length=length, label=label) as progressbar: with open(fpath, 'wb') as song_file: for chunk in resp.iter_content(chunk_size=1024): if chunk: song_file.write(chunk) progressbar.update(1024) 交流基地:630390733