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