怎么用Python爬虫音频平台

搜索郭德纲相声,选择第一个专辑,点击进入。 

 

 

 

找数据小技巧:直接先找xhr分类,如没有数据,再找all里第一个html,一般情况下,批量采集的数据是以json数据格式获取的。

喜马拉雅的音频数据藏在点击播放后的url里。截图中的url正是音频列表的数据了。

 

 接着点开右侧 Preview预览的文件,trackId就是区分每个文件的id。要找到下载数据的地方,就必须找到唯一的关键词。

 顺着左侧的url查看,发现下面这个url对应的右侧数据,有我们需要的.m4a音频文件数据。

 

 经过url的观察,发现请求头里,都会有个xm-sign的数据。没有这个数据,则抓取不到我们要的数据。

 

 那我们就生成xm-sign数据,规则是 md5(himalaya-服务器时间戳)(100以内随机数)服务器时间戳(100以内随机数)现在时间戳。(每次抓取数据的时候,都需要调用该方法,现在时间戳和服务器时间戳相差大到一定值,则获取不到数据)

 

def getServerTime(self):
        """
        获取喜马拉雅服务器的时间戳
        :return:
        """
        # 这个地址就是返回服务器时间戳的接口
        serverTimeUrl = "https://www.ximalaya.com/revision/time"
        response = requests.get(serverTimeUrl,headers = self.headers)
        return response.text
 
    def getSign(self,serverTime):
        """
        生成 xm-sign
        规则是 md5(himalaya-服务器时间戳)(100以内随机数)服务器时间戳(100以内随机数)现在时间戳
        :param serverTime:
        :return:
        """
        nowTime = str(round(time.time()*1000))
 
        sign = str(hashlib.md5("himalaya-{}".format(serverTime).encode()).hexdigest()) + "({})".format(str(round(random.random()*100))) + serverTime + "({})".format(str(round(random.random()*100))) + nowTime
        # 将xm-sign添加到请求头中
        self.headers["xm-sign"] = sign
        return sign

 """
    获取课程下分页的页码(名称,图片,简介,)
    """
    def getPageCount(self,url):
        page_count = 0
        # 分页数据测试
        res = requests.get(url,headers=self.headers)
        try:
            # print(res.text)
            soup = bs4.BeautifulSoup(res.text,'html.parser')
            # print(soup)
            data_list = soup.find('ul',class_='pagination-page _Xo').find_all('li')     # 页码所在的html结构
            
            # lesson_title = soup.find('h1',class_='title lO_').text    # 名称
            # lesson_img = soup.find('img',class_='img lO_')['src']     # 图片
            # lesson_abstract = soup.find('article',class_='intro aB_')     # 简介
            for data in data_list:
                if(data.text.isdigit()):    # 如果是数字,代表是分页的
                    page_count+=1
        except:
            print('='*30 + '不存在分页' + '='*30)
        if(page_count == 0):
            page_count = 1  # 分页从1开始,为第一页
 
        return page_count
        # return lesson_title,lesson_img,lesson_abstract,page_count

这里再引申一下:插入数据到数据库(sql server),其他数据库大同小异。

'''
    连接sql server数据库,增删改查,语句可以在数据库写好,复制进来,因为这里是字符串,不容易发现错误
    '''
    def insertData(self,lesson):
        connect = pymssql.connect('192.168.0.248','***','***','***')    # 服务器名,账户,密码,数据库名
        if connect:
            print('连接成功!')
            cursor = connect.cursor()   # 创建一个游标对象,python里的sql语句都要通过cursor来执行
            sql = "insert into Lesson(parentId,lessonType,lessonImg,lessonName,abstract,lessonFileUrl) values('{}','{}','{}','{}','{}','{}')".format(self.parentId,self.lessonType,self.lessonImg,self.lessonName,self.abstract,self.lessonFileUrl)
            cursor.execute(sql)    # 执行sql语句
            connect.commit()    # 提交
            cursor.close()
            connect.close()

注意看注释喔~ 有问题随时微信联系我们吧。下载的音频文件路径需更改。

import requests,bs4,time
import time
import hashlib
import random
import pymssql
 
'''
插入数据库的数据对象,封装对象,方便调用
'''
class lesson(object):
    def __init__(self,parentId,lessonType,lessonImg,lessonName,abstract,lessonFileUrl):
        self.parentId = parentId
        self.lessonType = lessonType
        self.lessonImg = lessonImg
        self.lessonName = lessonName
        self.abstract = abstract
        self.lessonFileUrl = lessonFileUrl
 
class ximalaya(lesson):
 
    def __init__(self):
        self.headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36"
        }
 
    def getServerTime(self):
        """
        获取喜马拉雅服务器的时间戳
        :return:
        """
        # 这个地址就是返回服务器时间戳的接口
        serverTimeUrl = "https://www.ximalaya.com/revision/time"
        response = requests.get(serverTimeUrl,headers = self.headers)
        return response.text
 
    def getSign(self,serverTime):
        """
        生成 xm-sign
        规则是 md5(himalaya-服务器时间戳)(100以内随机数)服务器时间戳(100以内随机数)现在时间戳
        :param serverTime:
        :return:
        """
        nowTime = str(round(time.time()*1000))
 
        sign = str(hashlib.md5("himalaya-{}".format(serverTime).encode()).hexdigest()) + "({})".format(str(round(random.random()*100))) + serverTime + "({})".format(str(round(random.random()*100))) + nowTime
        # 将xm-sign添加到请求头中
        self.headers["xm-sign"] = sign
        return sign
    '''
    下载音频文件,路径需要设置
    '''
    def downVoice(self,url,fileName):
        serverTime = self.getServerTime()   # 每次执行下载都需要发出请求,xm-sign的现在时间戳和服务器时间戳需要不断更新,才能通过验证
        self.getSign(serverTime)    # 将xm-sign添加到请求头中, 不然无法获取到数据
        try:
            res = requests.get(url,headers=self.headers)
            down_file_url = res.json()['data']['src']   # json解析报错  
            # print(down_file_url)
            down_file_content = requests.get(down_file_url,headers=self.headers)
            with open('D:\\you-get\\喜马拉雅\\'+fileName+'.mp3', 'wb') as file: #保存到本地的文件名, 文件名一样会被替换(这里是特殊情况,可根据需要区分文件名)
                print('正在下载...:'+fileName)
                file.write(down_file_content.content)
                file.flush()
            print('下载完成!!!:'+fileName)
            print('=' * 30)
        except Exception as e:
            print('=====报错的url为:'+url)
            print(e)
    '''
    获取课程下的所有课件列表
    '''
    def getAllLesson(self,url):
        res = requests.get(url,headers=self.headers)
        list_data = res.json()['data']['tracksAudioPlay']
        for data in list_data:
            voice_data_url = 'https://www.ximalaya.com/revision/play/v1/audio?id={}&ptype=1'.format(data['trackId'])
            trackName = data['trackName']
            # lesson.lessonName = trackName     # 装载数据到lesson对象
            # ximalaya.insertData(self,lesson)    # 传入lesson对象
            self.downVoice(voice_data_url,trackName)
            time.sleep(3)
 
    """
    获取课程下分页的页码(名称,图片,简介,)
    """
    def getPageCount(self,url):
        page_count = 0
        # 分页数据测试
        res = requests.get(url,headers=self.headers)
        try:
            # print(res.text)
            soup = bs4.BeautifulSoup(res.text,'html.parser')
            # print(soup)
            data_list = soup.find('ul',class_='pagination-page _Xo').find_all('li')     # 页码所在的html结构
            
            # lesson_title = soup.find('h1',class_='title lO_').text    # 名称
            # lesson_img = soup.find('img',class_='img lO_')['src']     # 图片
            # lesson_abstract = soup.find('article',class_='intro aB_')     # 简介
            for data in data_list:
                if(data.text.isdigit()):    # 如果是数字,代表是分页的
                    page_count+=1
        except:
            print('='*30 + '不存在分页' + '='*30)
        if(page_count == 0):
            page_count = 1  # 分页从1开始,为第一页
 
        return page_count
        # return lesson_title,lesson_img,lesson_abstract,page_count
 
    '''
    连接sql server数据库,增删改查,语句可以在数据库写好,复制进来,因为这里是字符串,不容易发现错误
    '''
    def insertData(self,lesson):
        connect = pymssql.connect('***','***','***','***')    # 服务器名,账户,密码,数据库名
        if connect:
            print('连接成功!')
            cursor = connect.cursor()   # 创建一个游标对象,python里的sql语句都要通过cursor来执行
            sql = "insert into Lesson(parentId,lessonType,lessonImg,lessonName,abstract,lessonFileUrl) values('{}','{}','{}','{}','{}','{}')".format(self.parentId,self.lessonType,self.lessonImg,self.lessonName,self.abstract,self.lessonFileUrl)
            cursor.execute(sql)    # 执行sql语句
            connect.commit()    # 提交
            cursor.close()
            connect.close()
'''
程序入口
'''
if __name__ == '__main__':
    # 韩雪讲给孩子的20本世界经典名著|儿童睡前故事-喜马拉雅
    # 获取课程的所有课件列表数据
    # lesson_id = '38839711'
    # lesson_id = '31966031'
    lesson_id = '238474'  # Url地址栏中的一串数字
 
    # 课程详情url,包含课程下所有的章节数据页面
    # lesson_url = '喜马拉雅-国内专业音频分享平台,随时随地,听我想听!'.format(lesson_id)
    # lesson_url = '喜马拉雅-国内专业音频分享平台,随时随地,听我想听!'.format(lesson_id)
    lesson_url = '喜马拉雅-国内专业音频分享平台,随时随地,听我想听!'.format(lesson_id)
 
    ximalaya = ximalaya()
 
    page_count = ximalaya.getPageCount(lesson_url)
 
    for count in range(1,page_count+1):
        # json数据Url
        json_url = 'Bad Request'.format(lesson_id,count)
        ximalaya.getAllLesson(json_url)

 进下面链接,学习更多python小技巧。

 https://note.youdao.com/s/bfdk7lCG

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值