Python Scrapy的QQ音樂爬蟲 音樂下載、爬取歌曲信息、歌詞、精彩評論

QQ音樂爬蟲(with scrapy)/QQ Music Spider

UPDATE 2019.12.23

已實現對QQ音樂文件的下載,出於版權考慮,不對此部分代碼進行公開。此項目僅做爲學習交流使用,支持正版,人人有責javascript

 

 

項目介紹

  • 在寫一個項目的時候須要用到一些音樂的信息,可是在網上找了許久也沒找到滿意的音樂語料,因而便用scrapy寫了一個QQ音樂的爬蟲
  • 因爲本人只須要用到中文歌曲,因此僅使用該爬蟲爬取了QQ音樂中排名前6400名的內地和港臺歌手的49萬+的歌曲信息,該資源也分享到了百度雲(該資源僅用於學習交流,請勿用於商業用途,若有侵權,請聯繫刪除)
  • QQ音樂的歌曲信息是使用js動態填充的,雖然QQ音樂的歌手和歌曲信息是使用GET進行明文請求,可是開發人員卻在url請求參數上添加了一些冗餘信息,對參數進行了一些加密,所以大部分精力仍是花在瞭解析url上

運行環境

scrapy==1.5.1html

使用方法

進入項目根目錄,運行以下命令便可:scrapy crawl qqmusicjava

歌曲格式

爬取到的歌曲信息保存在根目錄下的music文件中,每一行表示一條歌曲,存儲格式爲jsongit

歌曲的字段說明:github

  • singer_name:歌手名稱,數組形式,由於一首歌可能由多名歌手合唱
  • song_name:歌曲名稱
  • subtitle:歌曲的子標題
  • album_name:專輯名稱
  • singer_id:歌手id,數組形式
  • singer_mid:歌手的mid,數組形式
  • song_time_public:歌曲發行時間
  • song_type:歌曲類型
  • language:歌曲語種
  • song_id:歌曲id
  • song_mid:歌曲mid
  • song_url:歌曲播放的url
  • lyric:歌詞
  • hot_comments:歌曲的精彩評論(此處只爬取了歌曲的精彩評論,部分比較冷門的歌曲有最新評論,可是沒有精彩評論),數組形式。若無精彩評論,置爲"null"
    • comment_name:評論者的暱稱
    • comment_text:評論內容

爬取說好不哭(with 五月天阿信)樣例:正則表達式

{
	'singer_name': ['周杰倫'],
	'song_name': '說好不哭(with 五月天阿信)',
	'subtitle': '',
	'album_name': '說好不哭(with 五月天阿信)',
	'singer_id': [4558],
	'singer_mid': ['0025NhlN2yWrP4'],
	'song_time_public': '2019-09-16',
	'song_type': 0,
	'language': 0,
	'song_id': 237773700,
	'song_mid': '001qvvgF38HVc4',
	'song_url': 'https://y.qq.com/n/yqq/song/001qvvgF38HVc4.html',
	'hot_comments': [{
		'comment_name': 'Cohen',
		'comment_text': '《說好不哭》是聽衆很期待的一個做品,前奏鋼琴曲的漸入和後續的絃樂給整首歌奠基了溫暖的基調。不知道你們有沒有好好去看了這首歌的背景介紹「這是一首關於「約定」和「成全」的情歌,整首歌以鋼琴爲主要故事線,絃樂編織出抒情場景,營造出一種愛情電影的氛圍」。依然的周式情歌,杰倫最總拿捏住每一首歌的感情基調,總能用最精妙的詞曲和編曲打動他的聽衆。\\n\\n這首歌固然在合乎聽衆期待的同時,也給予了咱們些許特別,第二段阿信的加入相信會令很多聽衆感到驚喜。對於我來講,我最喜歡整首歌的鋼琴曲,溫暖純淨感動,或許初遍聽並不是能徹底理解杰倫想要告訴咱們怎樣的一個愛情故事,可是咱們也能從簡單的歌詞和乾淨的旋律裏感覺到情感的部分。'
	}, {
		'comment_name': '野渡無人',
		'comment_text': '「我堅持個人音樂,我喜歡個人音樂,誰叫我是周杰倫。」或許喜歡他,正是由於他對音樂獨有的專一認真,才使人對這個音樂才子着迷。\\n我相信不少人的青春裏都有他,從曾經除了才華一無全部,無人知曉的少年,到現在的現代流行天王,周杰倫用一首首歌陪伴了咱們整個青春,說生如逆旅,多少迷茫和睦餒,卻總能在他的歌聲裏找回本身。今歲不復去歲,人生這條人行道上,兜兜轉轉,仍是一個周杰倫。\\n而這首《說好不哭》更像是一個約定,「你會微笑放手 說好不哭讓我走」 ,而咱們不遠萬里赴約,這就是周杰倫,即青春。\\n'
	}, {
		'comment_name': '是硬糖啊',
		'comment_text': '對於不少80後90後來講,青春或許就這樣悄然慢慢過去了,我依稀還記得那個夏天裏七里香的香味,還有那個唱着《簡單愛》,表情酷酷的男孩。\\n靜靜聽了一遍,仍是那個熟悉的風格,那個熟悉的Jay。也許傑倫的嗓音已經有了變化,可是在歌裏他依舊延續着那份感動。\\n喜歡Jay的歌,忘不了有多少個夜晚的歌單循環,忘不了有多少次的展轉反側。他的歌曲,常常會在某個時間點引起你的共鳴。\\n說好不哭,但是有多少人仍是會淚流滿面,多是由於40歲的杰倫終於發了新歌,也多是由於有些過往,有些感動,真的再也回不去了……'
	}, {
		'comment_name': '墨染梔',
		'comment_text': 'Jay式情歌重磅迴歸,期待了已久的歌。方文山再次做詞走心之做,前奏已沉醉。最驚喜的是阿信獻聲。一個彈琴一個彈吉他,簡直是神仙合做。1分40秒左右旋律是五月天的「忽然好想你,你會在哪裏?」。1分47秒的旋律是《說好的幸福呢》,而後進入阿信的part。杰倫歌裏總能藏着這些細膩。咱們的青春圓滿了。緩緩的鋼琴聲訴說着悽美的愛情。有一種愛叫默默奉獻,無需言語。有一種愛叫放手,你過得幸福就好。距上一次發新歌時隔一年了,40歲的周董是多少人的青春年華,熟悉的旋律是否是依舊耳邊迴盪。從第一張我的專輯《Jay》到現在,咱們熱情不減,周董驚喜不斷。周杰倫——一個表明時代歌手擁有的魅力。說好不哭,你哭了嗎?'
	}, {
		'comment_name': '森島帆高',
		'comment_text': '初中時的哥哥買的一盒盒堆積成山周杰倫封面的磁帶。\\n磁帶放入收音機,磁帶轉動起,每個停頓瞬間,每一首風格獨特,每一句聲聲入耳。從懵懂到成熟,都是喜歡周杰倫的年輪。\\n在這磁帶轉動的年輪裏,歌曲播放的列表裏,生活情緒的喜悲裏,一塵不變的仍是周杰倫的歌。\\n他的歌包攬了個人一整個年少,度過了個人大半個學生時代,陪伴了個人無數個孤獨夜晚。\\n百聽不厭多是對他的歌最完美的詮釋吧。\\n周杰倫是個人信念,是個人力量。\\n現在哥哥也已經參加工做,個人學生時代也轉瞬即逝。\\n對周杰倫的喜歡怕是聽着他音樂的旋律融到了內心,伴隨而去了吧。'
	}, {
		'comment_name': '玫瑰少年',
		'comment_text': '今年,杰倫40歲了,但我腦海中卻仍是那個充滿個性,說着「可不能夠多唱歌少講話」的男孩子....《說好不哭》其實可能也是杰倫的內心話,可能之後出歌不會像之前那樣快了,也在擔憂本身歌曲是否還能符合粉絲的要求,但說好不哭哦。\\n我相信對於不少粉絲來講,杰倫已經給予了一個完整的音樂海洋,不管傷心快樂,他好像總有爲你匹配的歌曲,時時刻刻呵護着本身的情感,即便在各種歌曲百花齊放的今天,每個夜晚依舊喜歡在他的歌聲中入睡。\\n不會哭的,不管過去仍是將來,咱們仍是願意讓你的歌聲陪伴着咱們,陪伴着整個青春,陪伴一生。'
	}, {
		'comment_name': '蝸牛..',
		'comment_text': '我想,你的青春裏必定有一首歌是屬於Jay的吧。躺在內心,偶而翻出,正好趕上那個情緒,便產生某些新的情感和新的認知。一場青春,一首周杰倫,沮喪時聽聽,不管是溫柔的仍是奮進的,總能唱到元氣滿滿。好的音樂,是會說話的。\n彷彿每次在掙扎,迷茫和無助的時候,都能在他的音樂世界裏慢慢治癒,而音樂和周杰倫本就是一次相互成全的相遇。\n青春難以留住,夏天已然散場。人生的道路也許各不相同,但只要在他須要咱們的時候爲他加油喝彩,就足夠了,那才叫青春。\n無論何時,什麼地點,我但願全部歌迷回過頭來看到的仍是同一個周杰倫。'
	}, {
		'comment_name': '此用戶已被封',
		'comment_text': '周杰倫三個字是一代青春,還記得08年晚會上聽的那首《青花瓷》頓時茅塞頓開,世間靜會有如此好聽的歌曲。以後迷上他的全部歌曲,本身買磁帶上學的時候在宿舍晚上聽,陪我渡過了5年學習生涯。此次咱們的周青春出新歌,前些天一直在等待,熬夜等待但我以爲這些全部的等待都是值得的。'
	}, {
		'comment_name': '黃子韜TAO',
		'comment_text': '人氣top周杰倫❗💎💖✨🌈\\n實力歌手周杰倫❗💎💖✨🌈\\n音樂鬼才周杰倫❗💎💖✨🌈\\n亞洲天王周杰倫❗💎💖✨🌈\\n家庭美滿周杰倫❗💎💖✨🌈\\n魔術大師周杰倫❗️💎💖✨🌈\\n華語天王周杰倫❗️💎💖✨🌈\\n無與倫比周杰倫❗️💎💖✨🌈\\n奶茶仙子周杰倫❗️💎💖✨🌈\\n守護全世界最好的周杰倫💖💖💖'
	}, {
		'comment_name': '指法芬芳張大仙z',
		'comment_text': '曾經傲嬌的少年,\\n也已到了不惑之年,\\n從一個老是喜歡將臉龐隱藏在鴨舌帽下的靦腆男孩,\\n到現在撒嬌賣萌幽默語句頻出還時時撒狗糧的小公舉,\\n新專輯如約而至,\\n能在這個時代遇到杰倫哥是人生最大幸運,\\n他的做品照亮你的路,陪伴你度過漫長的深夜,\\n你的支持和包容,也讓他從默默無聞變成萬衆矚目,\\n也許有一天 你忙於生活 他歸於沉寂 漸漸再也不會有交集\xa0,\\n但願在慢慢老去 還能回憶起青春時 曾爲一我的瘋狂追逐過,\\n他的名字就是\\n周!傑!倫!一輩子所愛 JAY\\n感謝你的音樂\\n讓我有了一直學習吉他的動力,\\n感謝你的音樂\\n陪我度過的每個夜晚,\\n感謝你的音樂\\n陪伴我在籃球場上的每一天,\\n青春有你,如此甚好,JAY !'
	}, {
		'comment_name': '指法芬芳張大仙z',
		'comment_text': '40歲的杰倫就坐在那裏,\\n深情的目光望過去,\\n滿眼都是本身當年22歲橫空出世范特西少年身影......\\n做爲華語樂壇最成功最具備影響力的歌手音樂人,\\n15座金曲獎、八屆大中華區銷量冠軍、4屆世界音樂獎WMA、全球25大創意人物、《Fast Company》全球百大創意人物,2010年歌曲下載量世界第三,歷史上第一首好萊塢中文主題曲,亞洲天王,世界十大鬼才音樂人之一,\\n這就是周杰倫,是信仰,是天才,是一個時代,是傳奇,是華人之光,是80後的回憶,90後的青春,他還見證着00後的成長;\\n感謝我倫,\\n你走過的軌跡是青春的記憶,\\n致敬,周杰倫!\\n永遠的小公舉,永遠的熱愛!'
	}, {
		'comment_name': '指法芬芳張大仙z',
		'comment_text': '難以忘記初次碰見你,是在《紅塵客棧》的《大笨鐘》下,你笑得《甜甜的》像是天邊的一道《彩虹》色的《麥芽糖》;他們都說愛情來的太快像是《龍捲風》,你和我《一點點》靠近,相識,相戀;我常常會《安靜》的看着你《傻笑》,表白《說好不哭》陪你到永遠;在每一個《晴天》裏,我都會在學校的籃球場上《等你下課》;個人女孩,你就像是我《不能說的祕密》,我想給你《告白氣球》般的浪漫,我想和你許下《蒲公英的約定》,而後牽起你的手,用吉他彈起那《手寫的從前》,就這樣一直牽着你去看《最長的電影》,在每一個夜晚裏去看最美的《星晴》,直到永遠;個人女孩,你就像是海里的《美人魚》公主,我願作你的王子,一直愛你❤一直守護在你身邊。😘'
	}, {
		'comment_name': '黃子韜TAO',
		'comment_text': '手牽手,一步兩步三步四步望着天\\n看星星,一顆兩顆三顆四顆連成線\\n周杰倫「說」三部曲將會在2019年9月16日正式完結\\n千萬別錯過,這一錯就是一生!'
	}, {
		'comment_name': '\u2062',
		'comment_text': '周杰倫\\n我QQ音樂裏惟一的主角\\n你說要聽媽媽的話喝爺爺泡的茶\\n你說最美的是與你躲過雨的屋檐下\\n我提一筆想用幾行字形容你是個人誰\\n禮物用香榭的落葉就不會以爲有點難追\\n時間是解藥也是我如今服下的這一劑毒藥\\n個人十八年青春由於有你的出現而引覺得傲\\n只要你還在爲咱們唱還在帶着笑面對逆境環繞\\n風就不會把距離吹得好遠個人青春也不會老\\n有人說你江郎才盡才華不復當年模樣\\n那是他們嫉妒你絕世的巔峯和輝煌\\n今晚說好不哭\\n謝謝你在一直陪伴着個人青春\\n❤️❤️❤️'
	}, {
		'comment_name': '指法芬芳張大仙z',
		'comment_text': '青春不散!東方之殿開軒窗,繪夢之卷迷迭香,獻世青花瓷世無雙,情書卻漸黃,手書蘭亭序,孤飲女兒紅,亂舞春秋夜未央,園遊會下燦爛七里香,遙思娘子在西廂,撫斷了的弦,奏夜的第七章,同一種調調徒感傷。楓葉落光,花海安靜夜曲入鄉,忍者星晴夜望,摩羯座非尋常,梯田聞稻香,甜甜的心雨灑晴天,將軍屋頂發呆,懦夫將被淘汰,我不配周大俠龍戰騎士那神態,沒借口不退後,以父之名遠走,拜別霍元甲,身披黃金甲,持雙截棍耍帥,一路向北過千山萬水漂移而來,赴千里以外菊花臺, 龍捲風兼藍色風暴雨,四面楚歌響起,止戰之殤的記憶、逆鱗的軌跡,乘坐時光機,世界末日又回到過去,簡單愛在愛的飛行日記裏一直擱淺下去。'
	}],
	'lyric': '說好不哭(with 五月天阿信) - 周杰倫 (Jay Chou)\\n詞:方文山\\n曲:周杰倫\\n周杰倫:\\n沒有了聯絡 後來的生活\\n我都是聽別人說\\n說你怎麼了 說你怎麼過\\n放不下的人是我\\n人多的時候 就待在角落\\n就怕別人問起我\\n大家怎麼了 你低着頭\\n護着我連抱怨都沒有\\n電話開始躲 從不對我說\\n不習慣一我的生活\\n離開我之後 要我好好過\\n怕打擾想自由的我\\n都這個時候 你還在乎着\\n別人是怎麼怎麼看個人\\n拼命解釋着 不是個人錯 是你要走\\n眼看着你難過 挽留的話卻沒有說\\n你會微笑放手 說好不哭讓我走\\n阿信:\\n電話開始躲 從不對我說\\n不習慣一我的生活\\n離開我之後 要我好好過\\n怕打擾想自由的我\\n都這個時候 你還在乎着\\n別人是怎麼怎麼看個人\\n拼命解釋着 不是個人錯 是你要走\\n合:\\n眼看着你難過 挽留的話卻沒有說\\n你會微笑放手 說好不哭讓我走\\n周杰倫:\\n你什麼都沒有 卻還爲個人夢加油\\n阿信:\\n心疼過了多久\\n周杰倫:\\n過了多久\\n合:\\n還在找理由等我'
}

  

 
 

爬蟲的大體邏輯

  • 先爬取指定數量的歌手
  • 根據歌手的id,獲取每一位歌手的歌曲列表(歌曲列表中包含歌曲的一些信息,但不包括歌詞和評論信息)
  • 根據歌曲id,獲取歌曲的歌詞信息
  • 根據歌曲id,獲取歌曲的評論信息
  • 將歌曲寫入文件

語料分享

該資源僅用於學習交流,請勿用於商業用途,若有侵權,請聯繫刪除。json

語料名稱 語料地址 語料描述
49萬+的歌曲信息 百度網盤【提取碼:uokb】 包含QQ音樂中排名前6400名的內地和港臺歌手的49萬+的歌曲信息,包含歌曲信息、歌詞、精彩評論等

解析QQ音樂的url

QQ音樂的歌手和歌曲信息,都是使用js進行動態填充的,因此不可能經過爬取html網頁,而後解析網頁內容來獲取歌曲信息。既然是經過js進行動態填充,那就須要對請求的url的格式進行解析數組

歌手列表url解析

打開QQ音樂的 歌手頁面 ,用開發者工具查看,找到請求歌手列表的url以下:app

https://u.y.qq.com/cgi-bin/musicu.fcg?-=getUCGI9574303950614538&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq.json&needNewCode=0&data=%7B%22comm%22%3A%7B%22ct%22%3A24%2C%22cv%22%3A0%7D%2C%22singerList%22%3A%7B%22module%22%3A%22Music.SingerListServer%22%2C%22method%22%3A%22get_singer_list%22%2C%22param%22%3A%7B%22area%22%3A-100%2C%22sex%22%3A-100%2C%22genre%22%3A-100%2C%22index%22%3A-100%2C%22sin%22%3A0%2C%22cur_page%22%3A1%7D%7D%7D

能夠看到url中攜帶了不少參數,包括:g_tk、loginUin、hostUin、format、inCharset、outCharset、notice、platform、needNewCode、datadom

將該url放到postman中,嘗試一個接一個地取消參數,找到有用的參數。最終能夠知道,其實只有data這個參數對請求有實際的做用,把其餘參數去掉,獲得簡化後的url以下:

https://u.y.qq.com/cgi-bin/musicu.fcg?data=%7B%22comm%22%3A%7B%22ct%22%3A24%2C%22cv%22%3A0%7D%2C%22singerList%22%3A%7B%22module%22%3A%22Music.SingerListServer%22%2C%22method%22%3A%22get_singer_list%22%2C%22param%22%3A%7B%22area%22%3A-100%2C%22sex%22%3A-100%2C%22genre%22%3A-100%2C%22index%22%3A-100%2C%22sin%22%3A0%2C%22cur_page%22%3A1%7D%7D%7D

結合歌手頁面,仔細分析一下上述簡化後的url,會發現data參數中隱含地攜帶了不少實際的請求參數:

  • area:歌手的地域(內地、港臺、歐美等)。-100:所有、200:內地、2:港臺、5:歐美、4:日本、3:韓國、6:其餘
  • genre:歌手風格(流行、嘻哈等)。-100:所有、1:流行、6:嘻哈、2:搖滾、4:電子、3:民謠、8:R&B、10:民歌、9:輕音樂、5:爵士、14:古典、25:鄉村、20:藍調
  • cur_page:當前歌手列表的頁碼
  • index:cur_page*page_size(index表示當前頁的起始index,page_size表示每一頁歌手的數量)

使用控制變量法,固定area和genre變量,比較下列請求第1、2、三頁歌手的url,能夠發現其中index和cur_page中存在一些潛在規律

在下列三個url中(*是人爲添加的,方便描述),index後面跟着的用**標記的數字就是變量index,cur_page後面用 **標記的數字就是變量cur_page。在歌手頁面,能夠看到每一頁有80個歌手。很顯然,當要請求第n頁歌手的時候,cur_page=n,index=80(n-1)。

https://u.y.qq.com/cgi-bin/musicu.fcg?data=%7B%22comm%22%3A%7B%22ct%22%3A24%2C%22cv%22%3A0%7D%2C%22singerList%22%3A%7B%22module%22%3A%22Music.SingerListServer%22%2C%22method%22%3A%22get_singer_list%22%2C%22param%22%3A%7B%22area%22%3A-100%2C%22sex%22%3A-100%2C%22genre%22%3A-100%2C%22index%22%3A-100%2C%22sin%22%3A**0**%2C%22cur_page%22%3A**1**%7D%7D%7D

https://u.y.qq.com/cgi-bin/musicu.fcg?data=%7B%22comm%22%3A%7B%22ct%22%3A24%2C%22cv%22%3A0%7D%2C%22singerList%22%3A%7B%22module%22%3A%22Music.SingerListServer%22%2C%22method%22%3A%22get_singer_list%22%2C%22param%22%3A%7B%22area%22%3A-100%2C%22sex%22%3A-100%2C%22genre%22%3A-100%2C%22index%22%3A-100%2C%22sin%22%3A**80**%2C%22cur_page%22%3A**2**%7D%7D%7D

https://u.y.qq.com/cgi-bin/musicu.fcg?data=%7B%22comm%22%3A%7B%22ct%22%3A24%2C%22cv%22%3A0%7D%2C%22singerList%22%3A%7B%22module%22%3A%22Music.SingerListServer%22%2C%22method%22%3A%22get_singer_list%22%2C%22param%22%3A%7B%22area%22%3A-100%2C%22sex%22%3A-100%2C%22genre%22%3A-100%2C%22index%22%3A-100%2C%22sin%22%3A**160**%2C%22cur_page%22%3A**3**%7D%7D%7D

經過以上分析,能夠獲得請求歌手列表的url格式以下:

singer_list_url = "https://u.y.qq.com/cgi-bin/musicu.fcg?data=%7B%22comm%22%3A%7B%22ct%22%3A24%2C%22cv%22%3A0%7D%2C%22singerList%22%3A%7B%22module%22%3A%22Music.SingerListServer%22%2C%22method%22%3A%22get_singer_list%22%2C%22param%22%3A%7B%22area%22%3A{area}%2C%22sex%22%3A-100%2C%22genre%22%3A{genre}%2C%22index%22%3A-100%2C%22sin%22%3A{index}%2C%22cur_page%22%3A{cur_page}%7D%7D%7D"

歌曲列表url解析

同理找到請求歌曲列表的url

https://u.y.qq.com/cgi-bin/musicu.fcg?-=getSingerSong8235365887193979&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq.json&needNewCode=0&data=%7B%22comm%22%3A%7B%22ct%22%3A24%2C%22cv%22%3A0%7D%2C%22singerSongList%22%3A%7B%22method%22%3A%22GetSingerSongList%22%2C%22param%22%3A%7B%22order%22%3A1%2C%22singerMid%22%3A%22004Be55m1SJaLk%22%2C%22begin%22%3A0%2C%22num%22%3A10%7D%2C%22module%22%3A%22musichall.song_list_server%22%7D%7D

過濾掉無用的參數,獲得簡化後的url:

https://u.y.qq.com/cgi-bin/musicu.fcg?data=%7B%22comm%22%3A%7B%22ct%22%3A24%2C%22cv%22%3A0%7D%2C%22singerSongList%22%3A%7B%22method%22%3A%22GetSingerSongList%22%2C%22param%22%3A%7B%22order%22%3A1%2C%22singerMid%22%3A%22004Be55m1SJaLk%22%2C%22begin%22%3A0%2C%22num%22%3A10%7D%2C%22module%22%3A%22musichall.song_list_server%22%7D%7D

data中隱藏的參數:

  • singerMid:歌手的mid
  • num:至關於page_size,表示每一頁歌曲的數量
  • begin:page*page_size(begin表示當前頁的起始index)

經過以上分析,能夠獲得請求歌曲列表的url格式以下:

song_list_url = "https://u.y.qq.com/cgi-bin/musicu.fcg?data=%7B%22comm%22%3A%7B%22ct%22%3A24%2C%22cv%22%3A0%7D%2C%22singerSongList%22%3A%7B%22method%22%3A%22GetSingerSongList%22%2C%22param%22%3A%7B%22order%22%3A1%2C%22singerMid%22%3A%22{singer_mid}%22%2C%22begin%22%3A{begin}%2C%22num%22%3A{num}%7D%2C%22module%22%3A%22musichall.song_list_server%22%7D%7D"

請求歌詞url解析

經過請求歌曲列表的url發現,並無返回歌曲的歌詞信息,所以確定是經過額外的url請求得到歌詞,找到請求歌詞的url以下:

https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_yqq.fcg?nobase64=1&musicid=105648715&-=jsonp1&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq.json&needNewCode=0

將以上url放到postman中發送請求,卻得不到正確的回覆,通過一番研究,發現該url須要加上referer這個header才能夠正常運行

referer:https://y.qq.com/n/yqq/song/004RDW5Q2ol2jj.html

請求歌詞的url通過簡化參數後獲得:

https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_yqq.fcg?musicid=105648715&format=json

容易看出

  • musicid:song_id
  • referer中的"004RDW5Q2ol2jj"表示song_mid

最終獲得請求歌詞的url以下,lyric_url須要帶上referer這個header:

lyric_url = "https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_yqq.fcg?nobase64=1&musicid={song_id}&format=json"

referer = "https://y.qq.com/n/yqq/song/{song_mid}.html"

歌曲評論url解析

找到歌曲評論的url以下:

https://c.y.qq.com/base/fcgi-bin/fcg_global_comment_h5.fcg?g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=GB2312&notice=0&platform=yqq.json&needNewCode=0&cid=205360772&reqtype=2&biztype=1&topid=105648715&cmd=8&needmusiccrit=0&pagenum=0&pagesize=25&lasthotcommentid=&domain=qq.com&ct=24&cv=10101010

通過參數簡化後,獲得以下url:

https://c.y.qq.com/base/fcgi-bin/fcg_global_comment_h5.fcg?biztype=1&topid=105648715&cmd=8&pagenum=0&pagesize=25

參數說明:

  • topid:歌曲的song_id
  • pagenum:"最新評論"的頁數
  • pagesize:每頁"最新評論"的評論數量

注意:此處的pagenum和pagesize影響的是"最新評論"的返回結果,而不影響"精彩評論",該url中沒有參數能夠控制"精彩評論"的返回結果

請求歌曲評論的url格式以下:

comment_url = 'https://c.y.qq.com/base/fcgi-bin/fcg_global_comment_h5.fcg?biztype=1&topid={song_id}&cmd=8&pagenum={pagenum}&pagesize={pagesize}'

歌曲url

歌曲的url格式以下:

https://y.qq.com/n/yqq/song/{song_mid}.html

歌詞解析

以周杰倫的說好不哭(with 五月天阿信)爲例

經過lyric_url請求得到的歌詞格式以下,格式看起來仍是比較雜亂的,包含各類字符

[ti:說好不哭(With 五月天阿信)]
[ar:周杰倫]
[al:說好不哭(With 五月天阿信)]

[by:]
[offset:0]
[00:00.00]說好不哭(with 五月天阿信) - 周杰倫 (Jay Chou)

[00:14.94]詞:方文山
[00:19.09]曲:周杰倫
[00:23.24]周杰倫:

[00:26.51]沒有了聯絡 後來的生活
[00:29.76]我都是聽別人說
[00:32.85]說你怎麼了 說你怎麼過

[00:36.02]放不下的人是我
[00:39.20]人多的時候 就待在角落
[00:42.34]就怕別人問起我

[00:45.37]大家怎麼了 你低着頭
[00:48.30]護着我連抱怨都沒有
[00:51.82]電話開始躲 從不對我說

[00:54.98]不習慣一我的生活
[00:58.11]離開我之後 要我好好過
[01:01.32]怕打擾想自由的我

[01:04.39]都這個時候 你還在乎着
[01:07.56]別人是怎麼怎麼看個人
[01:10.77]拼命解釋着 不是個人錯 是你要走

[01:15.55]眼看着你難過 挽留的話卻沒有說
[01:28.14]你會微笑放手 說好不哭讓我走
[01:52.13]阿信:

[01:54.95]電話開始躲 從不對我說
[01:58.17]不習慣一我的生活
[02:01.26]離開我之後 要我好好過

[02:04.41]怕打擾想自由的我
[02:07.62]都這個時候 你還在乎着
[02:10.62]別人是怎麼怎麼看個人

[02:13.90]拼命解釋着 不是個人錯 是你要走
[02:18.51]合:
[02:18.71]眼看着你難過 挽留的話卻沒有說

[02:31.28]你會微笑放手 說好不哭讓我走
[02:50.54]周杰倫:
[02:53.38]你什麼都沒有 卻還爲個人夢加油

[03:04.99]阿信:
[03:05.92]心疼過了多久
[03:09.83]周杰倫:
[03:10.02]過了多久

[03:12.58]合:
[03:12.77]還在找理由等我

經過正則表達式獲得比較工整的歌詞(每句歌詞之間用\\n間隔開):

說好不哭(with 五月天阿信) - 周杰倫 (Jay Chou)\\n
詞:方文山\\n
曲:周杰倫\\n
周杰倫:\\n
沒有了聯絡 後來的生活\\n
我都是聽別人說\\n
說你怎麼了 說你怎麼過\\n
放不下的人是我\\n
人多的時候 就待在角落\\n
就怕別人問起我\\n
大家怎麼了 你低着頭\\n
護着我連抱怨都沒有\\n
電話開始躲 從不對我說\\n
不習慣一我的生活\\n
離開我之後 要我好好過\\n
怕打擾想自由的我\\n
都這個時候 你還在乎着\\n
別人是怎麼怎麼看個人\\n
拼命解釋着 不是個人錯 是你要走\\n
眼看着你難過 挽留的話卻沒有說\\n
你會微笑放手 說好不哭讓我走\\n
阿信:\\n
電話開始躲 從不對我說\\n
不習慣一我的生活\\n
離開我之後 要我好好過\\n
怕打擾想自由的我\\n
都這個時候 你還在乎着\\n
別人是怎麼怎麼看個人\\n
拼命解釋着 不是個人錯 是你要走\\n
合:\\n
眼看着你難過 挽留的話卻沒有說\\n
你會微笑放手 說好不哭讓我走\\n
周杰倫:\\n
你什麼都沒有 卻還爲個人夢加油\\n
阿信:\\n
心疼過了多久\\n
周杰倫:\\n
過了多久\\n
合:\\n
還在找理由等我

settings.py的參數說明

  • DOWNLOAD_DELAY:每一個request請求的間隔時間
  • ROBOTSTXT_OBEY:是否遵照網站的爬蟲協議
  • SINGER_PAGE_NUM:爬取的歌手頁數
  • SINGER_PAGE_SIZE:每頁歌手的數量
  • SONG_PAGE_NUM:每一個歌手的歌曲爬取的頁數
  • SONG_PAGE_SIZE:每一個歌手每頁歌曲的數量

避免爬蟲被ban

  • 使用user agent池,輪流選擇其中一個做爲user agent
  • 設置下載延遲DOWNLOAD_DELAY,設爲1或者更大。(一開始怕QQ音樂官方會有一些反爬蟲的檢測,因而把DOWNLOAD_DELAY設爲1,也就是每隔一秒鐘才發送一次請求,發覺爬取速度過於慢,又改爲了0.1。最終索性設爲0,發現原來QQ音樂對於歌詞信息的url並無反爬蟲措施)
  • 使用IP池,動態變動IP地址

user agent池以下:

"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
"Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",
"Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"

Future Work

  • 解析QQ音樂的歌曲文件的請求方式
  • 韓文和英文歌詞中包含一些特殊的符號,部分特殊字符還沒能較好地進行轉義
  • 完善setting,使用戶能更靈活地爬取不一樣地域、風格的歌曲

未解決問題

程序能夠正常運行,可是當爬取結束時(日誌信息寫着'finish_reason':'finished',代表爬蟲爬取任務完成),報了一個錯,雖然不影響結果,但報錯緣由暫時不明

2019-12-21 15:08:53 [scrapy.core.engine] INFO: Closing spider (finished)
2019-12-21 15:08:53 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/exception_count': 8,
 'downloader/exception_type_count/twisted.internet.error.TimeoutError': 8,
 'downloader/request_bytes': 682269284,
 'downloader/request_count': 1067470,
 'downloader/request_method_count/GET': 1067470,
 'downloader/response_bytes': 1563129445,
 'downloader/response_count': 1067462,
 'downloader/response_status_count/200': 1067460,
 'downloader/response_status_count/404': 2,
 'dupefilter/filtered': 30476,
 'finish_reason': 'finished',
 'finish_time': datetime.datetime(2019, 12, 21, 7, 8, 53, 816618),
 'item_scraped_count': 489860,
 'log_count/DEBUG': 1557332,
 'log_count/ERROR': 1,
 'log_count/INFO': 229,
 'request_depth_max': 3,
 'response_received_count': 1067462,
 'retry/count': 8,
 'retry/reason_count/twisted.internet.error.TimeoutError': 8,
 'scheduler/dequeued': 1067468,
 'scheduler/dequeued/memory': 1067468,
 'scheduler/enqueued': 1067468,
 'scheduler/enqueued/memory': 1067468,
 'start_time': datetime.datetime(2019, 12, 20, 14, 59, 43, 749919)}
2019-12-21 15:08:53 [scrapy.core.engine] INFO: Spider closed (finished)
2019-12-21 15:08:53 [scrapy.utils.signal] ERROR: Error caught on signal handler: <bound method MemoryUsage.engine_stopped of <scrapy.extensions.memus
age.MemoryUsage object at 0x000001EFCF7E8630>>
Traceback (most recent call last):
  File "c:\users\administrator\.conda\envs\ppy36\lib\site-packages\twisted\internet\defer.py", line 151, in maybeDeferred
    result = f(*args, **kw)
  File "c:\users\administrator\.conda\envs\ppy36\lib\site-packages\pydispatch\robustapply.py", line 54, in robustApply
    return receiver(*arguments, **named)
  File "c:\users\administrator\.conda\envs\ppy36\lib\site-packages\scrapy\extensions\memusage.py", line 70, in engine_stopped
    for tsk in self.tasks:
AttributeError: 'MemoryUsage' object has no attribute 'tasks'

 Github:https://github.com/yangjianxin1/QQMusicSpider

相關文章
相關標籤/搜索