首页 > 编程语言 >python 爬虫 试了五种爬喜马的方法并做了测试代码(爬虫系列研究告一段落了...)

python 爬虫 试了五种爬喜马的方法并做了测试代码(爬虫系列研究告一段落了...)

时间:2022-11-23 19:35:43浏览次数:57  
标签:album ... python list 爬虫 url track rlt page


先介绍一下我想到和测试了的五种方法:

 方法1,使用下面接口:
        通过web_api 'http://m.ximalaya.com/m-revision/page/album/queryAlbumPage/%s?pageSize=1000'%albumid
        获取tracklist,不包函最终声音文件的url,要用 _update_track_media_url 来更新
        返回格式,这个接口,似乎只是返回专辑的首页用的
        分页:不能切换只能看第一页
        页大小:pageSize认是30,最大是1000条,如果pageSize设置超1000的话,返回就会是0条,
        提序:不能排序。
        文件下载地址:无
        专辑中如果超过 1000条声音就不适用了,只能下载前1000条

python 爬虫 试了五种爬喜马的方法并做了测试代码(爬虫系列研究告一段落了...)_chrome

方法2,使用下面接口:
​​​         http://m.ximalaya.com/m-revision/common/album/queryAlbumTrackRecordsByPage?albumId=15839339&page=2&pageSize=7​​​         这个接口应该是用于手机端显示的,
        分页(page):可以,
        页大小:pageSize 默认是 7 条,最大20,超20就会报错。
        排序:无法排序。
        文件下载地址: 文件下载地址字段(playPath)   
        page 超 过总页数后 "trackDetailInfos":[] 返回会是空列表,可用来判断是否到尾页了。

python 爬虫 试了五种爬喜马的方法并做了测试代码(爬虫系列研究告一段落了...)_分页_02

方法3,使用下面接口:
​​​         https://www.ximalaya.com/revision/play/album?albumId=15839339&pageNum=1&sort=-1&pageSize=30​​​         分页(page):可以,
        页大小:pageSize #最大30,超过会自动改为30
        排序:可排序。
        文件下载地址: 文件下载地址字段(src)   
        hasMore 字段为false 表示已尾页,,可用来判断是否到尾页了。
        page 超 过总页数后 "tracksAudioPlay":[] 返回会是空列表,可用来判断是否到尾页了。

python 爬虫 试了五种爬喜马的方法并做了测试代码(爬虫系列研究告一段落了...)_chrome_03

方法4,使用下面接口(两接口是一致的):
​​​         https://www.ximalaya.com/revision/album/getTracksList?albumId=15839339&pageNum=11&sort=0​​​         https://m.ximalaya.com/revision/album/getTracksList?albumId=15839339&pageNum=1&sort=0
        分页(page):可以,
        页大小:pageSize 固定为30。
        排序:可排序。
        文件下载地址: 不含  ,要用 _update_track_media_url 来更新
        page 超 过总页数后 "tracks":[] 返回会是空列表,可用来判断是否到尾页了。

python 爬虫 试了五种爬喜马的方法并做了测试代码(爬虫系列研究告一段落了...)_分页_04

 

 

方法5:直接解析专辑网页HTML,取出tracklist

用正则表达式来取出列表

python 爬虫 试了五种爬喜马的方法并做了测试代码(爬虫系列研究告一段落了...)_下载地址_05

 

其中,方法 4 方法5 没有直接取到文件下载的路径,所以增加了 通过selenuime 来操纵 chrome , 模拟播放声音动作,并从chrome的 network 日志中取出 media 的url, 更新到 trac_list的 mediaurl 和 title  ,这种取 media 地址的方法会比较慢,但最靠谱,中要是能播放的,就一定能取到。

python 爬虫 试了五种爬喜马的方法并做了测试代码(爬虫系列研究告一段落了...)_下载地址_06

 

 

贴上完整代码,爬虫的实验告一段落,接下准备研究一下 kivy GUI 和制作安卓apk.

#!/usr/bin/python
# -*- coding: utf-8 -*-
# By xulong , [email protected] ,20190606
# python3
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.chrome.options import Options
from urllib import request
from urllib.parse import urlparse
import time
import json
import re
import os

headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36"}


def get_track_list_by_ablum_url(ablum_url,way):
"""
参数:ablum_url,专集的URL,如:https://www.ximalaya.com/youshengshu/22573551
way,1:方法1,2:方法2,3:方法3,4:方法4,
返回:track_list,格式例子:
# index ,title ,url,mediaurl
[
{'index':64, 'title':'第064集',
'url':'https://www.ximalaya.com/youshengshu/22573551/187940972','mediaurl':''},
{'index':65, 'title':'第065集',
'url':'https://www.ximalaya.com/youshengshu/22573551/187940972','mediaurl':''}
]
"""

def _update_track_media_url(track_list):
"""
通过selenuime 来操纵 chrome , 模拟播放声音动作,并从chrome的 network 日志中取出 media 的url,
更新到 trac_list的 mediaurl 和 title
"""

if len(track_list) == 0 :
return

#chrome 浏览器初始化开始-----------------------------------------------------------------
chrome_options = Options()
chrome_options.add_argument('--no-sandbox') #解决DevToolsActivePort文件不存在的报错
chrome_options.add_argument('window-size=1920x3000') #指定浏览器分辨率
chrome_options.add_argument('--disable-gpu') #谷歌文档提到需要加上这个属性来规避bug
chrome_options.add_argument('--hide-scrollbars') #隐藏滚动条, 应对一些特殊页面
chrome_options.add_argument('blink-settings=imagesEnabled=false') #不加载图片, 提升速度
chrome_options.add_argument('--headless') #隐藏浏览器窗口

d = DesiredCapabilities.CHROME
d['loggingPrefs'] = { 'performance':'ALL' }
#chrome 浏览器初始化结束-----------------------------------------------------------------


#更新tract的tittle和mediaurl-begin
browser = webdriver.Chrome(chrome_options=chrome_options,desired_capabilities=d)
for tr in track_list:
idx = tr['index']
title = tr['title']
url = tr['trackurl']
mediaurl = ''
#取medaiURL,网络可能异常,所以用饭否多取两次,取到了就退出循环
for t in range(2):
try:
browser.get(tr['trackurl'])
if tr['title'] == '':
tr['title']=browser.find_element_by_class_name('title-wrapper').text
playBtn=browser.find_element_by_class_name('play-btn')
playBtn.click()
time.sleep(0.001*t)
playBtn.click()

entries = browser.get_log('performance')
for entry in entries:
try:
j=json.loads(entry['message'])
if j['message']['params']['type']=='Media':
mediaurl=(j['message']['params']['request']['url'])
#print(mediaurl)
if mediaurl != '':
break
except Exception as e:
pass
except Exception as e:
pass
if mediaurl != '':
break
#已取完 mediaurl
tr['mediaurl'] = mediaurl

browser.quit()
del browser


#下面用不同的方法或接口,实现了几个取track list 的 function.

def _get_track_list_url_1(ablum_url):
"""
方法1,使用下面接口:
通过web_api 'http://m.ximalaya.com/m-revision/page/album/queryAlbumPage/%s?pageSize=1000'%albumid
获取tracklist,不包函最终声音文件的url,要用 _update_track_media_url 来更新
返回格式,这个接口,似乎只是返回专辑的首页用的
分页:不能切换只能看第一页
页大小:pageSize认是30,最大是1000条,如果pageSize设置超1000的话,返回就会是0条,
提序:不能排序。
文件下载地址:无
专辑中如果超过 1000条声音就不适用了,只能下载前1000条
"""
_r=urlparse(ablum_url)
_url_prex = '%s://%s'%(_r.scheme,_r.netloc)
_album_id = os.path.split(ablum_url.rstrip('/'))[1]

_rlt_list=[]
_url = 'http://m.ximalaya.com/m-revision/page/album/queryAlbumPage/%s?pageSize=1000'%_album_id
req=request.Request(url=_url,headers=headers)
r = request.urlopen(req)
c = r.read()
#c = c.decode('utf-8')
j = json.loads(c)
if 'freeOrSingleAlbumData' not in j['data']['typeSpecData'].keys(): return _rlt_list
trs = j['data']['typeSpecData']['freeOrSingleAlbumData']['albumPageTrackRecords']['trackDetailInfos']
_rlt_list.extend([{
'index':0,
'title':t['trackInfo']['title'],
'trackurl':'%s%s'%(_url_prex, t['pageUriInfo']['url']),
'mediaurl':t['trackInfo']['playPath']
}
for t in trs ])
return _rlt_list

def _get_track_list_url_2(ablum_url):
"""
方法2,使用下面接口:
http://m.ximalaya.com/m-revision/common/album/queryAlbumTrackRecordsByPage?albumId=15839339&page=2&pageSize=7
这个接口应该是用于手机端显示的,
分页(page):可以,
页大小:pageSize 默认是 7 条,最大20,超20就会报错。
排序:无法排序。
文件下载地址: 文件下载地址字段(playPath)
page 超 过总页数后 "trackDetailInfos":[] 返回会是空列表,可用来判断是否到尾页了。
"""
_r=urlparse(ablum_url)
_url_prex = '%s://%s'%(_r.scheme,_r.netloc)
_album_id = os.path.split(ablum_url.rstrip('/'))[1]

_page_num = 1
_page_size = 7 #最大20
_rlt_list=[]

_url = 'http://m.ximalaya.com/m-revision/common/album/queryAlbumTrackRecordsByPage?albumId=%s&page=%s&pageSize=%s'%(_album_id,_page_num,_page_size)
while _url != '':
_url = 'http://m.ximalaya.com/m-revision/common/album/queryAlbumTrackRecordsByPage?albumId=%s&page=%s&pageSize=%s'%(_album_id,_page_num,_page_size)
req=request.Request(url=_url,headers=headers)
r = request.urlopen(req)
c = r.read()
#c = c.decode('utf-8')
j = json.loads(c)
trs = j['data']['trackDetailInfos']
_rlt_list.extend([{
'index':0,
'title':t['trackInfo']['title'],
'trackurl':'%s%s'%(_url_prex, t['pageUriInfo']['url']),
'mediaurl':t['trackInfo']['playPath']
}
for t in trs ] )
_page_num+=1
if len(trs) == 0:
_url = ''
return _rlt_list


def _get_track_list_url_3(ablum_url):
"""
方法3,使用下面接口:
https://www.ximalaya.com/revision/play/album?albumId=15839339&pageNum=1&sort=-1&pageSize=30
分页(page):可以,
页大小:pageSize #最大30,超过会自动改为30
排序:可排序。
文件下载地址: 文件下载地址字段(src)
hasMore 字段为false 表示已尾页,,可用来判断是否到尾页了。
page 超 过总页数后 "tracksAudioPlay":[] 返回会是空列表,可用来判断是否到尾页了。
"""
_r=urlparse(ablum_url)
_url_prex = '%s://%s'%(_r.scheme,_r.netloc)
_album_id = os.path.split(ablum_url.rstrip('/'))[1]

_page_num = 1
_page_size = 30 #最大30,超过会自动改为30
_rlt_list=[]

_url = 'https://www.ximalaya.com/revision/play/album?albumId=%s&pageNum=%s&sort=0&pageSize=%s'%(_album_id,_page_num,_page_size)
while _url != '':
_url = 'https://www.ximalaya.com/revision/play/album?albumId=%s&pageNum=%s&sort=0&pageSize=%s'%(_album_id,_page_num,_page_size)
req=request.Request(url=_url,headers=headers)
r = request.urlopen(req)
c = r.read()
#c = c.decode('utf-8')
j = json.loads(c)
trs = j['data']['tracksAudioPlay']
_rlt_list.extend([{
'index':t['index'],
'title':t['trackName'],
'trackurl':'%s%s'%(_url_prex, t['trackUrl']),
'mediaurl':t['src']
}
for t in trs ] )
_page_num+=1
if len(trs) == 0:
_url = ''

return _rlt_list

def _get_track_list_url_4(ablum_url):
"""
方法4,使用下面接口(两接口是一致的):
https://www.ximalaya.com/revision/album/getTracksList?albumId=15839339&pageNum=11&sort=0
https://m.ximalaya.com/revision/album/getTracksList?albumId=15839339&pageNum=1&sort=0
分页(page):可以,
页大小:pageSize 固定为30。
排序:可排序。
文件下载地址: 不含 ,要用 _update_track_media_url 来更新
page 超 过总页数后 "tracks":[] 返回会是空列表,可用来判断是否到尾页了。
"""
_r=urlparse(ablum_url)
_url_prex = '%s://%s'%(_r.scheme,_r.netloc)
_album_id = os.path.split(ablum_url.rstrip('/'))[1]

_page_num = 1
_page_size = 30 #固定为30,无法改
_rlt_list=[]

_url = 'https://www.ximalaya.com/revision/album/getTracksList?albumId=%s&pageNum=%s&sort=0'%(_album_id,_page_num)

while _url != '':
_url = 'https://www.ximalaya.com/revision/album/getTracksList?albumId=%s&pageNum=%s&sort=0'%(_album_id,_page_num)
print(_url)

req=request.Request(url=_url,headers=headers)
r = request.urlopen(req)
c = r.read()
#c = c.decode('utf-8')
j = json.loads(c)
trs = j['data']['tracks']
_rlt_list.extend([{
'index':t['index'],
'title':t['title'],
'trackurl':'%s%s'%(_url_prex, t['url']),
'mediaurl':''
}
for t in trs ] )
_page_num+=1
if len(trs) == 0:
_url = ''
_update_track_media_url(_rlt_list)
return _rlt_list

def _get_track_list_url_5(ablum_url):
"""
方法5:
通过分析专辑的网页HTML来获取tracklist,不包函最终声音文件的url,要用 _update_track_media_url 来更新
"""
_next_page_match_str = r'<li\s+class="page-next page-item _dN2">.*?<a\s+class="page-link _dN2"\s+href="(.*?)"></a></li>'

#普通可听专辑
_track_match_str1 = r'<span\s+class="num _OO">(\d+)</span>.*?<a\s+title="(.*?)"\s+href="(.*?)"'
#vip试听专辑
_track_match_str2 = r'<li class="_OO"><div class="icon-wrapper _OO">.*?<a\s+title="(.*?)"\s+href="(.*?)"'

_rlt_list=[]
_r=urlparse(ablum_url)
_url_prex = '%s://%s'%(_r.scheme,_r.netloc)
_url=ablum_url
while _url != '':
print(_url)
req=request.Request(url=_url,headers=headers)
r = request.urlopen(req)
c = r.read()
r.close()
del(r)
c = c.decode("utf-8")

s=re.findall(_track_match_str1,c,re.S )
if len(s) != 0:
_rlt_list.extend([{
'index':int(t[0]),
'title':t[1],
'trackurl':'%s%s'%(_url_prex,t[2]),
'mediaurl':''
}
for t in s])
else:
s=re.findall(_track_match_str2,c,re.S )
_rlt_list.extend([{
'index': 0,
'title':t[0],
'trackurl':'%s%s'%(_url_prex,t[1]),
'mediaurl':''
}
for t in s])


#print(c)
s=re.findall(_next_page_match_str,c,re.S)
if len(s) == 1:
_url = '%s%s'%(_url_prex,s[0])
else:
_url = ''
_update_track_media_url(_rlt_list)
return _rlt_list
#以上是5种取trackurl的方法


_rlt_list = []
if way == 1:
_rlt_list=_get_track_list_url_1(ablum_url)
elif way == 2:
_rlt_list=_get_track_list_url_2(ablum_url)
elif way == 3:
_rlt_list=_get_track_list_url_3(ablum_url)
elif way == 4:
_rlt_list=_get_track_list_url_4(ablum_url)
elif way == 5:
_rlt_list=_get_track_list_url_5(ablum_url)


print('catch:',_rlt_list)

return _rlt_list

def download_track_list(track_list,save_path):
"""
参数:
track_list(格式例子):
# index ,title ,url,mediaurl
[
{'index':64, 'title':'第064集',
'url':'https://www.ximalaya.com/youshengshu/22573551/187940972','mediaurl':''},
{'index':65, 'title':'第065集',
'url':'https://www.ximalaya.com/youshengshu/22573551/187940972','mediaurl':''}
]
save_path : 文件下载保存的目录
"""
for tr in track_list:
if tr['mediaurl'] != '':
f_path = '%s/%s.m4a'%(save_path,tr['title'])
print(tr)
with open(f_path,'wb') as f:
try:
req=request.Request(url=tr['mediaurl'],headers=headers)
r = request.urlopen(req)
ct=r.read()
f.write(ct)
except http_client.IncompleteRead as e:
ct=e.partial
f.write(ct)
except Exception as e:
pass



if __name__ == '__main__':

#针对两种类型的专辑,测试各种取URL的方法,并记录到文件。
typelist = []
#普通可听专辑
albumURL='https://www.ximalaya.com/xiangsheng/23154860'
typelist.append({'type':'普通可听专辑','albumurl':albumURL})

#VIP/付费/试听专辑
albumURL='https://www.ximalaya.com/youshengshu/15358207'
typelist.append({'type':'VIP/付费/试听专辑','albumurl':albumURL})

for i in range(1,6):
for t in typelist:
albumURL = t['albumurl']
tracklist=get_track_list_by_ablum_url(albumURL,i)
with open('d:/GetMediaUrlLog.log','a+') as f:
f.write('方法:%d,类型:%s--------------------------------------\n'%(i,t['type']))
f.write('序号, 标题, 文件URL\n')
f.write('-------------------------------------------\n')
for t in tracklist:
f.write('%d, %s, %s\n'%(t['index'],t['title'],t['mediaurl']))
else:
f.write('-------------------------------------------\n\n\n\n')





##下载tracklist
#save_path = 'd:/test'
#if not(os.path.isdir(save_path)):
# os.path.mkir(save_path)
#download_track_list(track_list,save_path):

要执行的exe文件的,请转之前的文章下载(核心用的是每1种方法,gui用的tkinter):


标签:album,...,python,list,爬虫,url,track,rlt,page
From: https://blog.51cto.com/fangkailove/5881717

相关文章

  • Python 处理输入法字库(五笔极点字库转小鸭字库)
    一直都是用的小鸭五笔,091新字库是极点格式的,刚开始懒得动,直接用极点五笔了,用了一段时间碰到很多问题.其中最坑的是.在tkinterGui里极点输入不能退格,一退格就乱码( ......
  • Python 统计学生总分
    输入学生的学号、姓名以及语文、数学、外语成绩,统计每个学生的总分,并按总分升序输出所有学生的学号、姓名和总分。输入格式:输入若干行数据,每一行数据分别为学号、姓名以......
  • vim-python全能补全与python环境变量设置
    vim针对python的万能补全对于python自带的模块库都能够正常使用全能补全,但一些自定义的模块却不行,这是因为vim当前进程需要找到相应模块并做导入分析获取补全用的词......
  • Python的GET和POST请求
    引入requests包注:发送请求(包括请求行、方法类型、头、体)&常见的请求方式有get、post、put、delete一、发送get请求格式:requests.get()(内容:url必填;params选填:u......
  • 【Bug】No validator... javax.validation.constraints.NotBlank validating type jav
    经检查,是因为在Integer类型的字段上加了@NotBlank的校验注解,而该注解只能用于字符串类型,因此报类型不匹配异常@NotBlank(message="整季量不能为空")privateInteger......
  • 6. python和Redis交互
    1安装包pipinstallredis2引入模块fromredisimport*这个模块中提供了StrictRedis对象(Strict严格),用于连接redis服务器,并按照不同类型提供了不同方法,进行交互操作......
  • Python 性能检测分析方法 - 时间、空间衡量方法
    性能检测分析方法-时间、空间衡量方法Python自带模块importtime点击查看代码#仅仅是示范time模块的用法,此段不能直接运行,运行请看测试项目源码importtime......
  • python四十期--mysql
    昨日内容回顾存取数据演变史1.文本文件2.目录规范3.数据库ps:数据处理统一数据库应用史1.本地存储2.网络存储ps:数据库集群数据库本质数据库在不同的场......
  • python爬取房产信息(仅供学习使用)
    importrequestsfrombs4importBeautifulSoupimporttimeimportopenpyxldefwrite_mysql(lst):wk=openpyxl.Workbook()sheet=wk.activeforiinlst:......
  • python+OpenCv 图像噪声(椒盐噪声、高斯噪声)
    由于图像采集、处理、传输等过程不可避免的会受到噪声的污染,妨碍人们对图像理解及分析处理。常见的图像噪声有高斯噪声、椒盐噪声等。一、椒盐噪声椒盐噪声也称为脉冲......