1. 程式人生 > >教你用Python爬取QQ音樂上的付費專輯

教你用Python爬取QQ音樂上的付費專輯

Hello,there!好久沒寫爬蟲的部落格啦,今天來寫一下怎麼爬取QQ音樂上的付費專輯(理論上所有專輯都可以)。想爬QQ音樂是因為實在沒錢買那些專輯,太多想聽的了!!

附上執行結果截圖:

先說一下需要的環境

系統是:基於Linux的DeepinOS桌面版15.7。為什麼用Linux?因為Terminal啊。

IDE是:PyCharm Community2018

語言&模組:Python3.5+requests+json+pymysql,為什麼用資料庫?因為資料庫好用啊!最近資料庫課設,寫了好多SQL語句。愛上資料庫了。你爬蟲不用re模組或者是BeautifuiSoup?垃圾!我就不用,你打我啊。這又要說到課設了,以前爬蟲總喜歡re.compile(),然後findall()。課設寫伺服器端用到json資料,然後發現Python的json模組也挺好用的。直接和字典互相轉換,不要太爽。其實主要是這次爬蟲都是處理的QQ音樂的json資料。

好了廢話就說這麼多,我們開始吧。

首先呢我們要爬的是,順便也把歌手的一些資訊爬下來,然後再把專輯裡的歌曲儲存到自己的電腦上。

一.分析專輯頁面

1.在瀏覽器中開啟專輯頁面,我用的是Chrome然後開啟開發者模式

第二個箭頭所指的檔案裡有這個專輯的資訊直接雙擊點開:

這裡面有這個專輯的很多資訊:名稱、流派、發行時間、公司.....等等,最重要的是歌曲的資訊(songmid,songname)我們待會兒爬歌曲的時候要用到。先爬這個javascript檔案,進行資料“清洗”,然後儲存到資料庫。資料庫建表的程式碼如下

//歌手錶
CREATE TABLE artists(
name VARCHAR(50),
id VARCHAR(20) NOT NULL PRIMARY KEY,
genre VARCHAR(10),
sex VARCHAR(10),
intro VARCHAR(10000),
area VARCHAR(10)
)engine innodb default charset =utf8;
//專輯表
CREATE TABLE albums(
name VARCHAR(50) NOT NULL,
id VARCHAR(20)NOT NULL PRIMARY KEY,
genre VARCHAR(10),
type VARCHAR(10),
company VARCHAR(20),
intro VARCHAR(1000),
area VARCHAR(10),
time VARCHAR(10)
)engine innodb default charset =utf8;
//歌曲表
CREATE TABLE songs(
name VARCHAR(200) NOT NULL,
id VARCHAR(20)NOT NULL PRIMARY KEY,
genre VARCHAR(10),
language VARCHAR(10),
time VARCHAR(10)
)engine innodb default charset =utf8;
//歌曲專輯關係表
CREATE TABLE so_to_al(
song_id VARCHAR(20),
album_id VARCHAR(20),
FOREIGN KEY (song_id) REFERENCES songs(id),
FOREIGN KEY (album_id) REFERENCES albums(id)
)engine innodb default charset =utf8;
//專輯歌手關係表
CREATE TABLE al_to_ar(
artists_id VARCHAR(20),
album_id VARCHAR(20),
FOREIGN KEY (artists_id) REFERENCES artists(id),
FOREIGN KEY (album_id) REFERENCES albums(id)
)engine innodb default charset =utf8;

爬專輯資訊:

在Headers可以看到專輯資訊的URL,也可以在雙擊開啟的頁面看到。

下面是處理專輯資訊程式碼handle_album_callback.py

import requests
import json
import pymysql
import delete_from_db#在儲存在資料庫之前,先將資料庫裡與這個專輯相關的資料刪除

class Song(object):
    def __init__(self,name,mid):
        self.name = name
        self.mid = mid


def get_album_callback(album_id):
    text = ''
    try:#未登入時的專輯資訊URL
        url = 'https://c.y.qq.com/v8/fcg-bin/fcg_v8_album_info_cp.fcg?albummid='+album_id+'&g_tk=5381&jsonpCallback=albuminfoCallback&loginUin=0&hostUin=0&format=jsonp&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq&needNewCode=0'
        res = requests.get(url)
        text = res.text
    except Exception as e :
        print(e)
    return text


def handle_album_callback(album_id):
    songs =[]
    #去掉多餘的文字
    text = get_album_callback(album_id)
    text = text.replace("albuminfoCallback(","")
    text = text[:-1]
    #用json模組將json轉為python的字典型別(我猜的)
    album_js = json.loads(text)
    singername = album_js['data']['singername']
    singerid = album_js['data']['singermid']
    company = album_js['data']['company']
    aDate = album_js['data']['aDate']
    intro = album_js['data']['desc']
    genre = album_js['data']['genre']
    area = album_js['data']['lan']
    albumname = album_js['data']['name']
    albumid = album_js['data']['mid']
    delete_from_db.delete_from_db(album_id, singerid)
    conn = pymysql.connect(host='localhost',user='root',password='109071',db='musicDB')
    try:
        with conn.cursor() as cursor:
            sql = 'INSERT INTO `artists` VALUES(%s,%s,%s,%s,%s,%s)'
            cursor.execute(sql,(singername,singerid,'test','test','test','test'))
            sql1 = 'INSERT INTO `albums` VALUES(%s,%s,%s,%s,%s,%s,%s,%s)'
            cursor.execute(sql1,(albumname,album_id,genre,"null",company,intro[:100],area,aDate))
            sql2 = 'INSERT INTO `al_to_ar` VALUES(%s,%s)'
            cursor.execute(sql2, (singerid, albumid))
            for k in album_js['data']['list']:
                song = Song("", "")
                song.name = k['songname']
                song.mid = k['songmid']
                songs.append(song)
                sql3 = 'INSERT INTO `songs` VALUES(%s,%s,%s,%s,%s)'
                cursor.execute(sql3,(song.name,song.mid,genre,area,aDate))
                sql4 = 'INSERT INTO `so_to_al` VALUES(%s,%s)'
                cursor.execute(sql4,(song.mid,albumid))
                print(song.name, song.mid)
            conn.commit()
    except Exception as e:
        print(str(e)+'  HAC')
   #將歌曲的mid,和名字返回
    return songs

這時候我們已經拿到了很多資訊了,但是最主要的歌曲沒有弄到。

隨便播放一首能播放的歌:

在Network裡點最長的那個,這個就是我們想要的音樂資料。為了獲取這個資料,我們得先製造這個歌曲資源的URL。而這個歌曲資源的URL裡vkey(祕鑰)是由QQ音樂專門的祕鑰伺服器生成的。這時候我就就要去找哪個檔案裡儲存了伺服器返回的祕鑰。

我們找到了這個檔案,然後在右邊Header裡看到Request URL 裡面有點亂。為了讓這個URL通俗易懂,我們需要用python2裡的urllib模組(我不知道為什麼我的python3裡的urllib模組為啥沒有這個功能)具體用法如下:

其實開發者模式也可以看到這個URL的引數,但是我懶得湊出來。這個URL最主要的引數是guid、songmid和loginUin這三個。這裡需要注意一下,這個是需要登入才能獲得的URL。由於這個我怕騰訊爸爸封我號,所以不敢多爬(手動狗頭)。不登入就不能獲取這個guid,這個東西是用來驗證的,你登入時在服務端生成了這個東西。然後這裡的songmid就是用來區分每一首歌的,這個東西就是我們在處理專輯資訊時返回的Song類的mid。

接下來就是訪問這個URL拿到裡面的vkey:

拿到了這個purl我們就可以湊成歌曲資源的URL了,然後儲存到電腦上。

下面是爬蟲的主程式碼grab_songs,py:

import handle_album_callback
import requests
import generate_song_url
import pymysql
import os

headers={'Accept': '*/*',
'Accept-Encoding': 'identity;q=1, *;q=0',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Connection': 'keep-alive',
'Host': '122.190.14.159',
'Range': 'bytes=0-',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36'}

headers1={'authority': 'u.y.qq.com',
'method': 'GET',
'path': '/cgi-bin/musicu.fcg?callback=getplaysongvkey8040123747165813&g_tk=1617931267&jsonpCallback=getplaysongvkey8040123747165813&loginUin=1090710046&hostUin=0&format=jsonp&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq&needNewCode=0&data={%22req%22:{%22module%22:%22CDN.SrfCdnDispatchServer%22,%22method%22:%22GetCdnDispatch%22,%22param%22:{%22guid%22:%227978049712%22,%22calltype%22:0,%22userip%22:%22%22}},%22req_0%22:{%22module%22:%22vkey.GetVkeyServer%22,%22method%22:%22CgiGetVkey%22,%22param%22:{%22guid%22:%227978049712%22,%22songmid%22:[%22001KKIbk3vD39M%22],%22songtype%22:[0],%22uin%22:%221090710046%22,%22loginflag%22:1,%22platform%22:%2220%22}},%22comm%22:{%22uin%22:1090710046,%22format%22:%22json%22,%22ct%22:20,%22cv%22:0}}',
'scheme': 'https',
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'zh-CN,zh;q=0.9',
'cache-control': 'max-age=0',
'cookie': 'pgv_pvid=7978049712; eas_sid=31h5x3C1H0Q5C7t3C561l6i5D1; pt2gguin=o1090710046; RK=Fhp8FqShTu; ptcz=a5dfc959cadde7f185167913f1ca3dfd0a107e07cb63d2c1cc3d7d20d25e9470; pgv_pvi=7308248064; ptui_loginuin=1090710046; ts_uid=1811149517; wf_tid=1148256b2a52; wf_rid=0fd757881c20; pgv_info=ssid=s1763371196; pgv_si=s8480007168; qqmusic_fromtag=66; ptisp=cnc; ts_refer=xui.ptlogin2.qq.com/cgi-bin/xlogin; uin=o1090710046; [email protected]; luin=o1090710046; lskey=00010000d3eab41a990cfc37b089f29764ec6057a610ff2a499b7bd67dba47affb73c1bf21547356109c9947; p_uin=o1090710046; pt4_token=4qW6bkRx-4GOHiOp-7C2R537dGLrlYlF7aGND6BAfv0_; p_skey=RjDyrGp-*NaDu4nleLdOpBGT7XrY69jy1aU9nAASZSc_; p_luin=o1090710046; p_lskey=00040000bb83c4265423609a0ae3abe12d4b8c3c89535839d24cd70f525a25630f28a623f752260a99036107; yq_index=0; yq_playschange=0; yq_playdata=; player_exist=1; yplayer_open=0; yqq_stat=0; ts_last=y.qq.com/n/yqq/album/001v3NMj3Pi45u.html',
'upgrade-insecure-requests': '1',
'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36'}

def grab_song(album_id):
    album_name = ''
    singer_name = ''
    songs = handle_album_callback.handle_album_callback(album_id)
    conn = pymysql.connect(host='localhost', user='root', password='109071', db='musicDB')
    try:
        with conn.cursor() as cursor:
             sql = 'select name from `albums` where id =%s'
             cursor.execute(sql,album_id)
             album_name = cursor.fetchone()[0]
             sql1 = 'SELECT name FROM artists where id in (SELECT artists_id FROM al_to_ar WHERE album_id = %s)'
             cursor.execute(sql1,album_id)
             singer_name = cursor.fetchone()[0]
    except Exception as e :
        print(str(e)+' GS')
    #path是歌曲的儲存在本機的路徑,請根據自己的電腦路徑修改
    path = '/home/alexhowe/grabed_music/' + album_name+'/'
    if not os.path.exists(path):
        os.mkdir(path)
        print('The song will be stored at '+path)
    for s in songs:
        #請按照上面的方法得到這個獲取vkey的URL(guid處為數字)
        url = 'https://u.y.qq.com/cgi-bin/musicu.fcg?callback=getplaysongvkey8040123747165813&g_tk=1617931267&jsonpCallback=getplaysongvkey8040123747165813&loginUin=1090710046&hostUin=0&format=jsonp&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq&needNewCode=0&data=' \
              '{"req":{"module":"CDN.SrfCdnDispatchServer","method":"GetCdnDispatch","param":' \
              '{"guid":"7978049712","calltype":0,"userip":""}},"req_0":{"module":"vkey.GetVkeyServer",' \
              '"method":"CgiGetVkey","param":{"guid":"7978049712","songmid":["'+s.mid+'"],' \
              '"songtype":[0],"uin":"1090710046","loginflag":1,"platform":"20"}},' \
              '"comm":{"uin":1090710046,"format":"json","ct":20,"cv":0}}'
        res = requests.get(url,headers=headers1)
     #song_url是我們獲取vkey後湊成的歌曲資源URL
        song_url = generate_song_url.gen_song_url(res.text)
        res_song = requests.get(song_url,headers=headers)
        #儲存到本地就不多說了
        with open(path+s.name+'-'+singer_name+'.m4a','wb') as f:
            f.write(res_song.content)
            print(s.name+' by '+singer_name+' has been saved!')
      
if __name__=='__main__':
    grab_song('000h66z521TUCT')#這裡輸入專輯ID

注意主爬蟲程式碼(grab_songs.py)裡的url要自己去登入(https://y.qq.com/)然後按照上面的方法獲取的,其中的guid是阿拉伯數字。然後再像程式碼裡那樣將url裡的songmid引數拼接成"songmid":["’+s.mid+‘"],因為我們要獲取專輯裡每一首歌的vkey。

下面是湊成歌曲資源URL的程式碼generate_song_url.py:

import json

#這個比較簡單就不解釋了,和專輯資訊“清洗”差不多
def gen_song_url(text):
    text = text.replace('getplaysongvkey8040123747165813(','')
    text = text[:-1]
    song_js = json.loads(text)
    url_js = song_js['req_0']['data']['midurlinfo'][0]
    return 'http://122.190.14.159/amobile.music.tc.qq.com/'+url_js['purl']

結語:

好了,到這裡我們爬取QQ音樂的爬蟲程式碼就全部寫好了。總結一下思路:

開啟專輯頁面->在位址列裡可以拿到專輯ID(這是主程式碼grab_songs.py裡grab_song()函式的引數)->獲取到專輯資訊的javascript檔案,然後再用handle_album_callback.py處理並返回Song類->這是已經拿到了songmid和歌曲名字,然後再用songmid去獲取vkey->到generate_song_url.py就把拿到的vkey湊成歌曲資源URL返回。

整個過程是不是很簡單?相信聰明的你一定能理解的~

最後還有一個delete_from_db.py(handle_album_callback.py裡面呼叫了)等著你去寫,沒錯這是一片關於SQL資料庫的部落格!沒想到吧!

注意,程式碼執行前請在第一行新增:# -- coding: utf-8 --(因為添加了註釋)

你要是實在不想寫可以把handle_album_callback.py裡用到的地方刪掉,或者你要是想支援我也行:

點選下載

部落格有點長感謝耐心看完!祝你在Python爬蟲領域所向披靡!

相關推薦

PythonQQ音樂付費專輯

Hello,there!好久沒寫爬蟲的部落格啦,今天來寫一下怎麼爬取QQ音樂上的付費專輯(理論上所有專輯都可以)。想爬QQ音樂是因為實在沒錢買那些專輯,太多想聽的了!! 附上執行結果截圖: 先說一下需要的環境: 系統是:基於Linux的DeepinOS桌面版15

python喜馬拉雅FM音訊,乾貨分享~

前前言 喜馬拉雅已經更換標籤,我重新更新了下程式碼,文章暫時未改,因為思路還是如此,需要的可以掃一下文末公眾號二維碼(本人會在上面發表爬蟲以及java的文章還有送書等資源福利哦),也可以直接搜尋公眾號“ 猿獅的單身日常”,好了廣告結束... 前言 之前寫過爬取圖片的一篇文章,這回來看看如

Python豆瓣圖書Top250

質量、速度、廉價,選擇其中兩個 這篇文章將會用到上一篇文章所講的內容,如果沒有看過可以去看一下教你用Python寫excel 今天我們要做的就是用Python爬取豆瓣圖書Top250,先開啟網站看一下 今天不談這豆瓣圖書top250垃圾不垃圾的問題,只看看怎麼用p

Python妹子圖APP

教你用Python爬美之圖APP(妹子圖) 爬取結果 程式只運行了2h,最後認為程式沒有問題了就關了(我可不是去殺生去了…… 執行環境 Python 3.5+ Windows 10 VSCode 如何使用 下載專案原始碼 https

python QQ音樂

python 爬蟲import requestsimport jsonimport osimport threading#發送請求獲取信息def get_response(url): headers = { 'User-Agent': 'Mozilla/5.0 (M

富貴PHP掘金文章

前言 最近忙完了專案比較空就打算深入學習一些關於爬蟲的知識,以前讀書的時候就喜歡用爬蟲去爬一些學習網站(波多野**老師)。寫這篇部落格是想對之前學習的一些爬蟲知識做一個梳理和交流。希望有大佬指出不足,幫我成長。 新手村任務 下面這些是我2018年這半年業餘時間研究的一些小東西,比較適合剛

15分鐘,Python網站資料,並用BI視覺化分析!

作為一名在資料行業打拼了兩年多的資料分析師,雖然目前收入還算ok,但每每想起房價,男兒三十還未立,內心就不免彷徨不已~ 兩年時間裡曾經換過一份工作,一直都是從事大資料相關的行業。目前是一家企業的BI工程師,主要工作就是給業務部門出報表和業務分析報告。 回想自己過去的工作成績也還算是不錯的,多

Pythonqq音樂的過程例項

一、前言  qq music上的音樂還是不少的,有些時候想要下載好聽的音樂,但有每次在網頁下載都是煩人的登入什麼的。於是,來了個qqmusic的爬蟲。至少我覺得for迴圈爬蟲,最核心的應該就是找到待爬元素所在url吧。   二、Python爬取QQ音樂單曲

Python爬蟲視訊教程:QQ音樂資料(實戰處理+資料視覺化)-劉宇宙-專題視訊課程...

Python爬蟲視訊教程:教你爬取QQ音樂資料(實戰處理+資料視覺化)—704人已學習 課程介紹        本視訊課程主要培訓Python爬蟲入門,資料分析及資料視覺化實戰內容,通過本課的學習,您可以在2小時左右掌握Python基礎程式設計的核心內容,實現Python在爬

Swaggypython實現NBA資料統計的

相信很多喜歡NBA的小夥伴們經常會關注NBA的資料統計,今天我就用虎撲NBA的得分榜為例,實現NBA資料的簡單爬取。https://nba.hupu.com/stats/players是虎撲體育的NBA球員得分榜:當我們右鍵檢視該網站的原始碼時,會發現所有的資料統計都存放在&

Python網易雲音樂的Hip-hop歌單,分析rapper如何押韻

line gone 謠言 大致 -i 態度 大眾 其中 當前 緣起 《中國有嘻哈》這個節目在這個夏天吸引了無數的目光,也讓嘻哈走進了大眾的視野。作為我今年看的唯一一個綜藝節目,它對我的影響也蠻大。這個夏天,我基本都在杭州度過,在上下班的taxi上,我幾乎都在刷這個節目,最後

Python爬蟲:現學現Xpath豆瓣音樂

9.1 tree when href scrapy 發現 pat 直接 where 爬蟲的抓取方式有好幾種,正則表達式,Lxml(xpath)與Beautiful,我在網上查了一下資料,了解到三者之間的使用難度與性能 三種爬蟲方式的對比。 抓取方式 性能 使用難度

Python 多執行緒京東商城商品評論(代理ip請閱讀一篇)

爬蟲永不停息 最近改進上一篇的爬蟲,不爬豆瓣了,改爬一爬京東評論,先放幾張圖研究看看先。 研究了一下,發現商品的id就是連結.html前面的數字。我們把它複製貼上下拉 1,對上一篇的代表進行修改和新增 class Spider(): def

下午不知道吃什麼?Python美團外賣評論幫選餐!

一、介紹 朋友暑假實踐需要美團外賣APP評論這一份資料,一開始我想,這不就抓取網頁原始碼再從中提取資料就可以了嗎,結果發現事實並非如此,情況和之前崔大講過的分析Ajax來抓取今日頭條街拍美圖類似,都是通過非同步載入的方式傳輸資料,不同的是這次的是通過JS傳輸,其他的基本思路基本一致,希望那些資料

獨家 | 手把手Python進行Web抓(附程式碼)

作為一名資料科學家,我在工作中所做的第一件事就是網路資料採集。使用程式碼從網站收集資料,當時對我來說是一個完全陌生的概念,但它是最合理、最容易獲取的資料來源之一。經過幾次嘗試,網路抓取已經成為我的第二天性,也是我幾乎每天使用的技能之一。 在本教程中,我將介紹一個簡單的例子,說明如何抓取一個網站,

10分鐘Python玩轉微信之抓好友個性簽名製作詞雲

01 前言+展示 各位小夥伴我又來啦。今天帶大家玩點好玩的東西,用Python抓取我們的微信好友個性簽名,然後製作詞雲。怎樣,有趣吧~好了,下面開始幹活。我知道你們還是想先看看效果的。 後臺登入: 詞雲: 02 環境準備 Python版本:3.6.0系統平臺:W

python3qq音樂並下載 Python qqmusic音樂url並批量下載

本文參考Python 爬取qqmusic音樂url並批量下載 同學找我爬取一下qq音樂播放連結,包括歌詞等資訊打包成json,試了一下可以爬取。 一、找到qq音樂播放的url 1.找到搜尋頁面返回的資料包 歌曲最終的播放連結時經過多次拼接的,首先找到qq音樂搜尋歌曲介面,https://y.qq.

Python網頁的小說,讓從此告別書荒!

eset 爬取網頁 網站 鏈接 表頭 寫入 改變 span 人生 人生苦短,我用Python。有道愛看小說的小夥伴們,在看小說的期間總會遇到那麽一段書荒期,在這段期間想看書卻找不到,要麽就是要VIP,要麽就是下載不了。所以學會爬取網站上的小說是很有必要的,今天就以爬取筆趣閣

喜歡抖音面的音樂怎麼辦?Python音樂並分類放置資料夾

最近小編也在刷著抖音,上面的小哥哥、小姐姐各個都是人才,小編超喜歡裡面的 歌也挺好聽的,小編就打算把抖音上面歌曲都下載並且分類,把自己的喜歡的歌換成手機鈴聲,那麼抖音上面都有那些好聽的歌呢,比如: 《最美的期待》 周筆暢 《那個人》 周延英 《Panama》 Matteo 《病變