前段时间在公众号《Python爱好者社区》看到这篇文章:
https://mp.weixin.qq.com/s?__biz=MzI5NDY1MjQzNA==&mid=2247489917&idx=5&sn=4e5aa7626d480368c3edaa543a474b2f&chksm=ec5ec600db294f16a7d490f6a24e8296acea2069903a8749faafd8c4212872d4a6c6b3392454&mpshare=1&scene=1&srcid=0428PUNAL4ubKu9LSuT9YVft&sharer_sharetime=1588077632124&sharer_shareid=ac3ae07c07d7eeaa77ecab49b86cc99e&key=b057c75bc90186ba1d681e6a3712efacfd6535366253fadb64c9750f9936979c2542da3451446b54c51a2cf4e6c1f0c093045a3dda0b93923a066ee13f55d37c804ac434662b53cdf4168ec1942e22aa&ascene=1&uin=MjU2NzUxMzExMQ%3D%3D&devicetype=Windows+10+x64&version=62090070&lang=zh_CN&exportkey=A6XkASyz8tDXvDktPa1WOgY%3D&pass_ticket=ffVVHy6oiS17%2BgZMUytcIopIS5vv%2FOPxyRRLXt21%2FS1spi6t%2BQw%2FjBmA4F3kbWKg
觉得挺有意思,就和小伙伴一起写了一下当作学习python的练习。
语音合成
科大讯飞提供的语音合成有限制次数,只能免费调用500次,而百度提供的语音合成不限次数,但QFS限额为5,即一秒钟最多调用5次。于是果断选择用百度语音合成API。
注册一个百度账户,登录到百度AI智能平台,创建一个应用。
记录AppID、API Key、Secret Key,在调用API的时候会用到。
具体调用代码参考:https://ai.baidu.com/ai-doc/SPEECH/Gk4nlz8tc
result = client.synthesis('你好百度', 'zh', 1, {
'vol': 5,
})
# 识别正确返回语音二进制 错误则返回dict 参照下面错误码
if not isinstance(result, dict):
with open('auido.mp3', 'wb') as f:
f.write(result)
'zh'应该是中文的意思;'vol'选项为选择语音类型(1为普通男声,2为普通女声,3为度逍遥,4为度丫丫)。
此外,还可以通过参数调节音量、语调、语速等。
获取小说内容
小说内容从笔趣阁获取,原因是免费且没有反爬。首先选择一本小说,找到其网址。
这里以《我真没想重生啊》为例,其网址是http://www.biquge.info/69_69102/。
观察网站源代码,发现章节信息为:
因此从dd标签中获取章节名、章节链接。
def getChapters(self):
"""获取所有章节信息(章节名、章节url)
input:
output:"""
r=requests.get(self.main_url)
r.encoding='utf-8'
soup = BeautifulSoup(r.text,'html.parser')
#每个章节
cpts=soup.findAll('dd')
num=1
for cpt in tqdm(cpts):
if str(num) not in cpt.text:
continue
#章节名
self.chapters_name[num]=cpt.text
#章节url
url=cpt.find('a')
self.chapters_url[num]=url.get('href').split('.')[0]
num+=1
然后使用BeautifulSoup.find(attrs={"id":"content"})来获取具体章节内容。
def getContents(self,chapter):
"""获取指定章节内容"""
r=requests.get(self.main_url+self.chapters_url[chapter]+'.html')
r.encoding='utf-8'
soup=BeautifulSoup(r.text,'html.parser')
content=soup.find(attrs={"id":"content"})
soup_text = BeautifulSoup(str(content), 'lxml')
text=soup_text.div.text.replace('\xa0','')
self.chapters_contens[chapter]=text
播放语音
使用pygame库,做法与上述文章一致。
def play(self,chapter):
"""播放指定章节内容"""
#如果没有下载章节内容则先下载
if chapter not in self.chapters_contens:
self.getContents(chapter)
#调用百度语音合成API,把文字转成语音
result = self.client.synthesis(self.chapters_contens[chapter][:1024], 'zh', 1, {"per": 4})
if isinstance(result, dict):
print('合成失败')
#播放语音
pygame_mixer = pygame.mixer
pygame_mixer.init(frequency=16000)
byte_obj = BytesIO()
byte_obj.write(result)
byte_obj.seek(0, 0)
pygame_mixer.music.load(byte_obj)
pygame_mixer.music.play()
while pygame_mixer.music.get_busy():
time.sleep(0.1)
pygame_mixer.stop()
最终代码
from bs4 import BeautifulSoup
import requests
from aip import AipSpeech
from tqdm import tqdm
import time
import pygame
from io import BytesIO
class listenWebNovel():
def __init__(self):
"""初始化"""
self.main_url='http://www.biquge.info/69_69102/'
self.chapters_name=dict()
self.chapters_url=dict()
self.chapters_contens=dict()
self.APP_ID=''#需改为个人APP_ID
self.API_KEY=''#需改为个人API_KEY
self.SECRET_KEY=''#需改为个人SECRET_KEY
self.client = AipSpeech(self.APP_ID,self.API_KEY,self.SECRET_KEY)
self.getChapters()
def getChapters(self):
"""获取所有章节信息(章节名、章节url)
input:
output:"""
r=requests.get(self.main_url)
r.encoding='utf-8'
soup = BeautifulSoup(r.text,'html.parser')
#每个章节
cpts=soup.findAll('dd')
num=1
for cpt in tqdm(cpts):
if str(num) not in cpt.text:
continue
#章节名
self.chapters_name[num]=cpt.text
#章节url
url=cpt.find('a')
self.chapters_url[num]=url.get('href').split('.')[0]
num+=1
def getContents(self,chapter):
"""获取指定章节内容"""
r=requests.get(self.main_url+self.chapters_url[chapter]+'.html')
r.encoding='utf-8'
soup=BeautifulSoup(r.text,'html.parser')
content=soup.find(attrs={"id":"content"})
soup_text = BeautifulSoup(str(content), 'lxml')
text=soup_text.div.text.replace('\xa0','')
self.chapters_contens[chapter]=text
def play(self,chapter):
"""播放指定章节内容"""
#如果没有下载章节内容则先下载
if chapter not in self.chapters_contens:
self.getContents(chapter)
#调用百度语音合成API,把文字转成语音
result = self.client.synthesis(self.chapters_contens[chapter][:1024], 'zh', 1, {"per": 4})
if isinstance(result, dict):
print('合成失败')
#播放语音
pygame_mixer = pygame.mixer
pygame_mixer.init(frequency=16000)
byte_obj = BytesIO()
byte_obj.write(result)
byte_obj.seek(0, 0)
pygame_mixer.music.load(byte_obj)
pygame_mixer.music.play()
while pygame_mixer.music.get_busy():
time.sleep(0.1)
pygame_mixer.stop()
if __name__ == '__main__':
#实例化
lw=listenWebNovel()
#播放第1章
lw.play(1)