前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >教大家爬取喜马拉雅全站音频数据,探秘喜马拉雅的天籁之音

教大家爬取喜马拉雅全站音频数据,探秘喜马拉雅的天籁之音

作者头像
润森
发布2022-08-18 09:46:01
3.4K0
发布2022-08-18 09:46:01
举报
文章被收录于专栏:毛利学Python毛利学Python

一、前言

喜马拉雅FM是一个知名的音频分享平台,在移动音频行业的市场占有率已达73%,用户规模突破4.8亿,今天我们就带大家突破层层障碍,探秘喜马拉雅的天籁之音,实现实时抓捕并保存到本地。

个人觉得,听书也是对情感的一种认知和感受。看书的时候我们可以天马行空,有各种理解,但听的时候呢,听一些优质的声音和读物,可以试着从别人的声音里感知一些信息和情绪,就像我们在日常生活中一样,不仅要用眼睛看,还需要用耳朵去听呀。

二、寻找音频的URL

首先打开喜马拉雅的网址:https://www.ximalaya.com/

然后我们输入关键字 进行搜索,此处以荒村阴阳师为例,如下图:

爬取的数据如下

你就会发现了:https://aod.cos.tx.xmcdn.com/group82/M00/8E/B8/wKg5HF8b_PXC6K1wADMmSFDB0hw087.m4a 就是下载一个MP3的链接,点击下载

访问下:https://aod.cos.tx.xmcdn.com/

j经过我的分析,这个应该Nigux代理请求,因此需要找到这个url的来源

在这里插入图片描述

三、请求参数的处理

在这里插入图片描述

没错,就是这个:https://www.ximalaya.com/revision/play/v1/audio?id=68966138&ptype=1

在请求参数中,有一个xm-sign需要处理下

这个xm-sign是:md5(服务器时间戳)(100以内随机数)服务器时间戳(100以内随机数)现在时间戳。

这个我看出来的,为什么呢?因为我是大神,没有为什么???

获取服务器时间戳,这个我也发现了,是https://www.ximalaya.com/revision/time

「我真的大神,你们可以叫我大师」

四、重新分析目标网站

重新分析目标网站:https://www.ximalaya.com/yinyue/12576446/ 分析每一页网页url有什么不同:第一页的是https://www.ximalaya.com/revision/play/albumalbumId=12576446&pageNum=1&sort=1&pageSize=30第二页https://www.ximalaya.com/revision/play/albumalbumId=12576446&pageNum=2&sort=1&pageSize=30第三页https://www.ximalaya.com/revision/play/albumalbumId=12576446&pageNum=3&sort=1&pageSize=30

一共有十七页,可以使用Python当中的.format方法来占位(方法不唯一)

五、实现代码

代码如下

代码语言:javascript
复制
import hashlib
import json
import os
import re
import time
import random
import requests

'''有声书下载'''
class ximalaya(object):
    def __init__(self):
        self.base_url = 'https://www.ximalaya.com'
        self.base_api = 'https://www.ximalaya.com/revision/play/album?albumId={}&pageNum={}&sort=0&pageSize=30'
        self.time_api = 'https://www.ximalaya.com/revision/time'
        self.header = {'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0'}
        self.s = requests.session()

    def get_time(self):
        """
        获取服务器时间戳
        :return:
        """
        r = self.s.get(self.time_api, headers=self.header)
        return r.text

    def get_sign(self):
        """
        获取sign:md5(服务器时间戳)(100以内随机数)服务器时间戳(100以内随机数)现在时间戳
        :return: xm_sign
        """
        nowtime = str(round(time.time() * 1000))
        servertime = self.get_time()
        sign = str(hashlib.md5("himalaya-{}".format(servertime).encode()).hexdigest()) + "({})".format(
            str(round(random.random() * 100))) + servertime + "({})".format(str(round(random.random() * 100))) + nowtime
        self.header["xm-sign"] = sign


    def index_choose(self):
        xm_id = input(u'请输入要获取喜马拉雅节目的ID:')
        xima.get_fm(xm_id)
        self.index_choose()

    @staticmethod
    def make_dir(xm_fm_id):
        # 保存路径,请自行修改,这里是以有声书ID作为文件夹的路径
        fm_path = './{}'.format(xm_fm_id)
        f = os.path.exists(fm_path)
        if not f:
            os.makedirs(fm_path)
            print('make file success')
        else:
            print('file already exists')
        return fm_path

    def get_fm(self, xm_fm_id,lable='youshengshu'):
        # 根据有声书ID构造url
        fm_url = self.base_url + '/{}/{}'.format(lable,xm_fm_id)
        r_fm_url = self.s.get(fm_url, headers=self.header)
        fm_title = re.findall('<h1 class="title vA_">(.*?)</h1>', r_fm_url.text, re.S)[0]
        print('书名:' + fm_title)
        # 新建有声书ID的文件夹
        fm_path = self.make_dir(xm_fm_id)
        # 取最大页数
        s = re.findall(r'/{}/{}/p(\d+)/'.format(lable,xm_fm_id), r_fm_url.text, re.S)
        max_page = sorted([int(i) for i in s])[-1]

        if max_page:
            for page in range(1, int(max_page) + 1):
                print('第' + str(page) + '页')
                self.get_sign()
                r = self.s.get(self.base_api.format(xm_fm_id, page), headers=self.header)
                r_json = json.loads(r.text)
                for audio in r_json['data']['tracksAudioPlay']:
                    audio_title = str(audio['trackName']).replace(' ', '')
                    audio_src = audio['src']
                    self.get_detail(audio_title, audio_src, fm_path)
                # 每爬取1页,30个音频,休眠3秒
                time.sleep(3)
        else:
            print(os.error)

    def get_detail(self, title, src, path):
        r_audio_src = self.s.get(src, headers=self.header)
        m4a_path = path+'/' + title + '.m4a'
        if not os.path.exists(m4a_path):
            with open(m4a_path, 'wb') as f:
                f.write(r_audio_src.content)
                print(title + '保存完毕...')
        else:
            print(title + 'm4a已存在')


if __name__ == '__main__':
    xima = ximalaya()
    xima.index_choose()
    # 12576446

六、爬取结果

可能有人问这样的目的是什么?我可以在APP或者网页上的直接听啊!

诶~对于某些需要的收费的节目,量又很大,你可能会员过期了就无法享受其中的内容,所以可以通过这种方式“下载”

当然最终要的还是为了让大家理解爬虫的一些思路

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-10-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小刘IT教程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、前言
  • 二、寻找音频的URL
  • 三、请求参数的处理
  • 四、重新分析目标网站
  • 五、实现代码
  • 六、爬取结果
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档