前前言
喜馬拉雅已經(jīng)更換標(biāo)簽,我重新更新了下代碼,思路還是如此,需要的可以掃一下文末公眾號(hào)二維碼(本人會(huì)在上面發(fā)表爬蟲以及java的文章還有送書等資源福利哦),也可以直接搜索公眾號(hào)“ 猿獅的單身日?!保昧藦V告結(jié)束...
前言
之前寫過爬取圖片的一篇文章,這回來看看如何爬取音頻。圖片,音頻,視頻這類都可以通過二進(jìn)制方式保存到本地下載下來。
爬取圖片文章的鏈接:
python爬取圖片并以二進(jìn)制方式保存到本地
目標(biāo)
本次我們爬取的目標(biāo)是--喜馬拉雅FM
喜馬拉雅FM有數(shù)不計(jì)的音頻,這些音頻都有自己的分類,所以進(jìn)一步給自己拋出一個(gè)需求,爬取喜馬拉雅所有分類的音頻
接下來我們來分析這些分類,找到所有分類 https://www.ximalaya.com/category/
我們可以看到這里包括了大量的分類,那么我們找一個(gè)分類來看看其內(nèi)部是怎樣的
這里我們可以看到文學(xué)類下面的諸多FM節(jié)目,那么點(diǎn)開節(jié)目,有的需要充值,有的免費(fèi),還有很多頁這樣的節(jié)目
繼續(xù)跟進(jìn),可以看到,我們需要爬取的音頻列表了!
好了,所以現(xiàn)在目標(biāo)已經(jīng)清晰起來了:找到所有分類 -> 對(duì)每一個(gè)分類,獲取其中所有頁的FM節(jié)目->對(duì)每一個(gè)FM節(jié)目,爬取其下列表里的所有免費(fèi)的音頻
開始動(dòng)刀
第一步
代碼如下:
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:
# 以一個(gè)分類為例 - - 有聲書中的文學(xué)類,若沒有break 則可獲取全部分類
second_url = base_url + i[0]
url_list.append(second_url)
# 獲取該分類中全部的頁數(shù)
getMorePage(second_url)
print second_url
break
分析每個(gè)分類的標(biāo)簽,獲取網(wǎng)頁源碼中的所有分類,這里的category_Url是上面提到的所有分類得界面的URL
還定義一些要用到的基本的,比如請求頭、連接MongoDB等,在這里添加了break,是因?yàn)橐纛l數(shù)過多,所以以有聲書為例
第二步
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])
# 循環(huán)獲取每一頁,這里暫時(shí)獲取第一頁
for i in range(1, pageNum + 1):
if i == 1:
page_url = url
# 獲取頁中的30個(gè)FM
getMusicList(page_url, i)
else:
page_url = url + 'p{}/'.format(i)
getMusicList(page_url, i)
#爬取一頁
break
進(jìn)入一個(gè)分類后,可以看到很多頁的FM節(jié)目,所以應(yīng)該想辦法循環(huán)獲取頁面的內(nèi)容,這里我們發(fā)現(xiàn)頁面數(shù)在網(wǎng)頁源碼中存在,通過正則我們將其取出,然后循環(huán)
這里我們注意一下其頁面的url :
https://www.ximalaya.com/youshengshu/wenxue/p2/
后面的p2對(duì)應(yīng)頁數(shù),而第一頁沒有p,所以需要判斷,這里也同樣以第一頁為例
第三步
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中每一個(gè)FM的數(shù)據(jù)信息,可以存入MongoDB
for i in result:
FM_info = {}
#每個(gè)節(jié)目的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)
# 先獲取一個(gè)FM
# for j in info:
# print j
test = db['page' + str(page)]
test.insert(info)
以每頁的url為參數(shù)傳入getMusicList()獲取每一頁中的30個(gè)FM節(jié)目信息,可以將每個(gè)節(jié)目的信息存入到MongoDB中;然后是獲取每個(gè)節(jié)目中的音頻
第四步
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 = []
# 爬取一個(gè)FM下的每個(gè)音頻
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中的數(shù)據(jù)信息
get_detailFM_api(id)
print u'已獲取第' + str(j) + u'個(gè)音頻'
j += 1
print detail['title']+u',該音頻爬取完畢'
time.sleep(2+random.randint(1,10))
獲取每個(gè)音頻對(duì)應(yīng)的url,這里需要注意,自我們點(diǎn)擊一個(gè)音頻的時(shí)候
進(jìn)入到以下界面
我們既然要獲取音頻,那么不妨打開開發(fā)者工具,再點(diǎn)擊播放音頻試試
結(jié)果我們發(fā)現(xiàn),點(diǎn)擊播放按鈕,發(fā)送了一個(gè)請求:
https://www.ximalaya.com/revision/play/tracks?trackIds=93433726
注意trackIds就是當(dāng)前音頻url的最后一部分:
https://www.ximalaya.com/youshengshu/11377428/93433726
同時(shí)我們可以看到我們所需的音頻源就在這里:
所以我們可以通過獲取頁面url的最后一部分,構(gòu)建一個(gè)請求,發(fā)送后就可以獲取json數(shù)據(jù),從而獲得音頻源的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'需要收費(fèi)'
pass
通過訪問音頻源,以r.content將音頻保存到本地
這里保存的時(shí)候還需改進(jìn),希望做到對(duì)每個(gè)節(jié)目新建一個(gè)文件夾,將該節(jié)目的音頻存入對(duì)應(yīng)的文件夾中
最后,程序從這里開始運(yùn)行
if __name__ == '__main__':
getUrl()
有疑問或更好的方法的話,歡迎交流!
下一篇應(yīng)該是爬取網(wǎng)易云的,或者是爬取視頻;最近也是忙著期末的考試,我也算是碰見了最佩服的老師...(考試時(shí)看我們做的試卷,唉,急的直接說答案了??!...)
完整代碼可以在我的GitHub上下載~
https://github.com/joelYing/XimalayaFM
print('微信公眾號(hào)搜索 "猿獅的單身日常" ,Java技術(shù)升級(jí)、蟲師修煉,我們 不見不散!')
print('也可以掃下方二維碼哦~')
