爬取網易雲音樂精彩評論

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

(一)java

故事的小黃花python

從出生那年就飄着git

童年的盪鞦韆github

隨記憶一直晃到如今web

Re So So Si Do Si Lajson

So La Si Si Si Si La Si La Soapi

吹着前奏望着天空瀏覽器

我想起花瓣試着掉落服務器

……

小編猴哥有個愛好,喜歡一邊聽着熟悉的旋律,一邊看着網易雲音樂歌曲中的評論,特別是精彩評論。

評論內容,讓人泫然流涕的故事,就是讓人深思的段子。

(二)

某天,猴哥突發奇想,想將本身平時喜歡聽的歌曲的精彩評論爬取下來。之後就能夠直接閱讀這些評論,無須打開網頁。

說幹就幹。猴哥打開瀏覽器訪問網易雲音樂,隨便點擊某個歌曲頁面。如今大多數網站都採用 Ajax 技術來獲取數據。因此須要先判斷網頁是否採用該技術。

有個谷歌瀏覽器插件名爲 Toggle JavaScript,它能控制頁面中 javascript 啓用或者禁用。

正常的頁面長這樣:

當禁用頁面 JavaScript 腳本以後,正常顯示數據頁面會變成一個空白頁面。

所以,能夠判定網易雲音樂加載數據方式採用 Ajax。

Ajax 技術能夠在不刷新頁面的狀況下,利用嵌在 HTML 文檔中的 JavaScript 腳本向服務器請求數據,而後更新到頁面。想進一步確認數據來源,須要知道請求域名以及請求參數。

這就須要藉助瀏覽器的開發者工具(通常按 F12 鍵會顯示),根據抓取數據包進行分析。由於咱們已經肯定網站採用 Ajax ,因此直接在選擇 XHR 過濾器過濾出全部請求。

而後依次對每一個 url 連接的 HTTP 請求進行分析,着重觀察 HeadersPreview 選項。最後,猴哥發現 R_SO_4_186001?csrf_token= 請求中有咱們須要的信息。Preview 中有字段跟精彩評論中用戶名一致。

繼續切換到 Headers 確認請求域名以及請求須要攜帶的參數。

那麼爬取思路是:使用 POST 方式攜帶參數 paramsencSecKey 向該地址 music.163.com/weapi/v1/re… 發起HTTP 請求。返回結果中的 Json 數據就是用戶評論數據。

(三) 既然思路明確,編寫代碼就是容易多了。

這裏,猴哥使用列表來保存想爬取精彩評論的歌曲。

songs_url_list = [
    'http://music.163.com/#/song?id=186016',  # 晴天
    'http://music.163.com/#/song?id=186001',  # 七里香
    'http://music.163.com/#/song?id=27876900',  # Here We Are Again 《喜劇之王》電影插曲
    'http://music.163.com/#/song?id=439915614',  # 恰好碰見你
    'http://music.163.com/#/song?id=139774',  # The truth that you leave
    'http://music.163.com/#/song?id=29567189',  # 理想
    'http://music.163.com/#/song?id=308353',  # 鍾無豔
    'http://music.163.com/#/song?id=31445772',  # 理想三旬
    'http://music.163.com/#/song?id=439915614',  # 恰好碰見你
    'http://music.163.com/#/song?id=28815250',  # 平凡之路
    'http://music.163.com/#/song?id=25706282',  # 夜空中最亮的星
    'http://music.163.com/#/song?id=436514312',  # 成都
]
複製代碼

而後截取每一個連接中 id 字段的值。

def get_song_id(url):
    """ 從 url 中截取歌曲的 id """
    song_id = url.split('=')[1]
    return song_id
複製代碼

接着根據 id 拼接處請求的 url 地址,再使用 requests 發起 HTTP 請求。

for each in songs_url_list:
    start_spider(get_song_id(each))
    time.sleep(random.randint(5, 8))

def start_spider(song_id):
    """ 評論數據採用 AJAX 技術得到, 下面纔是獲取評論的請求地址 """
    url = 'http://music.163.com/weapi/v1/resource/comments/R_SO_4_{}?csrf_token='.format(song_id)

    headers = {
        'User-agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 UBrowser/6.2.3964.2 Safari/537.36',
        'Origin': 'http://music.163.com',
        'Referer': 'http://music.163.com/song?id={}'.format(song_id),
    }

    formdata = {
        'params': '57Wh2mgebLOOPQVBc+B2wz4sCCH/nXZFEoTc/XNySiqT0V7ZxUADzDNgTXXhYgAJ5BNMryMgxhdwNzF1GyxDZo3iR9/YYbWgCAQHC5DCDuObqvxNcOcnQDaRqJCrqQcrEABW1SwKitfbD3wMEyB4tJu+rU8goSwg2FP/PBBLs9DVs1iWdWGjV6CdrocA36Rs',
        'encSecKey': '63774137ba4f5cc60d1b6a3bc14985a9563a7bfdec4f3e74297ffc07514adf18f90620933a01c2db4ca989cc4e1dfc49789981424c294a34e48c2cbe7aa51533a5cc5b5776a9e499cd08770bc596655dbe8e001d1ed5fd47a27dd195128480820cc67a799d341f95d447e3522851f2b64ad1cb8350e2015b265b9e684179351c',
    }

    response = requests.post(url, headers=headers, data=formdata)
    print('請求 [ ' + url + ' ], 狀態碼爲 ')
    print(response.status_code)
    # get_hot_comments(response.text)
    # 將數據寫到 CSV 文件中
    write_to_file(get_hot_comments(response.text))
複製代碼

由於請求返回結果是 Json 數據,咱們只須要精彩評論(HotComments)內容,因此須要對數據進行處理下。

def get_hot_comments(response):
    """ 獲取精彩評論 請求返回結果是 Json 數據格式, 使用 json.loads(response) 將其轉化爲字典類型, 就能夠使用 key-value 形式獲取值 """
    data_list = []
    data = {}

    for comment in json.loads(response)['hotComments']:
        data['userId'] = comment['user']['userId']
        data['nickname'] = comment['user']['nickname']
        data['content'] = comment['content']
        data['likedCount'] = comment['likedCount']
        data_list.append(data)
        data = {}
    # print(data_list)
    return data_list
複製代碼

最後將數據保存到 CSV 文件中。

def write_to_file(datalist):
    print('開始將數據持久化……')
    file_name = '網易雲音樂精彩評論.csv'

    with codecs.open(file_name, 'a+', 'GBK') as csvfile:
        filednames = ['用戶Id', '暱稱', '評論內容', '點贊數']
        writer = csv.DictWriter(csvfile, fieldnames=filednames)

        writer.writeheader()
        for data in datalist:
            print(data)
            try:
                writer.writerow({filednames[0]: data['userId'],
                                 filednames[1]: data['nickname'],
                                 filednames[2]: data['content'],
                                 filednames[3]: data['likedCount']})
            except UnicodeEncodeError:
                print("編碼錯誤, 該數據沒法寫到文件中, 直接忽略該數據")
複製代碼

寫到這裏,小夥伴們應該瞭解如何爬取運用 Ajax 技術加載數據的網站了。可能某些網站的請求攜帶的參數只能使用一次,那就進一步數據包中 js 代碼。推斷出加密方式,本身再用代碼還原。

哈哈,這裏請容許我貼下爬取結果。

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


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

相關文章
相關標籤/搜索