1. 程式人生 > >python爬取喜馬拉雅FM音訊

python爬取喜馬拉雅FM音訊

前前言

喜馬拉雅已經更換標籤,我重新更新了下程式碼,思路還是如此,需要的可以掃一下文末公眾號二維碼(本人會在上面發表爬蟲以及java的文章還有送書等資源福利哦),也可以直接搜尋公眾號“ 猿獅的單身日常”,好了廣告結束…

前言

之前寫過爬取圖片的一篇文章,這回來看看如何爬取音訊。圖片,音訊,視訊這類都可以通過二進位制方式儲存到本地下載下來。
爬取圖片文章的連結:
python爬取圖片並以二進位制方式儲存到本地

目標

本次我們爬取的目標是–喜馬拉雅FM
這裡寫圖片描述

喜馬拉雅FM有數不計的音訊,這些音訊都有自己的分類,所以進一步給自己丟擲一個需求,爬取喜馬拉雅所有分類的音訊

這裡寫圖片描述

我們可以看到這裡包括了大量的分類,那麼我們找一個分類來看看其內部是怎樣的

這裡寫圖片描述

這裡我們可以看到文學類下面的諸多FM節目,那麼點開節目,有的需要充值,有的免費,還有很多頁這樣的節目

這裡寫圖片描述

繼續跟進,可以看到,我們需要爬取的音訊列表了!
好了,所以現在目標已經清晰起來了:找到所有分類 -> 對每一個分類,獲取其中所有頁的FM節目->對每一個FM節目,爬取其下列表裡的所有免費的音訊

開始動刀

第一步

程式碼如下:

category_Url = 'https://www.ximalaya.com/category/'
base_url = 'https://www.ximalaya.com'
base_api = 'https://www.ximalaya.com/revision/play/tracks?trackIds='
header = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36'
}
client = pymongo.MongoClient(host='localhost', port=27017)
db = client['ximalaya']

def getUrl():
    r = requests.get(category_Url, headers=header)
    html = r.text
    result = re.findall(r'<a class="e-2880429693 item separator".*?href="(.*?)">(.*?)</a>', html, re.S)
    url_list = []
    for i in result:
        # 以一個分類為例  - - 有聲書中的文學類,若沒有break 則可獲取全部分類
        second_url = base_url + i[0]
        url_list.append(second_url)
        # 獲取該分類中全部的頁數
        getMorePage(second_url)
        print second_url
        break

分析每個分類的標籤,獲取網頁原始碼中的所有分類,這裡的category_Url是上面提到的所有分類得介面的URL

還定義一些要用到的基本的,比如請求頭、連線MongoDB等,在這裡添加了break,是因為音訊數過多,所以以有聲書為例

第二步

def getMorePage(url):
    r = requests.get(url, headers=header)
    m_list_html = r.text
    pageNum = re.findall(r'(\d+)</span></a></li><li class="e-3793817119 page-next page-item">', m_list_html,re.S)
    pageNum = int(pageNum[0])
    # 迴圈獲取每一頁,這裡暫時獲取第一頁
    for i in range(1, pageNum + 1):
        if i == 1:
            page_url = url
            # 獲取頁中的30個FM
            getMusicList(page_url, i)
        else:
            page_url = url + 'p{}/'.format(i)
            getMusicList(page_url, i)
        #爬取一頁
        break

進入一個分類後,可以看到很多頁的FM節目,所以應該想辦法迴圈獲取頁面的內容,這裡我們發現頁面數在網頁原始碼中存在,通過正則我們將其取出,然後迴圈

第三步

def getMusicList(url, page):
    r = requests.get(url, headers=header)
    m_list_html = r.text
    result = re.findall(
        r'<a class="e-1889510108.*?href="(.*?)"><img.*?src="(.*?)".*?alt="(.*?)".*?/>.*?"e-1889510108 icon-earphone xuicon xuicon-erji"></i>(.*?)</span>.*?"e-2896848410 album-author".*?title="(.*?)">',
        m_list_html, re.S)
    info = []
    # 獲取該page中每一個FM的資料資訊,可以存入MongoDB
    for i in result:
        FM_info = {}
        #每個節目的url
        FM_url = base_url + i[0] 
        FM_info['url'] = FM_url
        FM_info['picture'] = i[1]
        FM_info['name'] = i[2]
        FM_info['playback'] = i[3]
        FM_info['author'] = i[4]
        info.append(FM_info)
        # 獲取該FM中的音訊資訊
        # os.mkdir('D:\\Python\\PycharmProject\\Enhance\\xmly_fm\\{}'.format(FM_info['name']))
        get_FM_music(FM_url)
        # 先獲取一個FM

    # for j in info:
    #     print j
    test = db['page' + str(page)]
    test.insert(info)

以每頁的url為引數傳入**getMusicList()**獲取每一頁中的30個FM節目資訊,可以將每個節目的資訊存入到MongoDB中;然後是獲取每個節目中的音訊

第四步

def get_FM_music(fm_url):
    print fm_url
    r = requests.get(fm_url, headers=header)
    FM_music_html = r.text
    track_list = re.findall(r'<div class="e-2304105070 text"><a.*?title="(.*?)".*?href="(.*?)">.*?</a>', FM_music_html,re.S)
    detail_info = []
    # 爬取一個FM下的每個音訊
    j = 1
    for i in track_list:
        detail = {}
        # 獲取爬取音訊所需的trackIds
        id = str(i[1]).split('/')[3]
        detail['title'] = i[0]
        detail['detail_url'] = base_url + i[1]
        detail_info.append(detail)
        # api中的資料資訊
        get_detailFM_api(id)
        print u'已獲取第' + str(j) + u'個音訊'
        j += 1
    print detail['title']+u',該音訊爬取完畢'
    time.sleep(2+random.randint(1,10))

獲取每個音訊對應的url,這裡需要注意,自我們點選一個音訊的時候

這裡寫圖片描述

進入到以下介面

這裡寫圖片描述

我們既然要獲取音訊,那麼不妨開啟開發者工具,再點選播放音訊試試
結果我們發現,點選播放按鈕,傳送了一個請求:
這裡寫圖片描述

同時我們可以看到我們所需的音訊源就在這裡:
這裡寫圖片描述
這裡寫圖片描述

所以我們可以通過獲取頁面url的最後一部分,構建一個請求,傳送後就可以獲取json資料,從而獲得音訊源的url

第五步

def get_detailFM_api(id):
    api = base_api + id
    print api
    r = requests.get(api, headers=header)
    result = r.json()
    src = result['data']['tracksForAudioPlay'][0]
    if src['src']:
        print u'試聽'
        r = requests.get(src['src'], headers=header)
        try:
            f = open('D:\\Python\\PycharmProject\\Enhance\\xmly_fm\\{}.m4a'.format(src['trackName']),'wb')
        except:
            print u'已存在'
            pass
        f.write(r.content)
        f.close
        print u'儲存完畢...'
    else:
        print u'需要收費'
        pass

通過訪問音訊源,以r.content將音訊儲存到本地
這裡寫圖片描述

這裡儲存的時候還需改進,希望做到對每個節目新建一個資料夾,將該節目的音訊存入對應的資料夾中

最後,程式從這裡開始執行

if __name__ == '__main__':
    getUrl()

有疑問或更好的方法的話,歡迎交流!

下一篇應該是爬取網易雲的,或者是爬取視訊;最近也是忙著期末的考試,我也算是碰見了最佩服的老師…(考試時看我們做的試卷,唉,急的直接說答案了!!…)

公眾號二維碼
猿獅的單身日常