Python爬蟲:大規(guī)模爬取喜馬拉雅電臺(tái)詳細(xì)音頻數(shù)據(jù)

喜馬拉雅

一:前言

本次爬取的是喜馬拉雅的熱門欄目下全部電臺(tái)的每個(gè)頻道的信息和頻道中的每個(gè)音頻數(shù)據(jù)的各種信息,然后把爬取的數(shù)據(jù)保存到mongodb以備后續(xù)使用。這次數(shù)據(jù)量在70萬(wàn)左右。音頻數(shù)據(jù)包括音頻下載地址,頻道信息,簡(jiǎn)介等等,非常多。
昨天進(jìn)行了人生中第一次面試,對(duì)方是一家人工智能大數(shù)據(jù)公司,我準(zhǔn)備在這大二的暑假去實(shí)習(xí),他們就要求有爬取過(guò)音頻數(shù)據(jù),所以我就來(lái)分析一下喜馬拉雅的音頻數(shù)據(jù)爬下來(lái)。目前我還在等待三面中,或者是通知最終面試消息。 (因?yàn)槟艿玫揭欢隙?,不管成功與否都很開心)


二:運(yùn)行環(huán)境

  • IDE:Pycharm 2017
  • Python3.6
  • pymongo 3.4.0
  • requests 2.14.2
  • lxml 3.7.2
  • BeautifulSoup 4.5.3

三:實(shí)例分析

1.首先進(jìn)入這次爬取的主頁(yè)面http://www.ximalaya.com/dq/all/ ,可以看到每頁(yè)12個(gè)頻道,每個(gè)頻道下面有很多的音頻,有的頻道中還有很多分頁(yè)。抓取計(jì)劃:循環(huán)84個(gè)頁(yè)面,對(duì)每個(gè)頁(yè)面解析后抓取每個(gè)頻道的名稱,圖片鏈接,頻道鏈接保存到mongodb。

熱門頻道

2.打開開發(fā)者模式,分析頁(yè)面,很快就可以得到想要的數(shù)據(jù)的位置。下面的代碼就實(shí)現(xiàn)了抓取全部熱門頻道的信息,就可以保存到mongodb中。

start_urls = ['http://www.ximalaya.com/dq/all/{}'.format(num) for num in range(1, 85)]
for start_url in start_urls:
    html = requests.get(start_url, headers=headers1).text
    soup = BeautifulSoup(html, 'lxml')
    for item in soup.find_all(class_="albumfaceOutter"):
        content = {
            'href': item.a['href'],
            'title': item.img['alt'],
            'img_url': item.img['src']
        }
        print(content)
分析頻道

3.下面就是開始獲取每個(gè)頻道中的全部音頻數(shù)據(jù)了,前面通過(guò)解析頁(yè)面獲取到了美國(guó)頻道的鏈接。比如我們進(jìn)入http://www.ximalaya.com/6565682/album/237771 這個(gè)鏈接后分析頁(yè)面結(jié)構(gòu)。可以看出每個(gè)音頻都有特定的ID,這個(gè)ID可以在一個(gè)div中的屬性中獲取。使用split()和int()來(lái)轉(zhuǎn)換為單獨(dú)的ID。

頻道頁(yè)面分析

4.接著點(diǎn)擊一個(gè)音頻鏈接,進(jìn)入開發(fā)者模式后刷新頁(yè)面然后點(diǎn)擊XHR,再點(diǎn)擊一個(gè)json鏈接可以看到這個(gè)就包括這個(gè)音頻的全部詳細(xì)信息。

html = requests.get(url, headers=headers2).text
numlist = etree.HTML(html).xpath('//div[@class="personal_body"]/@sound_ids')[0].split(',')
for i in numlist:
    murl = 'http://www.ximalaya.com/tracks/{}.json'.format(i)
    html = requests.get(murl, headers=headers1).text
    dic = json.loads(html)
音頻頁(yè)面分析

5.上面只是對(duì)一個(gè)頻道的主頁(yè)面解析全部音頻信息,但是實(shí)際上頻道的音頻鏈接是有很多分頁(yè)的。

html = requests.get(url, headers=headers2).text
ifanother = etree.HTML(html).xpath('//div[@class="pagingBar_wrapper"]/a[last()-1]/@data-page')
if len(ifanother):
    num = ifanother[0]
    print('本頻道資源存在' + num + '個(gè)頁(yè)面')
    for n in range(1, int(num)+1):
        print('開始解析{}個(gè)中的第{}個(gè)頁(yè)面'.format(num, n))
        url2 = url + '?page={}'.format(n)
        # 之后就接解析音頻頁(yè)函數(shù)就行,后面有完整代碼說(shuō)明
分頁(yè)

6.全部代碼
完整代碼地址github.com/rieuse/learnPython

__author__ = '布咯咯_rieuse'

import json
import random
import time
import pymongo
import requests
from bs4 import BeautifulSoup
from lxml import etree

clients = pymongo.MongoClient('localhost')
db = clients["XiMaLaYa"]
col1 = db["album"]
col2 = db["detaile"]

UA_LIST = []  # 很多User-Agent用來(lái)隨機(jī)使用可以防ban,顯示不方便不貼出來(lái)了
headers1 = {} # 訪問(wèn)網(wǎng)頁(yè)的headers,這里顯示不方便我就不貼出來(lái)了
headers2 = {} # 訪問(wèn)網(wǎng)頁(yè)的headers這里顯示不方便我就不貼出來(lái)了

def get_url():
    start_urls = ['http://www.ximalaya.com/dq/all/{}'.format(num) for num in range(1, 85)]
    for start_url in start_urls:
        html = requests.get(start_url, headers=headers1).text
        soup = BeautifulSoup(html, 'lxml')
        for item in soup.find_all(class_="albumfaceOutter"):
            content = {
                'href': item.a['href'],
                'title': item.img['alt'],
                'img_url': item.img['src']
            }
            col1.insert(content)
            print('寫入一個(gè)頻道' + item.a['href'])
            print(content)
            another(item.a['href'])
        time.sleep(1)


def another(url):
    html = requests.get(url, headers=headers2).text
    ifanother = etree.HTML(html).xpath('//div[@class="pagingBar_wrapper"]/a[last()-1]/@data-page')
    if len(ifanother):
        num = ifanother[0]
        print('本頻道資源存在' + num + '個(gè)頁(yè)面')
        for n in range(1, int(num)+1):
            print('開始解析{}個(gè)中的第{}個(gè)頁(yè)面'.format(num, n))
            url2 = url + '?page={}'.format(n)
            get_m4a(url2)
    get_m4a(url)


def get_m4a(url):
    time.sleep(1)
    html = requests.get(url, headers=headers2).text
    numlist = etree.HTML(html).xpath('//div[@class="personal_body"]/@sound_ids')[0].split(',')
    for i in numlist:
        murl = 'http://www.ximalaya.com/tracks/{}.json'.format(i)
        html = requests.get(murl, headers=headers1).text
        dic = json.loads(html)
        col2.insert(dic)
        print(murl + '中的數(shù)據(jù)已被成功插入mongodb')


if __name__ == '__main__':
    get_url()

7.如果改成異步的形式可以快一點(diǎn),只需要修改成下面這樣就行了。我試了每分鐘要比普通的多獲取近100條數(shù)據(jù)。這個(gè)源代碼也在github中。

異步

五:總結(jié)

這次抓取的數(shù)據(jù)量在70萬(wàn)左右,這些數(shù)據(jù)后續(xù)可以進(jìn)行很多研究,比如播放量排行榜、時(shí)間區(qū)段排行、頻道音頻數(shù)量等等。后續(xù)我將繼續(xù)學(xué)習(xí)使用科學(xué)計(jì)算和繪圖工具來(lái)進(jìn)行數(shù)據(jù)分析,清洗的工作。

抓取的數(shù)據(jù)是頻道的信息和頻道中的每個(gè)音頻具體信息。


Paste_Image.png

Paste_Image.png

貼出我的github地址,我的爬蟲代碼和學(xué)習(xí)寫的代碼都放進(jìn)去了,有喜歡的朋友可以點(diǎn)擊 start follw一起學(xué)習(xí)交流吧!github.com/rieuse/learnPython

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容