Python爬蟲小白入門(六)爬取披頭士樂隊歷年專輯封面-網易雲音樂

1、前言


前文說過個人設計師小夥伴的設計需求,他想作一個披頭士樂隊歷年專輯的瀑布圖。html

經過搜索,發現網易雲音樂上有比較全的歷年專輯信息加配圖,圖片質量還能夠,雖然有大有小。git

個人例子怎麼都是爬取圖片?(誰讓你老是跟設計師小夥伴一塊兒玩耍。。。)看來圖片對於設計師來講仍是有着很深的情節,那就看他用這些圖片能作出什麼樣的做品啦,期待一下,後續會展現一下他的做品。github

其實爬取網易雲音樂跟以前爬取的網站稍稍有點不一樣,固然,爬蟲寫的多了就以爲套路都是固定的,見招拆招而已。web

2、運行環境


個人運行環境以下:框架

  • 系統版本
    Windows10。ide

  • Python版本
    Python3.5,推薦使用Anaconda 這個科學計算版本,主要是由於它自帶一個包管理工具,能夠解決有些包安裝錯誤的問題。去Anaconda官網,選擇Python3.5版本,而後下載安裝。函數

  • IDE
    我使用的是PyCharm,是專門爲Python開發的IDE。這是JetBrians的產品,點我下載工具

3、實戰


上面提到過,網易雲音樂的網頁跟普通的網頁相比主要有兩點不一樣:網站

  • 網頁是 js 動態加載的
  • 使用了iframe框架

因此,
首先,網頁請求不能使用requests庫,須要使用Selenium + PhatomJS。
其次,使用Selenium + PhatomJS後,還須要針對 iframe 作特定處理。atom

廢話很少說,看實際操做步驟:
首先打開網頁 http://music.163.com

在右上角的搜索框中輸入「The Beatles」,而後會有一個下拉選項,選擇歌手 The Beatles (紅框中的內容)。

而後看到以下頁面,選擇紅框中的「全部專輯」,點擊。

這樣就會看見全部的專輯列表,以及下方的翻頁按鈕。

咱們須要的就是全部專輯的圖片、專輯名和專輯出版時間。看到這就能夠構想一下爬蟲的爬取邏輯了。定位到該頁面,而後獲取頁碼,而後挨個請求頁面來爬取頁面中的內容。

點擊一下翻頁按鈕看看url 有沒有什麼規律。

點擊第二頁後,看到上面的地址欄!!!看到這個地址欄我都懶得翻頁了。。。

limit 參數是限制一個頁面加載專輯的個數
offset 參數是前面過濾多少個專輯,如今是一頁12個專輯,因此第二頁是offset=12,第三頁offset=24,以此類推。。。

一共9頁,一頁12個,也不到120個。So... ... 改一下url 就不用翻頁了!!

limit 參數等於120,offset 參數 等於0,就搞定了! 輸入下面的url,看看是否是全部的專輯都加載出來了。

http://music.163.com/#/artist/album?id=101988&limit=120&offset=0

下面就開始爬蟲代碼了。
這裏咱們會用到上一篇博文中寫好的幾個工具方法:

def save_img(self, url, file_name): ##保存圖片
        print('開始請求圖片地址,過程會有點長...')
        img = self.request(url)
        print('開始保存圖片')
        f = open(file_name, 'ab')
        f.write(img.content)
        print(file_name,'圖片保存成功!')
        f.close()

    def request(self, url):  #封裝的requests 請求
        r = requests.get(url)  # 像目標url地址發送get請求,返回一個response對象。有沒有headers參數均可以。
        return r

    def mkdir(self, path):  ##這個函數建立文件夾
        path = path.strip()
        isExists = os.path.exists(path)
        if not isExists:
            print('建立名字叫作', path, '的文件夾')
            os.makedirs(path)
            print('建立成功!')
            return True
        else:
            print(path, '文件夾已經存在了,再也不建立')
            return False

    def get_files(self, path): #獲取文件夾中的文件名稱列表
        pic_names = os.listdir(path)
        return pic_names

OK, 開始咱們的爬蟲邏輯部分:

這裏值得注意的是,該頁面使用frame 框架,使用Selenium + PhantomJS 後並不會加載iframe 框架中的網頁內容。iframe 框架至關於在頁面中又加載了一個頁面,須要使用Selenium 的 switch_to.frame() 方法加載(官網給的方法是switch_to_frame(),可是IDE提醒使用前面的方法替代該方法)。

看下面的網頁結構,iframe的id是「g_iframe」:



加載 iframe 框架中的內容:

driver = webdriver.PhantomJS()
driver.get(self.init_url)
driver.switch_to.frame("g_iframe")
html = driver.page_source

而後找到全部的封面元素:

根據上圖的網頁結構能夠看出,全部的專輯信息都在ul 標籤裏面,每個專輯在一個li 標籤裏。li 標籤中包含了圖片url、專輯名字、以及專輯時間。

抓取其中的內容就行了。

all_li = BeautifulSoup(html, 'lxml').find(id='m-song-module').find_all('li')

for li in all_li:
    album_img = li.find('img')['src']
    album_name = li.find('p', class_='dec')['title']
    album_date = li.find('span', class_='s-fc3').get_text()

這裏獲取到的圖片url 依然是有圖片寬高參數的,因此要過濾寬高參數:
http://p4.music.126.net/pLA1GX0KtU-vU4ZA6Cr-OQ==/1401877340532770.jpg?param=120y120

把問號後面的參數過濾掉:

end_pos = album_img.index('?')  #找到問號的位置
album_img_url = album_img[:end_pos]  #截取問號以前的內容

圖片命名邏輯:專輯時間 + 專輯名。
專輯名可能有一些特殊字符,須要替換掉!
photo_name = album_date + ' - ' + album_name.replace('/','').replace(':',',') + '.jpg'

再使用上一篇博文例子中的去重邏輯,修改後的爬蟲邏輯部分以下:

def spider(self):
        print("Start!")
        driver = webdriver.PhantomJS()
        driver.get(self.init_url)
        driver.switch_to.frame("g_iframe")
        html = driver.page_source

        self.mkdir(self.folder_path)  # 建立文件夾
        print('開始切換文件夾')
        os.chdir(self.folder_path)  # 切換路徑至上面建立的文件夾

        file_names = self.get_files(self.folder_path)  # 獲取文件夾中的全部文件名,類型是list

        all_li = BeautifulSoup(html, 'lxml').find(id='m-song-module').find_all('li')
        # print(type(all_li))

        for li in all_li:
            album_img = li.find('img')['src']
            album_name = li.find('p', class_='dec')['title']
            album_date = li.find('span', class_='s-fc3').get_text()
            end_pos = album_img.index('?')
            album_img_url = album_img[:end_pos]

            photo_name = album_date + ' - ' + album_name.replace('/','').replace(':',',') + '.jpg'
            print(album_img_url, photo_name)

            if photo_name in file_names:
                print('圖片已經存在,再也不從新下載')
            else:
                self.save_img(album_img_url, photo_name)

其實相對於上篇博文的例子,這個爬蟲的邏輯部分仍是挺簡潔的。

最後上一個完整的代碼: 也能夠從GitHub下載

from selenium import webdriver
from bs4 import BeautifulSoup
import requests
import os

class AlbumCover():

    def __init__(self):
        self.init_url = "http://music.163.com/#/artist/album?id=101988&limit=120&offset=0" #請求網址
        self.folder_path = "C:\D\TheBeatles" #想要存放的文件目錄

    def save_img(self, url, file_name):  ##保存圖片
        print('開始請求圖片地址,過程會有點長...')
        img = self.request(url)
        print('開始保存圖片')
        f = open(file_name, 'ab')
        f.write(img.content)
        print(file_name, '圖片保存成功!')
        f.close()

    def request(self, url):  # 封裝的requests 請求
        r = requests.get(url)  # 像目標url地址發送get請求,返回一個response對象。有沒有headers參數均可以。
        return r

    def mkdir(self, path):  ##這個函數建立文件夾
        path = path.strip()
        isExists = os.path.exists(path)
        if not isExists:
            print('建立名字叫作', path, '的文件夾')
            os.makedirs(path)
            print('建立成功!')
            return True
        else:
            print(path, '文件夾已經存在了,再也不建立')
            return False

    def get_files(self, path):  # 獲取文件夾中的文件名稱列表
        pic_names = os.listdir(path)
        return pic_names

    def spider(self):
        print("Start!")
        driver = webdriver.PhantomJS()
        driver.get(self.init_url)
        driver.switch_to.frame("g_iframe")
        html = driver.page_source

        self.mkdir(self.folder_path)  # 建立文件夾
        print('開始切換文件夾')
        os.chdir(self.folder_path)  # 切換路徑至上面建立的文件夾

        file_names = self.get_files(self.folder_path)  # 獲取文件夾中的全部文件名,類型是list

        all_li = BeautifulSoup(html, 'lxml').find(id='m-song-module').find_all('li')
        # print(type(all_li))

        for li in all_li:
            album_img = li.find('img')['src']
            album_name = li.find('p', class_='dec')['title']
            album_date = li.find('span', class_='s-fc3').get_text()
            end_pos = album_img.index('?')
            album_img_url = album_img[:end_pos]

            photo_name = album_date + ' - ' + album_name.replace('/', '').replace(':', ',') + '.jpg'
            print(album_img_url, photo_name)

            if photo_name in file_names:
                print('圖片已經存在,再也不從新下載')
            else:
                self.save_img(album_img_url, photo_name)

album_cover = AlbumCover()
album_cover.spider()

執行結果:

看看文件夾裏面什麼樣:

歷年的專輯封面已經到手啦,還有專輯的名稱和發行日期。

4、後語


這個實戰很好的運用了我們以前講解的知識:

  • 使用Selenium + PhatomJS 抓取動態頁面
  • 使用Selenium 的switch_to.frame() 加載 iframe 中的內容
  • 使用requests 庫獲取圖片
  • 使用BeautifulSoup 庫解析抓取網頁內容。
  • 使用os 庫建立文件夾和獲取文件夾中的文件名稱列表

使用現有的知識編寫簡單的爬蟲是不成問題了。接下來會講講爬蟲框架,就從如今比較流行的Scrapy 框架講起吧。

我得找找比較合適的例子,工做中用到的爬蟲不太方便貼上來,有合適的實例我會繼續更新。

有任何的疑問能夠留言,就先醬紫吧。

See you then.

相關文章
相關標籤/搜索