记录于:2020年12月03日
用了N年的手机在经历N次掉落之后终于扛不住了,后背都张嘴了,估计再摔一次电池都能飞出来。
换了手机,由于之前有听喜马拉雅的习惯,但是手机里自带有播客软件,强迫症逼着我不能下载喜马拉雅app。
找了几天没发现喜马拉雅提供的有RSS订阅(后来想了一下,别人怎么可能提供这个功能,O(∩_∩)O哈哈~),网上也没有相关服务。
苦啊,后来还是下载了喜马拉雅app,但是实在受不了,就索性自己捣鼓一个轮子。

诉求很简单,就是想将喜马拉雅的节目搬到播客软件,用原生的app听第三方的数据,这个需求好恶心啊,还好不是产品经理提的。

好吧,开始吧。
其实写爬虫,重要的不是代码实现,而是刚开始对需要爬取的数据的分析,分析怎么爬取,怎么得到自己的数据,只要这个流程明白了。代码实现就很简单了。

在这之前需要知道什么是RSS

分析

浏览器打开喜马拉雅,找到想听的节目,比如:郭德纲

这样就有了爬取项目啦,对着这个页面开始分析,我需要标题,作者,图片三个元素,打开浏览器F12,找到这三个元素的定位,这样只需要相应的代码就能抓取信息了,这些信息就足够生成RSS中的<channel> 元素啦。

重要的是<item> 元素,播客播的就是这个元素中的信息。
其实就是要拿到页面上的 [播放列表],还是F12找到 [播放列表]的定位,有了定位,就可以抓取出这个列表,并获取这个列表中每个元素的链接,通过此链接就可以进去详情页。

点开详情页,离实现越来越近了。
我需要标题,描述,及播放源这三个元素来构成<item> 元素。
标题和描述很好获取,还是老套路F12定位就可以了,播放源就需要观察了,打开F12,观察详情页有哪些请求,看是否有某些请求得到声音源数据,
通过发现:https://www.ximalaya.com/revision/play/v1/audio 这个请求,会响应数据播放数据

这就能拿到播放数据啦。这样一来,第一页的所有播放数据都能拿到了。

由于当前是列表页,所以少不了分页,我们只需要找出当前页面是否存在下一页,且找到下一页的链接,发起请求然后重复步骤,这样就能拿到整个列表页。

有了上面的一通分析,就知道了如何去编写代码实现这个功能啦。

编码

按照上面的流程,进行编码

1.构建Channel对象

2.构建Item对象

3.生成RSS(在同级目录下会生成一个xml文件)

import requests
from bs4 import BeautifulSoup
import datetime ##################################
##### 公用对象,存储/生成 ######
################################## # rss channel
class channel(object): def __init__(self, title, author, image):
self.title = title
self.author = author
self.image = image # rss item
class item(object): def __init__(self, title, pubDate, description,enclosure):
self.title = title
self.pubDate = pubDate
self.description = description
self.enclosure = enclosure ##################################
##### 爬取数据,存储 ######
################################## headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36'
} # 开始页 - 郭德纲21年相声精选
mainUrl = "https://www.ximalaya.com/xiangsheng/9723091/"
# 播放地址
playV1 = "/revision/play/v1/audio?id={}&ptype=1"
# gmt时间格式化
GMT_FORMAT = '%a, %d %b %Y %H:%M:%S GMT'
# 网址
ximalaya = mainUrl[:mainUrl.index('/',8)]
# 所有播放项
items = [] # 构建Channel对象
def getChannel():
r = requests.get(mainUrl, headers=headers)
soup = BeautifulSoup(r.text, 'html.parser')
title = soup.find('h1', attrs={'class': 'title vA_'}).text
author = soup.find('a',attrs={'class':'nick-name gK_'}).text
image = "http:" + soup.find('img', attrs={'class': 'img vA_'})['src'].split('!')[0]
return channel(title, author, image) # 构建Item对象
def getItem(listPageUrl): print('======> 正在爬取列表页',listPageUrl)
r = requests.get(listPageUrl, headers=headers)
soup = BeautifulSoup(r.text, 'html.parser') # 获取所有播放列表项详情
soundList = soup.find_all('div', attrs={'class': 'text lF_'})
for sound in soundList:
getDetails(ximalaya + sound.a['href']) # 进入下一页
pageNext = soup.find('li', attrs={'class': 'page-next page-item WJ_'})
if pageNext:
getItem(ximalaya + pageNext.a['href']) # 进入详情页
def getDetails(detailPageUrl): print("======> 正在爬取详情页",detailPageUrl) r = requests.get(detailPageUrl, headers=headers)
soup = BeautifulSoup(r.text, 'html.parser') # 标题
title = soup.find('h1', attrs={'class': 'title-wrapper _uv'}).text
# 发布时间
pubDate = soup.find('span', attrs={'class': 'time _uv'}).text
# 声音简介
description = ""
if soup.find('article'):
description = soup.find('article').text # 播放源
playUrl = ximalaya + playV1.format(detailPageUrl.split('/')[-1]);
r = requests.get(playUrl, headers=headers)
enclosure = r.json()['data']['src'] items.append( item(title,datetime.datetime.strptime(pubDate, '%Y-%m-%d %H:%M:%S').strftime(GMT_FORMAT),description,enclosure) ) ##################################
##### 生成RSS ######
################################## def createRSS(channel): rss_text = r'<rss ' \
r' xmlns:atom="http://www.w3.org/2005/Atom" ' \
r' xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" ' \
r' version="2.0" ' \
r' encoding="UTF-8"> ' \
r' <channel>' \
r' <title>{}</title>' \
r' <itunes:author>{}</itunes:author>' \
r' <itunes:image href="{}"/>' \
.format(channel.title, channel.author, channel.image) for item in items:
rss_text += r' <item>' \
r' <title>{}</title>' \
r' <description><![CDATA[{}]]></description>' \
r' <enclosure url="{}" type="audio/mpeg"/>' \
r' </item>'\
.format(item.title, item.description, item.enclosure) rss_text += r' </channel></rss>' print('======> 生成RSS')
print(rss_text) #写入文件
with open(mainUrl.split('/')[-2]+'.xml', 'w' ,encoding='utf-8') as f:
f.write(rss_text) if __name__=="__main__": channel = getChannel()
getItem(mainUrl)
createRSS(channel)

将生成后的xml放到服务器,就可以尽情享用了。

成果

易中天老师讲的真的好

后续

本文编写于2020年12月3日,后续官方可能会对页面进行更改,请求进行更改等,会导致以上爬虫失效,所以需要知道如何进行分析,才能知道如何爬取。

以上代码只作为学习探讨,请问恶意使用!

python 爬取喜马拉雅节目生成RSS Feed的更多相关文章

  1. Python 爬取喜马拉雅音频

    一.分析音频下载相关链接地址 1. 分析专辑音频列表页面   在 PC端用 Chrome 浏览器中打开 喜马拉雅 网站,打开 Chrome开发者工具,随意打开一个音频专辑页面,Chrome开发者工具中 ...

  2. Python爬取豆瓣《复仇者联盟3》评论并生成乖萌的格鲁特

    代码地址如下:http://www.demodashi.com/demo/13257.html 1. 需求说明 本项目基于Python爬虫,爬取豆瓣电影上关于复仇者联盟3的所有影评,并保存至本地文件. ...

  3. Python爬虫|爬取喜马拉雅音频

    "GOOD Python爬虫|爬取喜马拉雅音频 喜马拉雅是知名的专业的音频分享平台,用户规模突破4.8亿,汇集了有声小说,有声读物,儿童睡前故事,相声小品等数亿条音频,成为国内发展最快.规模 ...

  4. Python中使用requests和parsel爬取喜马拉雅电台音频

    场景 喜马拉雅电台: https://www.ximalaya.com/ 找到一步小说音频,这里以下面为例 https://www.ximalaya.com/youshengshu/16411402/ ...

  5. Python爬虫:爬取喜马拉雅音频数据详解

    前言 喜马拉雅是专业的音频分享平台,汇集了有声小说,有声读物,有声书,FM电台,儿童睡前故事,相声小品,鬼故事等数亿条音频,我最喜欢听民间故事和德云社相声集,你呢? 今天带大家爬取喜马拉雅音频数据,一 ...

  6. python爬取免费优质IP归属地查询接口

    python爬取免费优质IP归属地查询接口 具体不表,我今天要做的工作就是: 需要将数据库中大量ip查询出起归属地 刚开始感觉好简单啊,毕竟只需要从百度找个免费接口然后来个python脚本跑一晚上就o ...

  7. 萌新学习Python爬取B站弹幕+R语言分词demo说明

    代码地址如下:http://www.demodashi.com/demo/11578.html 一.写在前面 之前在简书首页看到了Python爬虫的介绍,于是就想着爬取B站弹幕并绘制词云,因此有了这样 ...

  8. Python爬取招聘信息,并且存储到MySQL数据库中

    前面一篇文章主要讲述,如何通过Python爬取招聘信息,且爬取的日期为前一天的,同时将爬取的内容保存到数据库中:这篇文章主要讲述如何将python文件压缩成exe可执行文件,供后面的操作. 这系列文章 ...

  9. python 爬取微信好友列表和个性签名,绘制个性签名云图

    python爬取微信好友列表和个性签名,绘制个性签名云图 1. 简要介绍 本次实验主要用到下面几个库 : 1)itchat---用于微信接口,实现生成QR码,用于微信扫描登陆 2)re(正则化)--- ...

随机推荐

  1. 300万运算/秒 :VoltDB在电信行业基准测试上可线性扩展性能

    01 总 体 概 述 VoltDB受到全球电信软件解决方案提供商的信赖,后者将其作为首选内存数据库来驱动他们部署在全球100多家运营商处的任务关键型应用.VoltDB受到青睐的原因在于其性能和功能不仅 ...

  2. 《Clojure编程》笔记 第1章 进入Clojure仙境

    目录 背景简述 第1章 进入Clojure仙境 1.1 基础概念 1.2 常用的一些符号 背景简述 本人是一个自学一年Java的小菜鸡,理论上跟大多数新手的水平差不多,但我入职的新公司是要求转Cloj ...

  3. PHP获取文件拓展名的方法

    1.用strrchar()函数,查找字符串在另一字符串中最后出现的位置,并返回该位置到字符串最后的所有字符(返回结果包括点).即返回拓展名前  点  到结尾的字符,即为扩展名.注意与strchar() ...

  4. think PHP5.1使用时 session重定向丢失问题

    查了很多资料,也看了redirect底层代码,具体来说,还是多个用的地方不太对.做个笔记防忘记: 遇重定向后丢失session时: 1.php.ini配置文件,不要自动启动,默认是0,session. ...

  5. Vue的生命周期--代码片段

    Vue 实例有一个完整的生命周期,也就是从开始创建. 初始化数据. 编译模板. 挂载 Dom. 渲染→更新→渲染. 销毁等一系列过程,我们称这是 Vue 的生命周期.通俗说就是 Vue 实例从创建到销 ...

  6. Vue常用性能优化

    Vue常用性能优化 Vue常用的一些优化方式,主要是在构建项目过程需要注意的方面. 编码优化 避免响应所有数据 不要将所有的数据都放到data中,data中的数据都会增加getter和setter,并 ...

  7. ExecutorService的invokeAny方法注意

    package com.msxf.datasource.thirdpart.service.extface; import java.util.HashSet; import java.util.Li ...

  8. Innodb表空间迁移过程

    1.大致流程 将a实例的表的数据迁移到b实例上. 1.在目标实例b上创建一个相同的表 2.在目标库b上执行ALTER TABLE t DISCARD TABLESPACE; 3.在源库a上执行FLUS ...

  9. ceph的pg的分布的快速查看

    前言 本篇的内容实际上是另外一篇文章的字篇章,在另外一篇文章当中,将会对crush的分布的调整的做一次总结,用比较简单的方式来展示各种crush的区别 在做这个工作过程中,为了更好的能展示出效果,就有 ...

  10. 删除osd的正确方式

    在ceph的集群当中关于节点的替换的问题,一直按照以前的方式进行的处理,处理的步骤如下: 停止osd进程 /etc/init.d/ceph stop osd.0 这一步是停止osd的进程,让其他的os ...