1. 程式人生 > >爬蟲入門——用python爬取網易雲音樂熱門歌手評論數

爬蟲入門——用python爬取網易雲音樂熱門歌手評論數

本文參考Monkey_D_Newdun 的文章

用爬蟲獲取網易雲音樂熱門歌手評論數

執行平臺:Windows 10

IDE:spyder

Python版本:3.6

瀏覽器:360


一、爬蟲基本思路

a. 通過URL或者檔案獲取網頁:開啟網頁-F12-找到需要獲取的url,request header以及form data或parameters.

b. 分析要爬取的目標內容所在的位置

c. 用元素選擇器快速提取(Raw) 目標內容

d. 處理提取出來的目標內容 ( 通常整理合成一個 Json)

e. 儲存處理好的目標內容 (比如放到 MongoDB 之類的資料庫,或者寫進檔案裡。)

二、用到的包或模組

1.Urllib-request、requests負責連線網站,處理HTTP協議,返回網頁。

2.bs4負責解析網頁,將網頁變成結構化資料,方便爬取

3.BeautifulSoup不用編寫正則表示式也能方便的實現網頁資訊的抓取

4.re(正則表示式):爬取bs4也難以爬取的內容

5.json :解析器,結構化網頁原始碼

from urllib import request  
from bs4 import BeautifulSoup  
import requests  
import json  
import re  

step 1 獲取歌曲評論數,以周杰倫《等你下課》為例


對連結解析沒有用到beautiful soup是因為網易對評論資料採取的是非同步傳輸,不能直接通過解析網頁內容得到評論資料。

F12開啟開發者工具,發現評論資料在一個名為"R_SO_4_531051217?csrf_token="的post請求中。


def comment_count(song_id):  
    headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36"}
               #agent就是請求的身份,如果沒有寫入請求身份,那麼伺服器不一定會響應
    url="http://music.163.com/weapi/v1/resource/comments/R_SO_4_"+song_id+"?csrf_token="  
    data = {  
        "params": "nHfVBsNbW+WCrz7pAbdaq4uW2+4kADa+gNEfGWK7M5n36mWvsmGXsM2KzVUAeR62mhYlsSvc23I58Rf0dvg1Cglxuf5/l1wVRBCRROpjz9WuYSlWdiwXT/x45iud30RmjbTUsMSQuiehO6Ef3vHSdKWHma9pYm/eeYUF7IQ0hXI3HIz42NgwllBj4cy1XlOH",  
        "encSecKey": "0587c5b45f3b0771db2b3fe449e7dd9640ab56f679d73a9189096283e776e7a9f749630c6e0fa3f947778f1588b9ec71bd779279006f352e5804036909d5d772c9572c64db575bcce675fcc9055614f1c955abb798eed602cb43945748d8b0a9ecf293cde0ef523e63c3115a1a12b7113be447fba7947090f0d98d2c37cff72a"}  
    req=requests.post(url=url,headers=headers,data=data)  
    req.encoding="utf-8"  #utf-8編碼,UTF-8是一種針對Unicode的可變長度字元編碼,又稱萬國碼。用在網頁上可以統一頁面顯示中文簡體繁體及其它語言(如英文,日文,韓文)。
    comment= json.loads(req.text)   #用於解碼 JSON 資料,返回結構化Python欄位的資料型別
    return comment["total"]  

if __name__=="__main__":  
    print(comment_count("531051217"))

step 2 獲得歌手名字與歌手ID

def artist_id():  
    a_headers = {"Referer": "http://music.163.com/discover/artist"  }
          #對付防盜鏈,伺服器會識別headers中的referer是不是它自己,如果不是,有的伺服器不會響應,所以我們還可以在headers中加入referer
    url="http://music.163.com/weapi/artist/top?csrf_token="    #在開發者選項找到熱門歌手對應的url,請求方式為post
    data={"params":"uAE0hN7yRCy+plWTUJw7imQQW+wUSFRuVlFD8UTgXNfJTVLzNyqfnLRqSByCjs40san8rbwMfpasdpJRNit6vKkbQE0F7MZEgRPgSEVfXrHIB/wGiyYQ/VIaZnyTql1m",  
          "encSecKey":"def9762a8c6ff1f3ae1a7ee23cbc095b3dd6c888f28e974ca00f927fd044a48cfdde49af3138aa99fa7da17fdb97809c7d1abd4ddfc40ab7ef3c0e574e56b2d623c0c23af4d08c629087fd5e1996c961af133140dc81b9fb2322aca668a8079c6cd01a0699fc860b2bb0df47b3887d563f1b18e6585198bb5d9c718a5fa92f04"}  
    #用Requests和urlopen解析歌手頁面的POST  
    req=requests.post(url=url,headers=a_headers,data=data)  #利用Request將headers,dict,data整合成一個物件傳入urlopen
    #Request存在的意義是便於在請求的時候傳入一些資訊,而urlopen則不
    req.encoding="utf-8"   
    #解析所返回的JSON資料  
    a_data=json.loads(req.text)  #字典,含code,more,artist,其中artist是列表,含歌手名字與ID
    a_list=a_data["artists"]#剛剛觀察返回資料可以知道歌手的資訊儲存在artists鍵中  
    id_list=[]#用一個列表儲存所有歌手的id和name  
    for i in range(len(a_list)):  
        a_dict = {}#用一個字典儲存一個歌手的id和name  
        a_dict["name"]=a_list[i]["name"]  
        a_dict["id"]=a_list[i]["id"]  
        id_list.append(a_dict)  
    return id_list  

if __name__=="__main__":  
    print(artist_id())  

輸出為一個包含60個字典的列表:

[{'name': '周杰倫', 'id': 6452}, {'name': '陳奕迅', 'id': 2116}, {'name': '薛之謙', 'id': 5781}, {'name': 'BIGBANG', 'id': 126339}, {'name': '林俊杰', 'id': 3684}, {'name': 'Maroon 5', 'id': 96266}, {'name': '王菲', 'id': 9621}, {'name': '李榮浩', 'id': 4292}, {'name': 'G.E.M.鄧紫棋', 'id': 7763}, {'name': '張學友', 'id': 6460}, {'name': '楊宗緯', 'id': 6066}, {'name': '許巍', 'id': 5770}, {'name': '蔡健雅', 'id': 7214}, {'name': 'Adele', 'id': 46487}, {'name': 'Bruno Mars', 'id': 178059}, {'name': 'Coldplay', 'id': 89365}, {'name': 'Justin Bieber', 'id': 35531}, {'name': '陳粒', 'id': 1007170}, {'name': '孫燕姿', 'id': 9272}, {'name': '趙雷', 'id': 6731}, {'name': '李志', 'id': 3681}, {'name': '王力巨集', 'id': 5346}, {'name': '好妹妹樂隊', 'id': 711683}, {'name': 'EXO', 'id': 759509}, {'name': 'Beyond', 'id': 11127}, {'name': 'Alan Walker', 'id': 1045123}, {'name': 'Fall Out Boy', 'id': 56782}, {'name': '金玟岐', 'id': 893259}, {'name': '宋冬野', 'id': 5073}, {'name': '朴樹', 'id': 4721}, {'name': 'Eminem', 'id': 32665}, {'name': '李健', 'id': 3695}, {'name': 'OneRepublic', 'id': 98105}, {'name': 'Tobu', 'id': 964486}, {'name': 'Two Steps From Hell', 'id': 102714}, {'name': '陳小春', 'id': 2112}, {'name': '那英', 'id': 9061}, {'name': '莫文蔚', 'id': 8926}, {'name': '許嵩', 'id': 5771}, {'name': '蘇打綠', 'id': 12707}, {'name': 'Ed Sheeran', 'id': 33184}, {'name': '謝安琪', 'id': 9952}, {'name': '楊千嬅', 'id': 10204}, {'name': '馬頔', 'id': 4592}, {'name': '張國榮', 'id': 6457}, {'name': 'Charlie Puth', 'id': 90331}, {'name': '蕭敬騰', 'id': 5768}, {'name': '張敬軒', 'id': 6462}, {'name': 'Wiz Khalifa', 'id': 46006}, {'name': 'Rihanna', 'id': 72724}, {'name': '張靚穎', 'id': 10561}, {'name': 'Ellie Goulding', 'id': 56598}, {'name': '張惠妹', 'id': 10559}, {'name': 'IU', 'id': 160947}, {'name': '防彈少年團', 'id': 783124}, {'name': '澤野弘之', 'id': 15290}, {'name': 'Carly Rae Jepsen', 'id': 50934}, {'name': 'G-Dragon', 'id': 123577}, {'name': '古巨基', 'id': 2849}, {'name': '五月天', 'id': 13193}]

step 3獲取歌手熱門單曲ID

def song_id(artist_id):  
    data={"id":artist_id}#將歌手ID作為params引數傳入requests.get()方法 
    s_url="http://music.163.com/artist"  
    headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36"}  
    req=requests.get(url=s_url,headers=headers,params=data)   #請求方式為get。在get請求中,允許使用params關鍵字,以一個字典來傳遞這些引數
    req.encoding="utf-8"  
    soup=BeautifulSoup(req.text,"lxml")#對返回的資料進行解析,lxml解析器,速度快,健壯性好
    song_list=soup.find_all("ul",class_="f-hide")#找到class="f-hide"的<ul>標籤  
    song_soup=BeautifulSoup(str(song_list),"lxml")#將<ul>......</ul>再解析一次,以便使用find_all()方法把所有<a>標籤取出來  
    song_list=song_soup.find_all("a")  
    id_list=[]#存歌曲ID  
    name_list=[]#存歌名  
    for each in song_list:  
        s_id=each.get("href")#歌曲ID在<a>標籤href屬性中  
        s_name=each.string  
        s=re.findall(r"\d+",s_id)#用正則找到href中的ID  
        id_list.append(s[0])#由於re.findall()返回的是一個列表,所以用下標將ID取出  
        name_list.append(s_name)  
    return id_list,name_list  

if __name__=="__main__":  
    song_id_list,name_list=song_id(6452)    #以周杰倫為例
    print(song_id_list)  
    print(name_list)  

在get請求中,允許使用params關鍵字,以一個字典來傳遞這些引數,例如:

content={‘pageIndex‘:1,‘pageSize‘:10,‘categoryId‘:None}
r=requests.get(‘http://www.xxxxx.com/api/v2/activities‘ ,params=content)
print (r.url)

#結果

正則 re.findall 的簡單用法

(返回string中所有與pattern相匹配的全部字串,返回形式為陣列) 語法: findall(pattern, string, flags=0)

“d”是正則語法規則用來匹配0到9之間的數返回列表

import re
re.findall(r"\d\d\d","https://docs.python.org/3/whatsnew/3.6.html/1234")
輸出:
['123']
import re
re.findall(r"\d\d","https://docs.python.org/3/whatsnew/3.6.html/1234")

輸出:

['12', '34']

import re
re.findall(r"\d+","https://docs.python.org/3/whatsnew/3.6.html/1234")

輸出:

['3', '3', '6', '1234']

step 4 獲取歌手&總評論

if __name__=="__main__":  
    f=open("網易雲評論.txt","w",encoding="utf-8")   #用寫的方式開啟網易雲評論.txt這個檔案
    id_list=artist_id()  
    for artist in id_list:  
        total=0  
        f.write("\n\n"+artist["name"]+"熱門歌曲以及評論數:")  #寫入檔案網易雲評論.txt:XXX(歌手名)熱門歌曲以及評論數:
        song_id_list,name_list=song_id(artist["id"])   #兩個列表,歌曲id&歌曲名
        for i in range(len(song_id_list)):  
            if(name_list[i]!=None):  #歌手澤野弘之有些歌曲名字為null
                total+=comment_count(song_id_list[i])  
                f.write(name_list[i]+":"+str(comment_count(song_id_list[i]))+"條")  
        f.write("總計:"+str(total)+"條")  
        print(artist["name"]+"網易雲音樂熱門歌曲總評論數:"+str(total)+"條")  
    print("抓取完畢!")  

輸出:

周杰倫網易雲音樂熱門歌曲總評論數:710456條
陳奕迅網易雲音樂熱門歌曲總評論數:1340896條
薛之謙網易雲音樂熱門歌曲總評論數:3876733條
BIGBANG網易雲音樂熱門歌曲總評論數:72278條
林俊杰網易雲音樂熱門歌曲總評論數:1047567條
Maroon 5網易雲音樂熱門歌曲總評論數:376437條
王菲網易雲音樂熱門歌曲總評論數:676064條
李榮浩網易雲音樂熱門歌曲總評論數:669950條
G.E.M.鄧紫棋網易雲音樂熱門歌曲總評論數:479356條
張學友網易雲音樂熱門歌曲總評論數:484701條
楊宗緯網易雲音樂熱門歌曲總評論數:566335條
許巍網易雲音樂熱門歌曲總評論數:417892條
蔡健雅網易雲音樂熱門歌曲總評論數:486667條
Adele網易雲音樂熱門歌曲總評論數:276238條
Bruno Mars網易雲音樂熱門歌曲總評論數:421597條
Coldplay網易雲音樂熱門歌曲總評論數:725671條
Justin Bieber網易雲音樂熱門歌曲總評論數:726028條
陳粒網易雲音樂熱門歌曲總評論數:845892條
孫燕姿網易雲音樂熱門歌曲總評論數:769744條
趙雷網易雲音樂熱門歌曲總評論數:1398742條
李志網易雲音樂熱門歌曲總評論數:773379條
王力巨集網易雲音樂熱門歌曲總評論數:559485條
好妹妹樂隊網易雲音樂熱門歌曲總評論數:565989條
EXO網易雲音樂熱門歌曲總評論數:113269條
Beyond網易雲音樂熱門歌曲總評論數:327790條
Alan Walker網易雲音樂熱門歌曲總評論數:1346941條
Fall Out Boy網易雲音樂熱門歌曲總評論數:261950條
金玟岐網易雲音樂熱門歌曲總評論數:681762條
宋冬野網易雲音樂熱門歌曲總評論數:771306條
朴樹網易雲音樂熱門歌曲總評論數:536437條
Eminem網易雲音樂熱門歌曲總評論數:398636條
李健網易雲音樂熱門歌曲總評論數:236075條
OneRepublic網易雲音樂熱門歌曲總評論數:294360條
Tobu網易雲音樂熱門歌曲總評論數:435382條
Two Steps From Hell網易雲音樂熱門歌曲總評論數:643321條
陳小春網易雲音樂熱門歌曲總評論數:311270條
那英網易雲音樂熱門歌曲總評論數:177621條
莫文蔚網易雲音樂熱門歌曲總評論數:402836條
許嵩網易雲音樂熱門歌曲總評論數:3386821條
蘇打綠網易雲音樂熱門歌曲總評論數:299000條
Ed Sheeran網易雲音樂熱門歌曲總評論數:431641條
謝安琪網易雲音樂熱門歌曲總評論數:264638條
楊千嬅網易雲音樂熱門歌曲總評論數:289710條
馬頔網易雲音樂熱門歌曲總評論數:318597條
張國榮網易雲音樂熱門歌曲總評論數:504605條
Charlie Puth網易雲音樂熱門歌曲總評論數:676351條
蕭敬騰網易雲音樂熱門歌曲總評論數:245439條
張敬軒網易雲音樂熱門歌曲總評論數:296725條
Wiz Khalifa網易雲音樂熱門歌曲總評論數:282971條
Rihanna網易雲音樂熱門歌曲總評論數:309311條
張靚穎網易雲音樂熱門歌曲總評論數:288221條
Ellie Goulding網易雲音樂熱門歌曲總評論數:166458條
張惠妹網易雲音樂熱門歌曲總評論數:264970條
IU網易雲音樂熱門歌曲總評論數:39468條
防彈少年團網易雲音樂熱門歌曲總評論數:96838條
澤野弘之網易雲音樂熱門歌曲總評論數:123395條
Carly Rae Jepsen網易雲音樂熱門歌曲總評論數:172148條
G-Dragon網易雲音樂熱門歌曲總評論數:64666條
古巨基網易雲音樂熱門歌曲總評論數:151144條
五月天網易雲音樂熱門歌曲總評論數:122676條
抓取完畢!
2018/4/23 00點11分