1. 程式人生 > 其它 >python爬取網易雲音樂並分析:使用者有什麼樣的音樂偏好?

python爬取網易雲音樂並分析:使用者有什麼樣的音樂偏好?

發現自己有時候比挖掘別人來的更加有意義,自己到底喜歡誰的歌,自己真的知道麼?習慣不會騙你。

搭建爬蟲環境

1.安裝selenium

pip install selenium

# anaconda環境的可用conda install selenium

# 網速不好的可用到https://pypi.python.org/pypi/selenium下載壓縮包,解壓後使用python setup.py install

2.安裝Phantomjs

Mac版本

步驟一下載包:去這裡下載對應版本http://phantomjs.org/download.html

步驟二解壓:雙擊就行,用unzip這都無所謂

步驟三切入路徑:cd ~/Downloads/phantomjs-2.1.1-macosx/bin # 我下的路徑的路徑是download,版本不一,注意修改

步驟四:chmod +x phantomjs

步驟五: 配置環境,因為我裝的的zsh,所以檔案需要修改的是~/.zshrc這個檔案,加上這句話export PATH="/Users/mrlevo/Downloads/phantomjs-2.1.1-macosx/bin/:$PATH",然後source ~/.zshrc 即可生效(沒用zsh的同學,直接修改的檔案時~/.bash_profile,新增內容和上述一致)

檢視是否生效:phantomjs -v # 有資訊如 2.1.1 則生效

mac若遇到問題請參考

PhantomJS 安裝

https://segmentfault.com/a/1190000009020535

Win版本

官網http://phantomjs.org/下載PhantomJS解壓後如下圖所示:

呼叫時可能會報錯“Unable to start phantomjs with ghostdriver”如圖:

此時可以設定下Phantomjs的路徑,同時如果你配置了Scripts目錄環境變數,可以解壓Phantomjs到該資料夾下。可參考Selenium with GhostDriver in Python on Windows - stackoverflow, https://stackoverflow.com/questions/21768554/selenium-with-ghostdriver-in-python-on-windows 整個win安裝過程可參考在Windows下安裝PIP+Phantomjs+Selenium], http://blog.csdn.net/eastmount/article/details/47785123 Mac和Linux/Ubuntu 下可參考[解決:Ubuntu(MacOS)+phantomjs+python的部署問題 http://blog.csdn.net/mrlevo520/article/details/73196256

測試安裝是否成功

爬取動態資料

獲取自己的id號,這個可以自己登陸自己的網易雲音樂後獲得,就是id=後面那個值

構造爬取的id,因為我發現,每個人的id只要被獲取到,他的歌單都是公開的!!!這就節省了自動登入的一步,而且,我還有個大膽的想法,哈哈哈,我還要搞個大新聞!這次先不說~

# -*- coding: utf-8 -*-

import traceback
from selenium import webdriver
import selenium.webdriver.support.ui as ui
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
import time
import random


# 儲存為文字的子函式
def write2txt(data,path):
    f = open(path,"a")
    f.write(data)
    f.write("n")
    f.close()


# 獲取該id喜歡音樂的列表
def catchSongs(url_id,url):

    user = url_id.split('=')[-1].strip()  
    print 'excute user:',user

    driver = webdriver.PhantomJS()#,executable_path='/Users/mrlevo/phantomjs-2.1.1-macosx/bin/phantomjs')  
    #  注意填上路徑
    driver.get(url)

    driver.switch_to_frame('g_iframe')  # 網易雲的音樂元素都放在框架內!!!!先切換框架

    try:
        wait = ui.WebDriverWait(driver,15)
        wait.until(lambda driver: driver.find_element_by_xpath('//*[@class="j-flag"]/table/tbody')) 
        # 等待元素渲染出來
        try:
            song_key = 1
            wrong_time = 0
            while wrong_time < 5:  # 不斷獲取歌資訊,假定5次獲取不到值,就判無值可獲取,跳出迴圈
                try:
                    songs = driver.find_elements_by_xpath('//*[@class="j-flag"]/table/tbody/tr[%s]'%song_key)
                    info_ = songs[0].text.strip().split("n")
                    if len(info_) == 5:
                        info_.insert(2,'None') # 沒有MV選項的進行插入None
                    new_line = '%s|'%user+'|'.join(info_)
                    song_key +=1
                    #new_line = "%s|%s|%s|%s|%s|%s|%s"%(user,info_[0],info_[1],info_[2],info_[3],info_[4],info_[5])

                    print new_line

                    write2txt(new_line.encode('utf-8'),user)  
                    # mac寫入檔案需要改變字元,以id命名的檔案,儲存在執行指令碼的當前路徑下,
                    # 在win下請去掉編.endcode('utf-8')


                except Exception as ex:
                    wrong_time +=1
                    # print ex
        except Exception as ex:
            pass

    except Exception as ex:
        traceback.print_exc()
    finally:
        driver.quit()



# 獲取id所喜愛的音樂的url
def catchPlaylist(url):


    driver = webdriver.PhantomJS()
    #,executable_path='/Users/mrlevo/phantomjs-2.1.1-macosx/bin/phantomjs')  
    #  注意填上路徑
    driver.get(url)

    driver.switch_to_frame('g_iframe')  # 網易雲的音樂元素都放在框架內!!!!先切換框架

    try:
        wait = ui.WebDriverWait(driver,15)
        wait.until(lambda driver: driver.find_element_by_xpath('//*[@class="m-cvrlst f-cb"]/li[1]/div/a'))  
        # 根據xpath獲取元素

        urls = driver.find_elements_by_xpath('//*[@class="m-cvrlst f-cb"]/li[1]/div/a')
        favourite_url = urls[0].get_attribute("href")

    except Exception as ex:
        traceback.print_exc()
    finally:
        driver.quit()
    # print favourite_url
    return favourite_url



if __name__ == '__main__':

    for url in ['http://music.163.com/user/home?id=67259702']:  
        # 這裡把自己的id替換掉,想爬誰的歌單都可以,只要你有他的id
        time.sleep(random.randint(2, 4)) # 隨機休眠時間2~4秒
        url_playlist = catchPlaylist(url)
        time.sleep(random.randint(1, 2))
不出意外的話,你的執行指令碼的目錄下會產生一個以你的id命名的檔案,裡面開啟應該是這樣的

接下來就是處理自己下好的自己的歌單了,為了方便起見,我在構造爬取程式碼的時候,已經構造的比較好了,這也就幫助大家減少了資料預處理的時間了,一般來說,資料不會那麼幹淨的。

我只是做了最簡單的歌手詞雲的例子,資料比較豐富的情況下,自己處理吧,想做什麼統計都可以

# -*- coding: utf-8 -*-

# 如果還不清楚詞雲怎麼搞,
# 請參考這裡https://mp.weixin.qq.com/s/0Bw8QUo1YfWZR_Boeaxu_Q,或者自行百度,很簡單的一個包

import numpy as np
import PIL.Image as Image
from wordcloud import WordCloud, ImageColorGenerator
import matplotlib.pyplot as plt

# 統計詞頻
# win的使用者,把解碼去掉即可,因為當時mac寫入的檔案有編碼,所以讀出來需要解碼
def statistics(lst):  
    dic = {}  
    for k in lst:  
        if not k.decode('utf-8') in dic:dic[k.decode('utf-8')] = 0  
        dic[k.decode('utf-8')] +=1  
    return dic  


path = '67259702'  # 自己路徑自己搞定
list_ = []
with open(path,'r') as f:
    for line in f:
        list_.append(line.strip().split('|')[-2].strip())

dict_ = statistics(list_)


# the font from github: https://github.com/adobe-fonts
font = r'SimHei.ttf'
coloring = np.array(Image.open("screenshot.png"))  # 遮罩層自己定義,可選自己的圖片
wc = WordCloud(background_color="white",
               collocations=False, 
               font_path=font,
               width=1400, 
               height=1400,
               margin=2,
               mask=np.array(Image.open("screenshot.png"))).generate_from_frequencies(dict_)

# 這裡採用了generate_from_frequencies(dict_)的方法,裡面傳入的值是{‘歌手1’:5,‘歌手2’:8,},分別是歌手及出現次數,其實和jieba分詞
# 之後使用generate(text)是一個效果,只是這裡的text已經被jieba封裝成字典了

image_colors = ImageColorGenerator(np.array(Image.open("screenshot.png")))
plt.imshow(wc.recolor(color_func=image_colors))
plt.imshow(wc)
plt.axis("off")
plt.show()

wc.to_file('mymusic2.png')  # 把詞雲儲存下來 
方塊版本

# -*- coding: utf-8 -*-
# 稍微修改下引數,就是另一幅圖,這是沒有遮罩層的
import numpy as np
import PIL.Image as Image
from wordcloud import WordCloud, ImageColorGenerator
import matplotlib.pyplot as plt

# 統計詞頻
def statistics(lst):  
    dic = {}  
    for k in lst:  
        if not k.decode('utf-8') in dic:dic[k.decode('utf-8')] = 0  
        dic[k.decode('utf-8')] +=1  
    return dic  


path = '67259702'  # 自己路徑自己搞定
list_ = []
with open(path,'r') as f:
    for line in f:
        list_.append(line.strip().split('|')[-2].strip())

dict_ = statistics(list_)


# the font from github: https://github.com/adobe-fonts
font = r'SimHei.ttf'
coloring = np.array(Image.open("screenshot.png"))
wc = WordCloud(
               collocations=False, 
               font_path=font,
               width=1400, 
               height=1400,
               margin=2,
               ).generate_from_frequencies(dict_)

# 這裡採用了generate_from_frequencies(dict_)的方法,裡面傳入的值是{‘歌手1’:5,‘歌手2’:8,},分別是歌手及出現次數,其實和jieba分詞
# 之後使用generate(text)是一個效果,只是這裡的text已經被jieba封裝成字典了

image_colors = ImageColorGenerator(np.array(Image.open("screenshot.png")))

plt.imshow(wc)
plt.axis("off")
plt.show()

wc.to_file('mymusic2.png')  # 把詞雲儲存下來 

剛看到個好玩的,迫不及待的試了下,這是關於語種翻譯的API介面,阿里雲買的,0.01=1000條,買買買,買來玩玩試試自己歌曲語種

# -*- coding:utf-8 -*-
# 呼叫的阿里雲的API介面實現語種翻譯
# API官網:https://market.aliyun.com/products/57124001/cmapi010395.html?spm=5176.730005.0.0.UrR9bO#sku=yuncode439500000
import urllib, urllib2, sys
import ssl

def Lang2Country(text):
    host = 'https://dm-12.data.aliyun.com'
    path = '/rest/160601/mt/detect.json'
    method = 'POST'
    appcode = 'xxxxx'  # 購買後提供的appcode碼
    querys = ''
    bodys = {}
    url = host + path
    bodys['q'] = text
    post_data = urllib.urlencode(bodys)
    request = urllib2.Request(url, post_data)
    request.add_header('Authorization', 'APPCODE ' + appcode)
    # 根據API的要求,定義相對應的Content-Type
    request.add_header('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8')
    ctx = ssl.create_default_context()
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE
    response = urllib2.urlopen(request, context=ctx)
    content = response.read()
    if (content):
        # print(content)
        return content
    else:
        return None


# 
# 67259702|1|Claux - 水之畔(8lope Remix) (feat. 陶心瑤)|None|02:44|8lope|水之畔(feat. 陶心瑤) (8lope Remix)
list_songs = []
list_songwithsinger = []
with open('67259702') as f:  # 檔名寫上次爬下來的
    for line in f:
        line_split = line.split('|')
        list_songs.append(line_split[2])
        list_songwithsinger.append(line_split[2]+line_split[5])


# 呼叫介面進行語種識別
dict_lang = {}
for i in range(537):
    try:
        content = Lang2Country(list_songwithsinger[i])
        lag_ = json.loads(content)['data']['language']
        if lag_ not in dict_lang:
            dict_lang[lag_]=0
        dict_lang[lag_] +=1
    except:
        pass

print dict_lang 

# {u'ru': 1, u'fr': 9, u'en': 111, u'zh': 259, u'pt': 21, u'ko': 8, u'de': 7, u'tr': 15, u'it': 47, u'id': 2, u'pl': 7, u'th': 1, u'nl': 10, u'ja': 17, u'es': 20}

ok,資料準備好了,接下來視覺化就好了!這次我用Echarts,換個口味的就不用雲詞了,來個統計效果好看點的!

# 進入該網頁:http://echarts.baidu.com/demo.html#pie-simple
# 然後把裡面的內容替換掉就行
option = {
    title : {
        text: '哈士奇說喵喜歡的音樂',
        x:'center'
    },
    tooltip : {
        trigger: 'item',
        formatter:'{b} : {c} ({d}%)' 
    },
    legend: {
        orient: 'vertical',
        left: 'left',
        data:['中文','英文','俄語','法語','葡萄牙語','韓語','德語','土耳其語','義大利語']
    },
    series : [
        {
            name: '訪問來源',
            type: 'pie',
            radius : '55%',
            center: ['50%', '60%'],
            itemStyle: {  
              normal: {label:{  
                show:true,  
                formatter:'{b} : {c} ({d}%)'  
            },  
              }},
            data:[
                {value:259, name:'中文'},
                {value:111,name:'英文'},
                {value:1, name:'俄語'},
                {value:9, name:'法語'},
                {value:21, name:'葡萄牙語'},
                {value:8, name:'韓語'},
                {value:7, name:'德語'},
                {value:15, name:'土耳其語'},
                {value:47, name:'義大利語'},
                {value:2, name:'印尼語'},
                {value:7, name:'波蘭語'},
                {value:1, name:'泰語'},
                {value:10, name:'荷蘭語'},
                {value:17, name:'日語'},
                {value:20, name:'西班牙語'},

            ],

        }
    ]
};
  1. 這裡遇到的最大問題,就是網易雲的網頁竟然還iframe框來做!!!不切入那個內聯框架連phantomjs都無能為力!!這是最值得注意的一點,即使你找對了元素,也可能獲取不到值!
  2. 如果是win的計算機,在 driver = webdriver.PhantomJS()裡面填上phantomjs.exe的路徑,上面抓取資料的程式碼裡面有兩個需要引擎需要填寫路徑
  3. 如果有打印出欄位,但是記錄的資料為0KB,那麼是檔案沒有寫進去,對於win的使用者,把程式碼寫入的部門,編碼方式去掉即可
  4. 有些win的小夥伴反應路徑都載入對了,但是還是找不到exe,那麼請在路徑前面加r比如executable_path=r"F:Pythonphantomjs-1.9.1-windowsphantomjs.exe"

結論

果然一下子就看出是上個世紀九十年代的人(:,還有就是,音樂不分國界,就是動感~

via: http://blog.csdn.net/mrlevo520/article/details