爬取《Five Hundred Miles》在網易雲音樂的全部評論

本文原創發佈於微信公衆號「極客猴」,歡迎關注第一時間獲取更多原創分享python

在使用 Ajax 技術加載數據的網站中, JavaScript 發起的 HTTP 請求一般須要帶上參數,並且參數的值都是通過加密的。若是咱們想利用網站的 REST API 來爬取數據,就必須知道其使用的加密方式。破解過程須要抓包,閱讀並分析網站的 js 代碼。這整個過程可能會花費一天甚至更長的時間。git

問:那麼是否有辦法繞過這機制,直接獲取網站數據? 答:有的。使用 Selenium 庫模擬瀏覽器行爲來抓取網站數據,達到事半功倍的效果。github

本文內容是利用 Selenium 爬取網易雲音樂中的歌曲 《Five Hundred Miles》 的全部評論,而後存儲到 Mongo 數據庫。web

0 前期準備

本文中所用到的工具比較多,因此我將其列舉出來。chrome

  • Selenium

Selenium 是一個 Web 應用程序自動化測試的工具。它可以模擬瀏覽器進行網頁加載。因此使用其來幫助咱們解決 JavaScript 渲染問題。數據庫

接下來就是安裝 selenium, 使用 pip 安裝是最方便的。瀏覽器

pip install selenium
複製代碼
  • Chrome 瀏覽器

在爬取數據過程當中, 須要啓動瀏覽器來顯示頁面。所以,電腦中須要一款瀏覽器。這裏推薦使用 Chrome 瀏覽器。推薦使用 59 版本以上的 Chrome,固然能使用最新版本那最好不過,目前最新版本是 68。服務器

  • Webdriver

Webdriver 是瀏覽器驅動。selenium 經過 Webdriver 來操做瀏覽器。由於咱們使用的瀏覽器是 Chrome,因此須要下載 Chrome 瀏覽器對應的驅動。微信

下載地址:chromedriver.chromium.org/downloads網絡

webdriver 下載解壓完成以後,將其放到 Python 目錄下的 Script 文件夾中。

  • MongoDB

網易雲音樂的評論數據總數都很大,十幾萬條數據比比皆是,甚至還有上百萬條數據。因此須要將數據存儲到數據庫中,我選用的是 MongoDB。

  • pymongo

pymongo 是 Python 操做 MongoDB 的庫。一樣使用 pip 進行安裝。

pip install pymongo
複製代碼

1 爬取思路

1)使用 Selenium 驅動 Chrome 瀏覽器打開須要爬取的頁面。 2)獲取頁面中 最新評論 標籤後面的評論總數,計算出一共有多少個分頁, 方便統計。利用總評論數除以 20(每一個頁面顯示 20 條評論),而後對結果進行向上取整。 3)爬取第一頁面的評論的數據,而後存儲到數據庫中。 4)利用 Selenium 模擬點擊下一頁按鈕,再繼續爬取該頁面的評論數據,並存儲到數據庫中。 5)一直循環點擊,直到全部分頁的數據都被爬取完成。

2 代碼實現

咱們要爬取的歌曲是 《Five Hundred Miles》,先找到其 url 地址,而後調用爬取函數。

if __name__ == '__main__':
    url = 'http://music.163.com/#/song?id=27759600'  # Five Hundred Miles
    start_spider(url)
複製代碼

使用 selenium 啓動 Chrome 瀏覽器。

from selenium import webdriver

def start_spider(url):
    """ 啓動 Chrome 瀏覽器訪問頁面 """
    """ # 從 Chrome 59 版本, 支持 Headless 模式(無界面模式), 即不會彈出瀏覽器 chrome_options = webdriver.ChromeOptions() chrome_options.add_argument('--headless') brower = webdriver.Chrome(chrome_options=chrome_options) """
    brower = webdriver.Chrome()
    brower.get(url)
    # 等待 5 秒, 讓評論數據加載完成
    time.sleep(5)
    # 頁面嵌套一層 iframe, 必須切換到 iframe, 才能定位的到 iframe 裏面的元素
    iframe = brower.find_element_by_class_name('g-iframe')
    brower.switch_to.frame(iframe)
    # 獲取【最新評論】總數
    new_comments = brower.find_elements(By.XPATH, "//h3[@class='u-hd4']")[1]
複製代碼

根據評論總數計算出總分頁數。

# start_spider(url)
max_page = get_max_page(new_comments.text)


def get_max_page(new_comments):
    """ 根據評論總數, 計算出總分頁數 """
    print('=== ' + new_comments + ' ===')
    max_page = new_comments.split('(')[1].split(')')[0]
    # 每頁顯示 20 條最新評論
    offset = 20
    max_page = ceil(int(max_page) / offset)
    print('一共有', max_page, '個分頁')
    return max_page
複製代碼

接着循環抓取評論數據,首先抓取第 1 頁的評論數據。

# start_spider(url)
current = 1
is_first = True
while current <= max_page:
    print('正在爬取第', current, '頁的數據')
    if current == 1:
        is_first = True
    else:
        is_first = False
    data_list = get_comments(is_first, brower)


def get_comments(is_first, brower):
    """ 獲取評論數據 """
    items = brower.find_elements(By.XPATH, "//div[@class='cmmts j-flag']/div[@class='itm']")
    # 首頁的數據中包含 15 條精彩評論, 20 條最新評論, 只保留最新評論
    if is_first:
        items = items[15: len(items)]

    data_list = []
    data = {}
    for each in items:
        # 用戶 id
        userId = each.find_elements_by_xpath("./div[@class='head']/a")[0]
        userId = userId.get_attribute('href').split('=')[1]
        # 用戶暱稱
        nickname = each.find_elements_by_xpath("./div[@class='cntwrap']/div[1]/div[1]/a")[0]
        nickname = nickname.text
        # 評論內容
        content = each.find_elements_by_xpath("./div[@class='cntwrap']/div[1]/div[1]")[0]
        content = content.text.split(':')[1]  # 中文冒號
        # 點贊數
        like = each.find_elements_by_xpath("./div[@class='cntwrap']/div[@class='rp']/a[1]")[0]
        like = like.text
        if like:
            like = like.strip().split('(')[1].split(')')[0]
        else:
            like = '0'
        # 頭像地址
        avatar = each.find_elements_by_xpath("./div[@class='head']/a/img")[0]
        avatar = avatar.get_attribute('src')

        data['userId'] = userId
        data['nickname'] = nickname
        data['content'] = content
        data['like'] = like
        data['avatar'] = avatar
        print(data)
        data_list.append(data)
        data = {}
    return data_list
複製代碼

將第 1 頁評論數據存儲到 Mongo 數據庫中。

# start_spider(url)
save_data_to_mongo(data_list)


def save_data_to_mongo(data_list):
    """ 一次性插入 20 條評論。 插入效率高, 下降數據丟失風險 """
    collection = db_manager[MONGO_COLLECTION]
    try:
        if collection.insert_many(data_list):
            print('成功插入', len(data_list), '條數據')
    except Exception:
        print('插入數據出現異常')
複製代碼

模擬點擊「下一頁」按鈕。

# start_spider(url)
time.sleep(1)
go_nextpage(brower)
# 模擬人爲瀏覽
time.sleep(random.randint(8, 12))
current += 1


def go_nextpage(brower):
    """ 模擬人爲操做, 點擊【下一頁】 """
    next_button = brower.find_elements(By.XPATH, "//div[@class='m-cmmt']/div[3]/div[1]/a")[-1]
    if next_button.text == '下一頁':
        next_button.click()
複製代碼

最後就一直循環爬取評論。

3 爬取結果

評論總數大概有 23W 條, 我又在代碼中增長延時操做。因此爬取全部評論大概須要 69 個小時。目前我只跑了 9 個小時,我貼下暫時爬取的結果。

4 擴展知識

這部份內容跟上述內容聯繫不大, 屬於服務器技術範疇。若是你不感興趣的話,能夠直接跳過。另外,這部份內容是本身的理解。若是有講錯的地方,還請多多指出。

咱們訪問普通網站的整個過程:

咱們訪問使用 Ajax 加載數據的網站的整個過程:

附: 程序源碼 Github 倉庫地址:163MusicCommentsCrawler


本文首發於微信公衆號,原文地址是 爬取《Five Hundred Miles》在網易雲音樂的全部評論。隨時歡迎轉載文章, 轉載請聯繫號主開通白名單,尊重做者的原創。本人微信公衆號「極客猴」,每週分享 Python 原創乾貨。涉及網絡爬蟲、數據分析、web 開發等方向。

相關文章
相關標籤/搜索