今天我給大家介紹一下用Python爬取網易雲音樂全部歌手的熱門歌曲.由於歌手個人主頁的網頁原始碼中還嵌入了一個子網頁(框架原始碼裡面包含了我們需要的資訊),因此我們不能使用requests庫來爬取,而使用selenium,接下來,讓我詳細講解整個爬取過程.
一,構造歌手個人主頁的URL
前段時間我們獲取了網易雲音樂全部歌手的id號,今天我們就利用全部歌手的id號來構造歌手個人主頁的URL,從而實現用爬取全部歌手的熱門歌曲及其id號的目的.以歌手 薛之謙的個人主頁 為例,來看一下他的主頁的URL為:
1 |
https://music.163.com/#/artist?id=5781 |
因此只需要根據歌手對應的id就可以構造出歌手的個人主頁,在歌手的個人主頁我們能看到熱門作品這一欄.網易雲音樂全部歌手id號點選獲取(csv檔案)
二,分析網頁原始碼
現在我們就要用Python爬蟲去爬取這些內容.如果你用requests庫去爬取的話,返回的網頁原始碼中根本就沒有這些資訊.這時我們開啟薛之謙的個人主頁滑鼠右鍵分別檢視網頁的原始碼和檢視框架的原始碼.你會發現網頁原始碼和用requests庫請求返回的原始碼一摸一樣(裡面沒有我們要爬取的資訊),而在框架原始碼中有我們要爬取的熱門作品的資訊,因此我們只需要將框架原始碼爬取下來,然後再解析即可得到我們需要的歌手的熱門作品的資訊.
三,網頁原始碼和框架原始碼的區別
網頁原始碼是指父級網頁的原始碼.另外網頁中還有一種節點叫iframe,也就是子Frame,相當於網頁的子頁面,它的結構和外部網頁的結構完全一致,框架原始碼就是這個子網頁的原始碼.
四,獲取框架原始碼
這裡我們使用selenium庫來爬取,在selenium開啟頁面後,預設是在父級frame裡面進行操作,而此時頁面中還有子frame,它是不能獲取到子frame裡面的節點的,因此這時我們需要使用swith_to.frame()方法來切換到子frame中去,這時請求得到的程式碼就從網頁原始碼切換到了框架原始碼,於是我們便能夠提取我們需要的熱門作品的資訊了.通過歌手的個人主頁的URL來爬取其框架原始碼,具體爬取框架原始碼的函式:
1 2 3 4 5 6 7 8 9 10 11 |
def get_html_src(url): # 可以任意選擇瀏覽器,前提是要配置好相關環境,更多請參考selenium官方文件 driver = webdriver.Chrome() driver.get(url) # 切換成frame driver.switch_to_frame("g_iframe") # 休眠3秒,等待載入完成! time.sleep(3) page_src = driver.page_source driver.close() return page_src |
返回結果為歌手個人主頁的框架原始碼,裡面包含了我們需要的資訊.
五,解析原始碼
我們使用bs4庫進行解析,需要的資訊包含在HTML5的下面程式碼片段中:
1 |
<span class="txt"><a href="/song?id=(\d*)"><b title="(.*?)"> |
因此可定義下面函式對其進行解析:
1 2 3 4 5 6 7 |
def parse_html_page(html): # pattern = '<span class="txt"><a href="/song?id=(\d*)"><b title="(.*?)">' # 這裡是使用lxml解析器進行解析,lxml速度快,文件容錯能力強,也能使用html5lib soup = BeautifulSoup(html, 'lxml') items = soup.find_all('span', 'txt') return items |
六,寫入csv檔案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
def write_to_csv(items, artist_name): with open("music163_songs.csv", "a") as csvfile: writer = csv.writer(csvfile) writer.writerow(["歌手名字", artist_name]) for item in items: writer.writerow([item.a['href'].replace('/song?id=', ''), item.b['title']]) print('歌曲id:', item.a['href'].replace('/song?id=', '')) song_name = item.b['title'] print('歌曲名字:', song_name) csvfile.close() |
七,讀取csv檔案,構造全部歌手的個人主頁
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# 獲取歌手id和歌手姓名 def read_csv(): with open("music163_artists.csv", "r", encoding="utf-8") as csvfile: reader = csv.reader(csvfile) for row in reader: artist_id, artist_name = row if str(artist_id) is "artist_id": continue else: yield artist_id, artist_name # 當程式的控制流程離開with語句塊後, 檔案將自動關閉 |
八,程式主函式
1 2 3 4 5 6 7 8 9 10 11 12 |
# 主函式 def main(): for readcsv in read_csv(): artist_id, artist_name = readcsv url = "https://music.163.com/#/artist?id=" + str(artist_id) print("正在獲取{}的熱門歌曲...".format(artist_name)) html = get_html_src(url) items = parse_html_page(html) print("{}的熱門歌曲獲取完成!".format(artist_name)) print("開始將{}的熱門歌曲寫入檔案".format(artist_name)) write_to_csv(items, artist_name) print("{}的熱門歌曲寫入到本地成功!".format(artist_name)) |
九,總結
獲取全部程式碼請上我的github,爬取過程中有任何問題歡迎留言!
作者簡介:志穎,一個狂熱的 python 爬蟲愛好者。