Python中使用requests和parsel爬取喜馬拉雅電台音頻


場景

喜馬拉雅電台:

https://www.ximalaya.com/

找到一步小說音頻,這里以下面為例

https://www.ximalaya.com/youshengshu/16411402/

博客:
https://blog.csdn.net/badao_liumang_qizhi
關注公眾號
霸道的程序猿
獲取編程相關電子書、教程推送與免費下載。

實現

找到下載地址

使用谷歌瀏覽器打開上面網址,按F12打開調試,點擊播放按鈕后,然后找到Network下的Media下的Headers下的RequestURL,然后選中在新窗口中打開

 

 

 

打開之后就可以點擊三個點出來之后的下載按鈕,便可以下載

 

 

 

使用代碼下載

打開PyCharm,新建一個Python項目

導入requests庫,然后為了防止其反扒機制,找到瀏覽器上Headers下的Requests Headers下的User-Agent,復制出來。

 

 

 

#能發送http請求的庫
import requests

headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36' 
}
media_url
= 'http://audio.cos.xmcdn.com/group47/M0A/34/EA/wKgKm1tHj6GwgeWBAFehkfjyvKI181.m4a' response = requests.get(media_url,headers = headers); with open('badao.mp4',mode='wb') as f: f.write(response.content)

 

下載成功之后

 

 

 

下載地址獲取

上面只是獲取一個音頻的下載地址,怎樣獲取每一集的下載地址

還是剛才的調試頁面,我們點擊放大鏡樣的搜索按鈕,出來搜索框之后,輸入剛才下載地址的文件名

 

 

 

點擊第一個返回json數據的接口url,找到其Headers下的RequestURL。

 

 

 

然后在新窗口打開

 

 

 

可以看到是通過這個API返回的Json數據中的下載地址。

那么這個API需要傳遞什么參數。通過其Headers底部的請求參數可以看到需要一個id參數和pytype參數。

 

 

 

通過對比每一集的接口的請求參數得知,pytype是固定的,id是每一集對應的鏈接中的id相對應的。

 

 

 

所以要是循環下載多集的話,需要在目錄頁面獲取超鏈接的href屬性中對應的id。

 

 

 

這里我們定義一個請求下載地址json數據的方法

defmedia_api(track_id):
api_url=f'https://www.ximalaya.com/revision/play/v1/audio?id={track_id}&ptype=1'; response = requests.get(api_url,headers = headers) print(response.json()) media_api(98791745)

 

運行下打印json數據

 

 

 

提取下載地址

那么就需要根據傳遞的id參數通過這個接口返回json數據,並從json數據中提取src對應的url數據

def media_api(track_id):   
api_url=f'https://www.ximalaya.com/revision/play/v1/audio?id={track_id}&ptype=1'; response = requests.get(api_url,headers = headers) #print(response.json()) #json返回字典類型 提取使用[] data_json = response.json() src = data_json['data']['src'] return src media_api(98791745)

 

這樣就能根據id獲取每一集的下載地址,然后再將下載地址傳遞給上面第一步下載的方法中進行下載即可。

接下來就是怎樣獲取每一集的id。

parsel解析網頁獲取id

首先需要導入parsel模塊

import parsel

 

如果沒有安裝則需要安裝

pip install parsel

 

 

我們來到其目錄頁

 

 

在Elemnts下可以看到每一集是一個a標簽,我們獲取a標簽的href屬性中的最后面的id。

我們再定義一個方法,此方法能根據頁面的url獲取當前頁的所有集的id。

def get_total_page(page_url):
    #請求頁面
    response = requests.get(page_url,headers = headers)
    print(response.text)
    #獲取頁面html的內容
    sel = parsel.Selector(response.text)
    print(sel)
    #通過css選擇器找到a標簽   .sound-list代表 class屬性為sound-list 然后下面的ul 下的li 下的a
    sound_list = sel.css('.sound-list ul li a')
    print(sound_list)
    #只有前30個是頁面鏈接 截取前30個
    for sound in sound_list[:30]:
        #extract_first()將對象中的文字提取出來
        #獲取a標簽的href屬性的內容
        media_url = sound.css('a::attr(href)').extract_first()
        #/youshengshu/16411402/98791745 --只去最后面的id
        media_url = media_url.split('/')[-1]
        # 獲取a標簽的title屬性的內容
        media_name = sound.css('a::attr(title)').extract_first()
        #用yield將整個循環的內容返回
        yield media_url,media_name

 

 

下載一頁的音頻

我們在main方法中調用獲取當前頁所有的集的id和名字,然后循環將拿到的id去請求api獲取下載的地址,然后將下載地址傳遞給下載的方法去下載

 

if __name__ == '__main__':
    meidas = get_total_page('https://www.ximalaya.com/youshengshu/16411402/')
    for media_id,media_name in meidas:
        #print(media_url, media_name)
        media_url = media_api(media_id)
        download_meida(media_url, media_name)

 

運行程序將一頁下載完

 

 

下載所有頁

我們點擊第二頁看到url中追加了一個p2,依次類推,p+相應的頁數。

這樣就可以將頁面url改造成傳參的

if __name__ == '__main__':
    #循環頁數下載 range代表下載的頁數范圍
    for page in range(2,3):
        meidas = get_total_page(f'https://www.ximalaya.com/youshengshu/16411402/p{page}')
        for media_id,media_name in meidas:
            #print(media_url, media_name)
            media_url = media_api(media_id)
            download_meida(media_url, media_name)

那么在range中就可以輸入要下載的頁數的范圍。

如果輸入(1,31)就是下載所有的30頁,這里只下載第二頁,所以range是(2,3)

代碼下載

關注公眾號:

霸道的程序猿

回復:

爬取喜馬拉雅

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM