天天看點

Python爬蟲-selenium爬取網易雲歌單(一)工欲善其事必先利其器-安裝工具(二)實戰

文章目錄

  • (一)工欲善其事必先利其器-安裝工具
    • Selenium
    • 浏覽器
  • (二)實戰

(一)工欲善其事必先利其器-安裝工具

Selenium

Selenium是一個強大的網絡資料采集工具,其最初是為網站自動化測試而開發的。近幾年,它還被廣泛用于擷取精确的網站快照,因為它們可以直接運作在浏覽器上。Selenium 庫是一個在WebDriver 上調用的API。WebDriver 有點兒像可以加載網站的浏覽器,但是它也可以像BeautifulSoup對象一樣用來查找頁面元素,與頁面上的元素進行互動(發送文本、點選等),以及執行其他動作來運作網絡爬蟲。安裝方式與其他Python第三方庫一樣。

pip install Selenium

浏覽器

Selenium 自己不帶浏覽器,它需要與第三方浏覽器結合在一起使用。例如,如果你在Firefox 上運作Selenium,可以直接看到一個Firefox 視窗被打開,進入網站,然後執行你在代碼中設定的動作。雖然這樣可以看得更清楚,但不适用于這個爬蟲程式,爬一頁就打開一頁效率太低,是以我用一個叫PhantomJS的工具代替真實的浏覽器。

PhantomJS:是一個“無頭”(headless)浏覽器。它會把網站加載到記憶體并執行頁面上的JavaScript,但是它不會向使用者展示網頁的圖形界面。把Selenium和PhantomJS 結合在一起,就可以運作一個非常強大的網絡爬蟲。

官方網站下載下傳:http://phantomjs.org/download.html

然後把可執行檔案拷貝到Python安裝目錄的Scripts檔案夾。

(二)實戰

1.爬取歌單的名字,播放量,連結放入一個csv檔案;

2.将歌單封面和歌單中的歌曲下載下傳到檔案中。

網易雲站外播放器連結:http://music.163.com/song/media/outer/url?id=

加上歌曲id号即可以擷取歌曲,如:http://music.163.com/song/media/outer/url?id=476592630.mp3

網易雲歌單連結(第一頁):https://music.163.com/#/discover/playlist/?order=hot&cat=全部&limit=35&offset=0

“F12”分析一下:

Python爬蟲-selenium爬取網易雲歌單(一)工欲善其事必先利其器-安裝工具(二)實戰

播放數nb (number broadcast):59340

封面 msk (mask):有标題(title)和url

同理,也可以找到“下一頁”的url,最後一頁的url是“javascript:void(0)”

Python爬蟲-selenium爬取網易雲歌單(一)工欲善其事必先利其器-安裝工具(二)實戰

這就可以做一個循環,來擷取資料:

url="https://music.163.com/#/discover/playlist/?order=hot&cat=%E5%85%A8%E9%83%A8&limit=35&offset=0"
while url!='javascript:void(0)':
           

網易雲有反爬蟲機制:

1.User Agent:

Python爬蟲-selenium爬取網易雲歌單(一)工欲善其事必先利其器-安裝工具(二)實戰

找到User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.6801.400 QQBrowser/10.3.2960.400

如果是使用入門的requests,BeautifulSoup來爬取資料就需要添加headers,不然伺服器會識别爬蟲,擷取不到資料;

headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.6788.400 QQBrowser/10.3.2714.400"}
html=requests.get(url,headers=headers)
           

2.frame架構:

Python爬蟲-selenium爬取網易雲歌單(一)工欲善其事必先利其器-安裝工具(二)實戰

網易雲用了frame架構,使用BeautifulSoup的find()方法擷取class和tag是擷取不到資料的,隻能使用xpath;

而這裡使用Selenium,就直接使用switch_to.frame()方法;

先完成第1步:

from selenium import webdriver
import csv

#準備好儲存資料的csv檔案
csv_file=open("playlist.csv","a",newline="",encoding='utf-8')
writer=csv.writer(csv_file)
writer.writerow(['歌單名','播放量','連結'])

#歌單第一頁
url="https://music.163.com/#/discover/playlist/?order=hot&cat=%E5%85%A8%E9%83%A8&limit=35&offset=0"
#用PhantomJS接口建立一個Selenium的WebDriver
driver=webdriver.PhantomJS()

#解析每一頁,到最後一頁
while url!='javascript:void(0)':
    print("通路位址:",url)
    #用WebDriver加載界面
    driver.get(url)
    #切換到内容的iframe
    driver.switch_to.frame("g_iframe")
    #擷取歌單标簽
    data=driver.find_element_by_id("m-pl-container").find_elements_by_tag_name("li")
    for i in range(len(data)):
        src=data[i].find_element_by_class_name("j-flag").get_attribute('src')
        a=data[i].find_element_by_class_name("msk")
        name=a.get_attribute('title')   #歌單名字
        print("歌單名:",name)
        nb=data[i].find_element_by_class_name("nb").text #播放量
        print("播放量:",nb)
        hf=a.get_attribute('href') #連結
        print("連結:",hf)
        
        #将資料寫入csv檔案
        writer.writerow([name,nb,hf])

    url=data[i].find_element_by_xpath('//*[@id="m-pl-pager"]/div/a[11]').get_attribute('href')

csv_file.closed()
           

爬取資料結果:

Python爬蟲-selenium爬取網易雲歌單(一)工欲善其事必先利其器-安裝工具(二)實戰

完成第2步(網易雲維護更新,站外播放器的連結失效了,通路都是404,是以将歌曲連結存為.txt檔案):

from selenium import webdriver
import csv
import os
import requests
import re
import urllib

#建立以歌單名為檔案名的檔案
def creatFile(url,name):
    if not os.path.isdir(os.getcwd()+"/"+name):
        os.mkdir(os.getcwd()+"/"+name)
    img=requests.get(url)
    with open(os.getcwd()+"/"+name+"/"+"封面.jpg",'wb') as f:
        f.write(img.content)

#獲得歌單内歌曲界面
def getMusicPage(name,url):
    driver=webdriver.PhantomJS()
    driver.get(url)
    driver.switch_to.frame("g_iframe")
    info=driver.find_element_by_xpath('//table[@class="m-table "]/tbody').find_elements_by_tag_name("tr")
    for i in range(len(info)):
        musicName=info[i].find_element_by_tag_name("b").get_attribute('title').replace('\xa0','')
        print(musicName)
        title=validateTitle(musicName)
        hf=info[i].find_element_by_tag_name("a").get_attribute('href')
        #song_id=hf.strip('https://music.163.com/song?id=85575')
        #song_url="http://music.163.com/song/media/outer/url?id="+song_id
        #print(song_url)
        downloadMusic(name,title,hf)

#正規表達式處理建立檔案夾檔案名時的非法字元
def validateTitle(title):
    rstr=r"[\/\\\:\*\?\"\<\>\|]"  # '/ \ : * ? " < > |'
    new_title=re.sub(rstr,"_",title) #将非法字元替換為下劃線
    return new_title

#将歌曲連結存入檔案
def downloadMusic(name,musicName,url):
    if not os.path.isdir(os.getcwd()+"/"+name+"/"+musicName):
        os.mkdir(os.getcwd()+"/"+name+"/"+musicName)
    with open(os.getcwd()+"/"+name+"/"+musicName+"/"+"連結.txt","w") as f:
        f.write(url)
    '''
    #下載下傳歌曲(已失效)
    path=os.getcwd()+"/"+name+"/{}.mp3".format(musicName)
    with open(path,'wb') as f:
        try:
            urllib.request.urlretrieve(url,path)
        except BaseException:
            print("下載下傳失敗:"+musicName)
            pass
    '''

if __name__=='__main__':
    csv_file=open("playlist.csv","a",newline="",encoding='utf-8')
    writer=csv.writer(csv_file)
    writer.writerow(['歌單名','播放量','連結'])

    #歌單第一頁
    url="https://music.163.com/#/discover/playlist/?order=hot&cat=%E5%85%A8%E9%83%A8&limit=35&offset=0"
    #用PhantomJS接口建立一個Selenium的WebDriver
    driver=webdriver.PhantomJS()

    #解析每一頁,到最後一頁
    while url!='javascript:void(0)':
        print("通路位址:",url)
        #用WebDriver加載界面
        driver.get(url)
        #切換到内容的iframe
        driver.switch_to.frame("g_iframe")
        #擷取歌單标簽
        data=driver.find_element_by_id("m-pl-container").find_elements_by_tag_name("li")
        for i in range(len(data)):
            src=data[i].find_element_by_class_name("j-flag").get_attribute('src')
            a=data[i].find_element_by_class_name("msk")
            name=a.get_attribute('title')   #歌單名字
            fileName=validateTitle(name)
            #建立檔案存儲歌單
            creatFile(src,fileName)
            hf=a.get_attribute('href') #連結
            #獲得歌單連結,獲得歌曲資訊
            getMusicPage(fileName,hf)


        url=data[i].find_element_by_xpath('//*[@id="m-pl-pager"]/div/a[11]').get_attribute('href')

           

建立檔案夾時使用相對路徑建立檔案夾,爬取結果:

以歌單名建立的檔案夾:
           
Python爬蟲-selenium爬取網易雲歌單(一)工欲善其事必先利其器-安裝工具(二)實戰
以歌曲名建立的檔案夾:
           
Python爬蟲-selenium爬取網易雲歌單(一)工欲善其事必先利其器-安裝工具(二)實戰
檔案夾中為歌曲播放連結:
           
Python爬蟲-selenium爬取網易雲歌單(一)工欲善其事必先利其器-安裝工具(二)實戰

繼續閱讀