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()
有疑問或更好的方法的話,歡迎交流!
下一篇應該是爬取網易雲的,或者是爬取視訊;最近也是忙著期末的考試,我也算是碰見了最佩服的老師…(考試時看我們做的試卷,唉,急的直接說答案了!!…)
公眾號二維碼