使用 Python 批量下载喜马拉雅有声书音频

文章目录

  • 使用 Python 批量下载喜马拉雅有声书音频
    • 介绍
    • 原理
      • 用到的 API
    • 源码

介绍

在提供喜马拉雅有声书的网页地址(例:https://www.ximalaya.com/youshengshu/3544633/)后,可批量下载这个有声书的所有音频到书名所在的目录。

原理

  1. 分析 URL 得到 book_id。
  2. 通过 book_id 获取书名和总集数。
  3. 通过 book_id 获取每集的列表。
  4. 在列表中提取每集的标题和 audio_id。
  5. 通过 audio_id 获取 audio_url。
  6. 通过 audio_url 获取音频流数据。

用到的 API

# 通过 book_id 获取书名和总集数
https://www.ximalaya.com/revision/album?albumId=book_id

# 通过 book_id 获取每集的列表
https://www.ximalaya.com/revision/album/v1/getTracksList?albumId=book_id&pageNum=page_num

# 通过 audio_id 获取 audio_url
https://www.ximalaya.com/revision/play/v1/audio?id=audio_id&ptype=1

源码

import re
import sys
import time
import json
import requests
import subprocessfrom pathlib import Pathfrom typing import Tuple, List, Generatordef http_get(url: str):headers = {# "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",# "accept-encoding": "gzip, deflate, br",# "accept-language": "zh-CN,zh;q=0.9",# "cache-control": "max-age=0",# "sec-fetch-dest": "document",# "sec-fetch-mode": "navigate",# "sec-fetch-site": "none",# "sec-fetch-user": "?1",# "upgrade-insecure-requests": "1","user-agent": "Windows",}respond = requests.get(url, headers=headers)respond.raise_for_status()return respond.contentdef get_description(book_id: int) -> Tuple[str, str]:url = r"https://www.ximalaya.com/revision/album?albumId=%d" % book_iddata = json.loads(http_get(url))title = data['data']['mainInfo']['albumTitle']total_count = data['data']['tracksInfo']['trackTotalCount']return title, total_countdef get_audio_url(audio_id: int) -> str:url_template = r"https://www.ximalaya.com/revision/play/v1/audio?id=%d&ptype=1"data = json.loads(http_get(url_template % audio_id))return data['data']['src']def get_page_entries(book_id: int, page_num: int) -> List[Tuple[str, str]]:url_template = r"https://www.ximalaya.com/revision/album/v1/getTracksList?albumId=%d&pageNum=%d"data = json.loads(http_get(url_template % (book_id, page_num)))res = []for track in data['data']['tracks']:title = track['title']url = track['url']audio_id = int(url[url.rindex("/")+1:])audio_url = get_audio_url(audio_id)res.append((title, audio_url))return resdef save_to_local(url: str, path: str) -> None:audio = http_get(url)with open(path, "wb+") as file:file.write(audio)def parse_book_id(book_url: str) -> int:return int(re.search(r"/(\d+)/", book_url).groups()[0])def all_entries_generator(book_id: int, begin: int, end: int) -> Generator[Tuple[str, str], None, None]:assert 0 < beginbegin -= 1      # 输入区间为 [begin, end], 调整为 [begin, end)count = 0page_num = 1entries = get_page_entries(book_id, page_num)page_size = len(entries)if count < begin:page_num = begin // page_size + 1if page_num != 1:entries = get_page_entries(book_id, page_num)entries = entries[begin % page_size:]count = beginwhile True:yield from entriescount += len(entries)if count == end:breakpage_num += 1entries = get_page_entries(book_id, page_num)def current_time() -> str:# %Y-%m-%d %H:%M:%Sreturn time.strftime("%H:%M:%S", time.localtime())def pretty_time_interval(second: float) -> str:return time.strftime("%H:%M:%S", time.gmtime(second))def mprint(*args, **kv) -> None:print("%s " % current_time(), end=" ", flush=True)print(*args, **kv)def download(book_url: str, target_folder: str, begin: int = 1) -> int:book_id = parse_book_id(book_url)title, total_count = get_description(book_id)mprint("开始下载 \"%s\",共 %d 集,从第 %d 集开始" % (title, total_count, begin))folder = Path(target_folder) / titlefolder.mkdir(parents=True, exist_ok=True)mprint("下载的数据将保存到 \"%s\"" % folder.absolute())begin_time = time.time()for i, (name, audio_url) in enumerate(all_entries_generator(book_id, begin, total_count)):filename = "%s%s" % (name, audio_url[audio_url.rindex("."):])mprint("第 %04d 集:%-50s" % (i+begin, filename), end="", flush=True)single_download_time = time.time()save_to_local(audio_url, folder / filename)print("%s" % pretty_time_interval(time.time()-single_download_time))total_number = total_count - begin + 1total_time = time.time()-begin_timestatistics = "从第 %d 集到第 %d 集,一共 %d 集,总共耗时 %s,平均每集耗时 %s" % (begin,total_count,total_number,pretty_time_interval(total_time),pretty_time_interval(total_time / total_number))print(statistics)print("已经全部已经下载到 \"%s\"" % folder.absolute())def main():if len(sys.argv) not in (2, 3):raise ValueError("用法:python script.py 音频详情页网址 [保存到的目录]")book_url = sys.argv[1]folder = sys.argv[2] if len(sys.argv) == 3 else r"./"download(book_url, folder)if __name__ == "__main__":main()

使用 Python 批量下载喜马拉雅有声书音频相关推荐

  1. python 喜马拉雅_Python爬虫入门教程14:喜马拉雅有声书音频爬取

    基本开发环境????Python 3.6 Pycharm 相关模块的使用????import requests import os 安装Python并添加到环境变量,pip安装需要的相关模块即可. 一 ...

  2. Python爬虫入门教程14:喜马拉雅有声书音频爬取

    基本开发环境

  3. JS + shell 批量下载 喜马拉雅FM 的音频

    一直在线收听喜马拉雅的音频节目, 收听广播节目节约了大量时间,不管是地铁上还是走路都可以收听,不用低头看书,也脱离了颈椎病的苦恼. 过年回家我想在车上收听,发现只能通过手机播放,效果不好,我就在网上找 ...

  4. 新一配:perl循环调用python爬虫批量下载喜马拉雅音频

    新一配:perl循环调用python爬虫批量下载喜马拉雅音频 手机下载喜马拉雅音频后,获得的音频文件虽然可以转成mp3格式,但其文件名却是一长串字符串,无法辨别是哪一集,网上找了各种工具,都有局限性, ...

  5. JS下载喜马拉雅非付费音频

    JS下载喜马拉雅非付费音频 目录 JS下载喜马拉雅非付费音频 1 Demo"成品"及GitHub地址 2 数据分析 3 JS下载文件流 4 搜索列表,下载音频 5 总结 昨天分析了 ...

  6. python下载网页里面所有的图片-Python批量下载网页图片详细教程

    很多朋友在网上查找批量下载图片的方法~发觉挺凌乱的,无从下手.这里绿茶小编就来跟大家分享下使用Python批量下载图片方法. 目标:爬取某个网站上n多页的链接,每个链接有n多张图片,每一页对应一个文件 ...

  7. 群里又会python的吗_自从会了Python在群里斗图就没输过,Python批量下载表情包!...

    原标题:自从会了Python在群里斗图就没输过,Python批量下载表情包! 导语 最近图慌,于是随便写了个表情包批量下载的脚本,没什么技术含量,纯娱乐性质. 让我们愉快地开始吧~ 开发工具 Pyth ...

  8. python批量下载b站_python 批量下载bilibili视频的gui程序

    运行效果: 完整代码: # !/usr/bin/python # -*- coding:utf-8 -*- # time: 2019/07/02--08:12 __author__ = 'Henry' ...

  9. Python 批量下载SIGMOD,VLDB的论文 Mac OS

    这里写自定义目录标题 Python 批量下载SIGMOD,VLDB的论文 Mac OS 实现 0.要爬取的网站 1.下载单篇论文 2.获得所有论文的链接 完整代码 Python 批量下载SIGMOD, ...

  10. 教你怎么使用python批量下载图片

    教你怎么使用python批量下载图片 文章目录 教你怎么使用python批量下载图片 前言 一.运行环境 1. win10 2. python==3.7.2 二.需要用到的参数 1. download ...

最新文章

  1. Pytorch:使用DCGAN实现数据复制
  2. 登录MOSS站点失败
  3. 【转】Extending Lync Server routing with MSPL
  4. R语言 文本挖掘 tm包 使用
  5. java调用python库pyd_Java调用Python的两种方式
  6. [html] 你是如何理解html与css分离的?
  7. 信息学奥赛一本通 1031:反向输出一个三位数 | OpenJudge NOI 1.3 13
  8. 划重点丨详解Java流程控制语句知识点
  9. Gorgeous Sequence线段树区间跟新
  10. C#的set 和 get 方法
  11. efi文件错误服务器崩溃,[转自百度]关于系统安装时候弹出提示winload.efi文件损坏...
  12. knockoutjs 读源码
  13. 瑞星网络版防病毒软件For Linux通过银河麒麟产品兼容性测试
  14. 【Hive】Establishing SSL connection without server‘s identity verification is not recommended. Accord
  15. Wifi文件传输项目总结
  16. android坐标画图软件下载,地图坐标app下载-地图坐标软件下载v4.8.15 安卓版-西西软件下载...
  17. matlab hanning和hann,哪位大侠能告知——为什么在MATLAB2012中不能调研(汉宁)窗函...
  18. 鸟哥的Linux私房菜(基础篇)中涉及的所有网址
  19. 推理悬疑侦探小说大全合集隐私政策
  20. 谷歌推出新优化器Lion:优化算法的符号发现

热门文章

  1. 【python利用url下载文件】
  2. sql获取服务器系统时间,sql server 获取系统时间的方法
  3. fiddler ctrl+r 打开scripteditor提示报错提示fse2.exe不存在
  4. 防计算机病毒的重点,计算机病毒防范技术重点措施(1).doc
  5. 解决csdn登陆后复制的3种方法
  6. 早期的文章-手机开发平台指南、教程和资料介绍
  7. howler 音频插件使用
  8. vlan的基本指令_华为:vlan基础命令及配置实验
  9. 923模拟电子技术基础和数字电子技术基础考试大纲
  10. 为了进大厂,韩顺平Java教程百度云