精华内容
下载资源
问答
  • tts语音地址 千次阅读
    2020-06-07 18:46:52
    https://tts.baidu.com/text2audio?cuid=baike&lan=ZH&ctp=1&pdt=301&vol=9&rate=32&per=6&tex=试试这
    

    可以通过改变per的参数来改变音色
    把改变lan的值修改成EN可以设置成英文

    更多相关内容
  • 百度朗读引擎源码
  • 易语言TTS引擎语音朗读源码系统结构:回调函数,列举语音库,设置语音库,设置语速,设置声音大小,文本到语音, ======窗口程序集1 || ||------__启动窗口_创建完毕 || ||------回调函数 || || =====
  • TTS引擎语音朗读.rar

    2020-04-05 15:13:55
    TTS引擎语音朗读.rar TTS引擎语音朗读.rar TTS引擎语音朗读.rar TTS引擎语音朗读.rar TTS引擎语音朗读.rar TTS引擎语音朗读.rar
  • 完整版软件朗读源码.rar
  • 简单的语音朗读代码

    2015-01-09 14:46:29
    一个很简单的语音朗读代码,输入要朗读的文本,点击按钮就可以进行语音朗读
  • Python喜马拉雅有声小说音频文件爬虫

    千次阅读 热门讨论 2021-03-18 08:21:38
    今天爬取的是喜马拉雅有声小说。 ... 分析操作开始: ...我们尝试访问一下该接口的url,将url复制到浏览器打开。 发起访问后,跳转出了一个保存文件到本地的界面。 我们选择保存,发现多了一个类型

    今天爬取的是喜马拉雅有声小说。


    在这里插入图片描述

    目标网址:https://www.ximalaya.com/youshengshu/


    分析操作开始:

    首先在喜马拉雅有声小说页面,播放任意音频。

    当播放音频时,打开抓包工具(加载网页后打开抓包工具,发现没有抓到数据包,刷新网页就行),这边选择媒体Media,一般的视频,音频文件都会在这里被抓取到。
    在这里插入图片描述
    下图就是抓到的音频文件。在这里插入图片描述
    我们尝试访问一下该接口的url,将url复制到浏览器打开。在这里插入图片描述
    在这里插入图片描述
    发起访问后,跳转出了一个保存文件到本地的界面。
    在这里插入图片描述
    我们选择保存,发现多了一个类型为M4A的文件。
    在这里插入图片描述
    尝试播放,发现的确是之前在喜马拉雅界面中播放的有声小说音频。在这里插入图片描述
    通过上述操作,我们明白访问该url可直接得到相应的音频文件。

    现在开始分析这个url

    “https://aod.cos.tx.xmcdn.com/group58/M09/4B/2B/wKgLc1zJeDKgmWlwADxJRm7KRfE151.m4a”

    一看就可以看到 这个url上全是各种加密在这里插入图片描述
    如果我们直接去做解密的话,这是不合适的,因为同样我们也不知道它是否真的是加密了,有可能他只是在26个英文字母和0到9个阿拉伯数字随机组成呢。

    咱们不确定它是哪种加密方式,那么怎么办呢?

    我们先复制他

    然后在所有抓到的包中 去寻找

    在这里插入图片描述

    搜索后我们发现 出现了一个audio音频接口
    在这里插入图片描述

    我们双击后发现控制台返回的一大串数据里面数据里面有一个叫src的,就有我们刚刚看到的音频数据。

    也就是说 音频是这样生成的 并不是一个加密在这里插入图片描述

    我们找到它的url地址以后 去访问

    在这里插入图片描述
    访问后发现他是类似于一个字典一样的储存,并且包含着刚刚的src数据,就是有声小说音频播放的地址。
    在这里插入图片描述
    整理一下思路,也就是我们可以请求这个接口然后得到一大串数据,我们在得到的一大串数据中 再提取src链接,也就是音频地址。在这里插入图片描述
    准备开始怼代码了,我们先创建一个py文件 和 一个存放音频数据的文件夹。
    在这里插入图片描述
    常规的基础爬虫请求,请求方式为get请求。
    在这里插入图片描述
    请求结果如下,控制台打印的数据为两个字典嵌套。
    在这里插入图片描述
    通过简单的处理,再次打印数据。在这里插入图片描述
    在这里插入图片描述
    成功打印出音频文件的地址!!

    这个时候我们就已经可以存储文件了,因为地址已经拿到了,但是存储文件 文件名是必不可少的,咱们回忆之前下载的音频文件。
    在这里插入图片描述
    简单思索一下 我们其实可以直接将src这个网址的末尾,作为音频文件的文件名。
    在这里插入图片描述
    通过基础的字符串切割,得到音频文件名字。
    在这里插入图片描述
    在这里插入图片描述
    再次进行常规爬虫操作,对srd的地址发起请求。
    在这里插入图片描述
    得到16进制的,字节数据。
    在这里插入图片描述
    最后只需要进行文件存储,就可以将音频文件保存到本地了。
    在这里插入图片描述
    这个时候一个音频文件的操作已经完成。

    但是!!!爬虫的优势是什么????是大批量的下载。

    想要大批量的下载,就必须使得url变成动态url。

    所以我们再次回到开头,选取另一个音频专辑的url对比参数。看看能不能发现规律。

    重复最开始的操作播放音频,通过抓包工具抓到音频文件的接口,复制id进行搜索。
    在这里插入图片描述

    拿到url,进行比对。
    在这里插入图片描述

    比对发现 只是id不一样。那我们可以进行url拼接使得url可以动态变化。

    在这里插入图片描述
    因为我们知道了更换id就可以使得下载音频文件的url变化,下载不同的音频文件,只需要更换url的id,所以我们想办法在专栏下抓取音频文件的id。

    静态数据永远比动态数据要好拿一点,我们先看看静态页面上有没有我们想要的数据。
    在这里插入图片描述
    果然不出我们所料,id就藏在这些静态数据当中。

    进行简单爬虫操作,获得页面源码。
    在这里插入图片描述

    上图的url错误了,应该是某个有声小说专辑的url,而不是整个有声小说的url。正确url应该为“https://www.ximalaya.com/youshengshu/40942749/”)

    为了保证数据的准确性,我们通过浏览器,截取一段页面源码,然后在pycharm打印台搜索,测试是否拿到了真实的页面源码。
    在这里插入图片描述

    在获取到的数据中搜索,成功搜索到了匹配的内容,证明我们的确获得到了 页面的真实源码。
    在这里插入图片描述
    抓取id,用它的类选择器。
    在这里插入图片描述

    完美!成功打印出之前所需要的id。
    在这里插入图片描述
    这时仔细的同学应该已经发现,每个章节的音频名字就在id的旁边。
    我们顺手再降名字也一起抓取。
    在这里插入图片描述

    在这里插入图片描述

    参数都拿到了,我们将之前保存音频的代码封装成一个函数。在这里插入图片描述
    然后将刚刚拿到的,name和id传过去。为了保证准确性中途可以多次打印来测试。
    在这里插入图片描述
    这里整个喜马拉雅爬虫算是完工了,输入这里直接input的专题的url就好了,但是小编发现,输入url后必须敲两个空格再回车,不然会直接从浏览器访问网址了。
    在这里插入图片描述
    因为多输入了两个空格,我们只需要进行简单的字符串操作,再将url传入之前函数里面,我们的爬虫就算是完成了!!!!!!
    在这里插入图片描述

    在这里插入图片描述

    下面附上源码:

    # -*- endoding: utf-8 -*-
    # @ModuleName:喜马拉雅
    # @Function(功能):
    # @Author : 苏穆冰白月晨
    # @Time : 2021/3/17 9:52\
    
    """喜马拉雅音频爬虫"""
    import requests
    from pyquery import PyQuery as pq  #局部搜索
    
    
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36'
    }
    
    
    def request_mp3(id, name):
        """保存音频文件"""
        url = "https://www.ximalaya.com/revision/play/v1/audio?id={}&ptype=1".format(id)
        print(url)
    
        response = requests.get(url,headers=headers).json()
        data = response['data']['src']
    
    
        mp3 = requests.get(data,headers=headers)
        f = open('./音频文件/' +name, 'ab' ) #文件路径  文件读写方式 a文件追加(不存在新建) b进制文件
        f.write(mp3.content)
        f.close()
    
    
    
    def main(urls):
        response = requests.get(urls,headers=headers).text
        doc = pq(response)
    
        """<a title="神棍下山记 001 如此师徒(免费收听,福利多多,订阅不迷路)" href="/youshengshu/40942749/328847758"><span class="title lF_">神棍下山记 001 如此师徒(免费收听,福利多多,订阅不迷路)</span></a>"""
    
        text1 = doc(".text.lF_ a").items()
        for i in  text1:
            id1 = i.attr("href").split('/')[3]
            name = i.attr("title").split('(')[0]
            print(id1)
            print(name)
            request_mp3(id1, name)
    
    
    if __name__ == '__main__':
        urls1 = input(r"请输入专辑的url: ").split(" ")
        urls = urls1[0]
        main(urls)
    

    如果对您有帮助可以的话关注一下公众号:Python网络小蜘蛛

    展开全文
  • # readtxt_by_SAPI(i) #可以选择其他朗读引擎 # readtxt_by_pyttsx3(i) import paqu_sina readnews ( paqu_sina . newtitlelist ( ) ) ) 爬取新浪国际新闻版块最新消息 将该脚本命名为paqu_sina.py ...
    1. 调用讯飞API将文字转为语音文件
    2. 爬取新浪国际新闻版块最新消息保存到xlsx
    3. 讯飞API 文字有限制
    4. python程序打包成exe
    5. 语音即时播放

    定制新闻朗读助手(调用科大讯飞API)

    调用讯飞API将文字转为语音文件

    #-*- coding: utf-8 -*-
    import pyaudio
    import wave
    import os
    
        
    def play_xunfei(wavfilename):
    
        CHUNK = 1024
        # 从目录中读取语音
    #    wf = wave.open('mic4.wav', 'rb')
        wf = wave.open(wavfilename, 'rb')
        # read data
        data = wf.readframes(CHUNK)
        # 创建播放器
        p = pyaudio.PyAudio()
        # 获得语音文件的各个参数
        FORMAT = p.get_format_from_width(wf.getsampwidth())
        CHANNELS = wf.getnchannels()
        RATE = wf.getframerate()
    #    print('FORMAT: {} \nCHANNELS: {} \nRATE: {}'.format(FORMAT, CHANNELS, RATE))
        # 打开音频流, output=True表示音频输出
        stream = p.open(format=FORMAT,
                        channels=CHANNELS,
                        rate=RATE,
                        frames_per_buffer=CHUNK,
                        output=True)
        # play stream (3) 按照1024的块读取音频数据到音频流,并播放
        while len(data) > 0:
            stream.write(data)
            data = wf.readframes(CHUNK)
            
            
            
    import requests
    import time
    import hashlib
    import base64
    #  合成webapi接口地址
    URL = "http://api.xfyun.cn/v1/service/v1/tts"
    #  音频编码(raw合成的音频格式pcm、wav,lame合成的音频格式MP3)
    AUE = "raw"
    #  应用APPID(必须为webapi类型应用,并开通语音合成服务,参考帖子如何创建一个webapi应用:http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=36481
    APPID = "5ce265c9"
    #  接口密钥(webapi类型应用开通合成服务后,控制台--我的应用---语音合成---相应服务的apikey)
    API_KEY = "dedd145d73ca0e1fd5e70a77f38365a1"
    
    # 组装http请求头
    def getHeader():
        curTime = str(int(time.time()))#1558401768
        # ttp=ssml
        param = "{\"aue\":\"" + AUE + "\",\"auf\":\"audio/L16;rate=16000\",\"voice_name\":\"xiaoyan\",\"engine_type\":\"intp65\"}"
    #    print("param:{}".format(param))
    
        paramBase64 = str(base64.b64encode(param.encode('utf-8')), 'utf-8')
    #    print("x_param:{}".format(paramBase64))
    
        m2 = hashlib.md5()
        m2.update((API_KEY + curTime + paramBase64).encode('utf-8'))
    
        checkSum = m2.hexdigest()
    #    print('checkSum:{}'.format(checkSum))
    
        header = {
            'X-CurTime': curTime,
            'X-Param': paramBase64,
            'X-Appid': APPID,
            'X-CheckSum': checkSum,
            'X-Real-Ip': '127.0.0.1',
            'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
        }
    #    print(header)
        return header
    
    
    def getBody(text):
        data = {'text': text}
        return data
    
    
    def writeFile(file, content):
        with open(file, 'wb') as f:
            f.write(content)
        f.close()
    
    #  待合成文本内容
    #with open('t2v_test.txt','r',encoding='utf-8') as f:
    #    line = f.read()
    #r = requests.post(URL, headers=getHeader(), data=getBody("内容"))
    #待合成文本,使用utf-8编码,需urlencode,长度小于1000字节 一个汉字两个字节
    def readtxt_by_xunfei(readcontent):
        print('讯飞正在支持朗读助手')
        r = requests.post(URL, headers=getHeader(), data=getBody(readcontent))
        
        contentType = r.headers['Content-Type']
        if contentType == "audio/mpeg":
            sid = r.headers['sid']
            if AUE == "raw":
        #        print(r.content)
        #   合成音频格式为pcm、wav并保存在audio目录下
    #            writeFile("audio/" + sid + ".wav", r.content)
                writeFile(sid + ".wav", r.content)
            else:
        #        print(r.content)
        #   合成音频格式为mp3并保存在audio目录下
                writeFile("audio/" + "xiaoyan" + ".mp3", r.content)
            wavfilename=sid + ".wav"
            
            print("success, sid = " + sid)
            play_xunfei(wavfilename)
            os.remove(wavfilename)
        else:
        #   错误码链接:https://www.xfyun.cn/document/error-code (code返回错误码时必看)
            print(r.text)
    def readtxt_by_SAPI(content):
        print('SAPI正在支持朗读助手')
        import win32com.client
        speaker = win32com.client.Dispatch("SAPI.SpVoice")
        speaker.Speak(content)  
        
    def readtxt_by_pyttsx3(content):
        print('pyttsx3正在支持朗读助手')
        import pyttsx3
        engine = pyttsx3.init()
        volume=engine.getProperty('volume')
        engine.setProperty('volume', volume + 0.25)
        engine.say(content)
        engine.runAndWait()
        engine.stop()   
    def readnews(titlelist):
        for i in titlelist:
            readtxt_by_xunfei(i)
    #        readtxt_by_SAPI(i) #可以选择其他朗读引擎
    #        readtxt_by_pyttsx3(i)
    import paqu_sina    
    readnews(paqu_sina.newtitlelist()))
    

    爬取新浪国际新闻版块最新消息

    将该脚本命名为paqu_sina.py

    import requests
    from bs4 import BeautifulSoup
    import time
    import json
    import re
    import pandas
    import sys
    if sys.getdefaultencoding() != 'utf-8':
        reload(sys)
        sys.setdefaultencoding('utf-8')
    def getnewcontent(url):
        result = {}
        info = requests.get(url)
        info.encoding = 'utf-8'
        html = BeautifulSoup(info.text, 'html.parser')
        result['title'] = html.select('.second-title')[0].text
        result['date'] = html.select('.date')[0].text
        result['source'] = html.select('.source')[0].text
        article = []
        for v in html.select('.article p')[:-1]:
            article.append(v.text.strip())
        author_info = '\n'.join(article)
        result['content'] = author_info
        result['author'] = html.select('.show_author')[0].text.lstrip('责任编辑:')
        newsid = url.split('/')[-1].rstrip('.shtml').lstrip('doc-i')
        commenturl = 'http://comment5.news.sina.com.cn/page/info?version=1&format=json&channel=gj&newsid=comos-{}&group=undefined&compress=0&ie=utf-8&oe=utf-8&page=1&page_size=3&t_size=3&h_size=3&thread=1&callback=jsonp_1536041889769&_=1536041889769'
        comments = requests.get(commenturl.format(newsid))
        regex = re.compile(r'(.*?)\(')#去除左边特殊符号
        tmp = comments.text.lstrip(regex.search(comments.text).group())
        jd = json.loads(tmp.rstrip(')'))
        result['comment'] = jd['result']['count']['total'] #获取评论数
        return result
    def getnewslink(url):
        test = requests.get(url)
        test2 =  test.text.lstrip('newsloadercallback(')
        jd = json.loads(test2.rstrip(')\n'))
        content = []
        for v in jd['result']['data']:
            content.append(getnewcontent(v['url']))
        return content
    def getdata():
        url = 'https://interface.sina.cn/news/get_news_by_channel_new_v2018.d.html?cat_1=51923&show_num=27&level=1,2&page={}&callback=newsloadercallback&_=1536044408917'
        weibo_info = []
        for i in range(1,3):
            newsurl = url.format(i)#字符串格式化用i替换{}
            weibo_info.extend(getnewslink(newsurl))
        return weibo_info
    
        
    def newtitlelist():
    	print('正在载入新闻内容,请稍后。。。')
        new_info = getdata()
        #df = pandas.DataFrame(new_info)
        #df #去除全部 df.head() 取出5行 head(n)  n行
        #将文件下载为excel表格 
        #df.title
        #df.to_excel('weibonews.xlsx')
        titlelist=[]
        for i in new_info:
            titlelist.extend([i['title']])
        return titlelist
       
    

    安装pyinstaller打包exe

    1、安装pyinstaller(需要先安装pip)、再:pip install pyinstaller

    2、定位到pyinstaller.exe所在文件夹(一般再python下的“scripts”文件夹下)

    (温馨提示鼠标吧文件拖进CMD里面)

    3、再添加上你要转换的文件地址(两者之间有空格)
    在这里插入图片描述
    pyinstaller.exe后面如果加上-F就是打包为一个exe文件(文件会比较大),如果不加就会有很多库文件;加上-w就是打包为没有cmd窗口的exe,不加运行时就会出现cmd窗口。(加不加凭个人喜好)
    例如
    被打包的文件: xx.py, 人人皆知.
    打包的命令: pyinstaller -D xx.py
    打包的console提示: 见随后的引述块
    打包发布exe时的纪律(注意事项):
    很简单的py脚本. Simple is better than complex. 应该遵守Python的规则.
    所以在打包为exe时, 应该尽量减少没有必要的python包的导入. 否则吃的太胖
    可以运行的exe文件位于: dist 目录下, 而不是build目录下的.

    运行
    在这里插入图片描述

    离线可选择其他语音合成引擎

    pyttsx3模块初探及实战项目

    import pyttsx3
    engine = pyttsx3.init() # object creation
    
    """ RATE"""
    rate = engine.getProperty('rate')   # getting details of current speaking rate
    print (rate)                        #printing current voice rate
    engine.setProperty('rate', 125)     # setting up new voice rate
    
    
    """VOLUME"""
    volume = engine.getProperty('volume')   #getting to know current volume level (min=0 and max=1)
    print (volume)                          #printing current volume level
    engine.setProperty('volume',1.0)    # setting up volume level  between 0 and 1
    
    """VOICE"""
    voices = engine.getProperty('voices')       #getting details of current voice
    #engine.setProperty('voice', voices[0].id)  #changing index, changes voices. o for male
    engine.setProperty('voice', voices[1].id)   #changing index, changes voices. 1 for female
    
    engine.say("Hello World!")
    engine.say('My current speaking rate is ' + str(rate))
    engine.runAndWait()
    engine.stop()
    
    import win32com.client
    #用 微软这个服务器 朗读中文小说
    speaker = win32com.client.Dispatch("SAPI.SpVoice")
    with open('t2v_test.txt','r',encoding='utf-8') as f:
        line = f.read()
        speaker = win32com.client.Dispatch("SAPI.SpVoice")
        speaker.Speak(line)
    
    展开全文
  • 它可以在各种网站上工作,包括新闻网站,博客,同人小说,出版物,教科书,学校和班级网站,在线大学和课程资料。 “朗读”针对的是那些喜欢听内容而不是阅读的用户,阅读障碍者或其他学习障碍者,学习阅读的儿童...
  • 网页中文本朗读功能开发实现分享前几天完成了一个需求,在网页中完成鼠标指向哪里,就用语音读出所指的文本。如果是按钮、链接、文本输入框,则还还要给出是什么的提醒。同时针对大段的文本,不能整段的去读,要按照...

    网页中文本朗读功能开发实现分享

    前几天完成了一个需求,在网页中完成鼠标指向哪里,就用语音读出所指的文本。如果是按钮、链接、文本输入框,则还还要给出是什么的提醒。同时针对大段的文本,不能整段的去读,要按照标点符号进行断句处理。

    重点当然就是先获取到当前标签上的文本,再把文本转化成语音即可。

    标签朗读

    这个很简单了,只用根据当前是什么标签,给出提示即可。

    // 标签朗读文本

    var tagTextConfig = {

    'a': '链接',

    'input[text]': '文本输入框',

    'input[password]': '密码输入框',

    'button': '按钮',

    'img': '图片'

    };

    还有需要朗读的标签,继续再添加即可。

    然后根据标签,返回前缀文本即可。

    /**

    * 获取标签朗读文本

    * @param {HTMLElement} el 要处理的HTMLElement

    * @returns {String} 朗读文本

    */

    function getTagText(el) {

    if (!el) return '';

    var tagName = el.tagName.toLowerCase();

    // 处理input等多属性元素

    switch (tagName) {

    case 'input':

    tagName += '[' + el.type + ']';

    break;

    default:

    break;

    }

    // 标签的功能提醒和作用应该有间隔,因此在最后加入一个空格

    return (tagTextConfig[tagName] || '') + ' ';

    }

    获取完整的朗读文本就更简单了,先取标签的功能提醒,再取标签的文本即可。

    文本内容优先取 title 其次 alt 最后 innerText。

    /**

    * 获取完整朗读文本

    * @param {HTMLElement} el 要处理的HTMLElement

    * @returns {String} 朗读文本

    */

    function getText(el) {

    if (!el) return '';

    return getTagText(el) + (el.title || el.alt || el.innerText || '');

    }

    这样就可以获取到一个标签的功能提醒和内容的全部带朗读文本了。

    正文分隔

    接下来要处理的就是正文分隔了,在这个过程中,踩了不少坑,走了不少弯路,好好记录一下。

    首先准备了正文分隔的配置:

    // 正文拆分配置

    var splitConfig = {

    // 内容分段标签名称

    unitTag: 'p',

    // 正文中分隔正则表达式

    splitReg: /[,;,;。]/g,

    // 包裹标签名

    wrapTag: 'label',

    // 包裹标签类名

    wrapCls: 'speak-lable',

    // 高亮样式名和样式

    hightlightCls: 'speak-help-hightlight',

    hightStyle: 'background: #000!important; color: #fff!important'

    };

    最开始想的就是直接按照正文中的分隔标点符号进行分隔就好了呀。

    想法如下:

    获取段落全部文本

    使用 split(分隔正则表达式) 方法将正文按照标点符号分隔成小段

    每个小段用标签包裹放回去即可

    然而理想很丰满,现实很骨感。

    两个大坑如下:

    split 方法进行分隔,分隔后分隔字符就丢了,也就是说把原文的一些标点符号给弄丢了。

    如果段落内还存在其他标签,而这个标签内部也正好存在待分隔的标点符号,那包裹分段标签时直接破换了原标签的完整性。

    关于第一个问题,丢失标点的符号,考虑过逐个标点来进行和替换 split 分隔方法为逐个字符循环来做。

    前者问题是原本一次完成的工作分成了多次,效率太低。第二种感觉效率更低了,分隔本来是很稀疏的,但是却要变成逐个字符出判断处理,更关键的是,分隔标点的位置要插入包裹标签,会导致字符串长度变化,还要处理下标索引。代码是机器跑的,或许不会觉得烦,但是我真的觉得好烦。如果这么干,或许以后哪个AI或者同事看到这样的代码,说不定会说“这真是个傻xxxx”。

    第二个问题想过很多办法来补救,如先使用正则匹配捕获内容中成对的标签,对标签内部的分隔先处理一遍,然后再处理整个的。

    想不明白问题二的,可参考一下待分隔的段落:

    这是一段测试文本,这里有个链接。您好,可以点击此处进行跳转还有其他内容其他内容容其他内容容其他内容,容其他内容。

    如先使用/)(.+?))/g 正则,依次捕获段落内被标签包裹的内容,对标签内部的内容先处理。

    但是问题又来了,这么处理的都是字符串,在js中都是基本类型,这些操作进行的时候都是在复制的基础上进行的,要修改到原字符串里去,还得记录下原本的开始结束位置,再将新的插进去。繁,还是繁,但是已经比之前逐个字符去遍历的好,正则捕获中本来就有了匹配的索引,直接用即可,还能接受。

    但是这只是处理了段落内部标签的问题,段落内肯定还有很多文本是没有处理呢,怎么办?

    正则匹配到了只是段落内标签的结果啊,外面的没有啊。哦,对,有匹配到的索引,上次匹配到的位置加上上次处理的长度,就是一段直接文本的开始。下一次匹配到的索引-1就是这段直接文本的结束。这只是匹配过程中的,还有首尾要单独处理。又回到烦的老路上去了。。。

    这么烦,一个段落分隔能这么繁琐,我不信!

    突然想到了,有文本节点这么个东西,删繁就简嘛,正则先到边上去,直接处理段落的所有节点不就行了。

    文本节点则分隔直接包裹,标签节点则对内容进行包裹,这种情况下处理的直接是dom,更省事。

    文本节点里放标签?这是在开玩笑么,是也不是。文本节点里确实只能放文本,但是我把标签直接放进去,它会自动转义,那最后再替换出来不就行了。

    好了,方案终于有了,而且这个方案逻辑多简单,代码逻辑自然也不会烦。

    /**

    * 正文内容分段处理

    * @param {jQueryObject/HTMLElement/String} $content 要处理的正文jQ对象或HTMLElement或其对应选择器

    */

    function splitConent($content) {

    $content = $($content);

    $content.find(splitConfig.unitTag).each(function (index, item) {

    var $item = $(item),

    text = $.trim($item.text());

    if (!text) return;

    var nodes = $item[0].childNodes;

    $.each(nodes, function (i, node) {

    switch (node.nodeType) {

    case 3:

    // text 节点

    // 由于是文本节点,标签被转义了,后续再转回来

    node.data = '' +

    node.data.replace(splitConfig.splitReg, '' + splitConfig.wrapTag + '>$&') +

    '' + splitConfig.wrapTag + '>';

    break;

    case 1:

    // 元素节点

    var innerHtml = node.innerHTML,

    start = '',

    end = '';

    // 如果内部还有直接标签,先去掉

    var startResult = /^/.exec(innerHtml);

    if (startResult) {

    start = startResult[0];

    innerHtml = innerHtml.substr(start.length);

    }

    var endResult = /$/.exec(innerHtml);

    if (endResult) {

    end = endResult[0];

    innerHtml = innerHtml.substring(0, endResult.index);

    }

    // 更新内部内容

    node.innerHTML = start +

    '' +

    innerHtml.replace(splitConfig.splitReg, '' + splitConfig.wrapTag + '>$&') +

    '' + splitConfig.wrapTag + '>' +

    end;

    break;

    default:

    break;

    }

    });

    // 处理文本节点中被转义的html标签

    $item[0].innerHTML = $item[0].innerHTML

    .replace(new RegExp('<' + splitConfig.wrapTag + '>', 'g'), '')

    .replace(new RegExp('</' + splitConfig.wrapTag + '>', 'g'), '' + splitConfig.wrapTag + '>');

    $item.find(splitConfig.wrapTag).addClass(splitConfig.wrapCls);

    });

    }

    上面代码中最后对文本节点中被转义的包裹标签替换似乎有点麻烦,但是没办法,ES5之前JavaScript并不支持正则的后行断言(也就是正则表达式中“后顾”)。所以没办法对包裹标签前后的 < 和 > 进行精准替换,只能连同标签名一起替换。

    事件处理

    在上面完成了文本获取和段落分隔,下面要做的就是鼠标移动上去时获取文本触发朗读即可,移开时停止朗读即可。

    鼠标移动,只读一次,基于这两点原因,使用 mouseenter 和 mouseleave 事件来完成。

    原因:

    不冒泡,不会触发父元素的再次朗读

    不重复触发,一个元素内移动时不会重复触发。

    /**

    * 在页面上写入高亮样式

    */

    function createStyle() {

    if (document.getElementById('speak-light-style')) return;

    var style = document.createElement('style');

    style.id = 'speak-light-style';

    style.innerText = '.' + splitConfig.hightlightCls + '{' + splitConfig.hightStyle + '}';

    document.getElementsByTagName('head')[0].appendChild(style);

    }

    // 非正文需要朗读的标签 逗号分隔

    var speakTags = 'a, p, span, h1, h2, h3, h4, h5, h6, img, input, button';

    $(document).on('mouseenter.speak-help', speakTags, function (e) {

    var $target = $(e.target);

    // 排除段落内的

    if ($target.parents('.' + splitConfig.wrapCls).length || $target.find('.' + splitConfig.wrapCls).length) {

    return;

    }

    // 图片样式单独处理 其他样式统一处理

    if (e.target.nodeName.toLowerCase() === 'img') {

    $target.css({

    border: '2px solid #000'

    });

    } else {

    $target.addClass(splitConfig.hightlightCls);

    }

    // 开始朗读

    speakText(getText(e.target));

    }).on('mouseleave.speak-help', speakTags, function (e) {

    var $target = $(e.target);

    if ($target.find('.' + splitConfig.wrapCls).length) {

    return;

    }

    // 图片样式

    if (e.target.nodeName.toLowerCase() === 'img') {

    $target.css({

    border: 'none'

    });

    } else {

    $target.removeClass(splitConfig.hightlightCls);

    }

    // 停止语音

    stopSpeak();

    });

    // 段落内文本朗读

    $(document).on('mouseenter.speak-help', '.' + splitConfig.wrapCls, function (e) {

    $(this).addClass(splitConfig.hightlightCls);

    // 开始朗读

    speakText(getText(this));

    }).on('mouseleave.speak-help', '.' + splitConfig.wrapCls, function (e) {

    $(this).removeClass(splitConfig.hightlightCls);

    // 停止语音

    stopSpeak();

    });

    注意要把针对段落的语音处理和其他地方的分开。为什么? 因为段落是个块级元素,鼠标移入段落中的空白时,如:段落前后空白、首行缩进、末行剩余空白等,是不应该触发朗读的,如果不阻止掉,进行这些区域将直接触发整段文字的朗读,失去了我们对段落文本内分隔的意义,而且,无论什么方式转化语音都是要时间的,大段内容可能需要较长时间,影响语音输出的体验。

    文本合成语音

    上面我们是直接使用了 speakText(text) 和 stopSpeak() 两个方法来触发语音的朗读和停止。

    我们来看下如何实现这个两个功能。

    其实现代浏览器默认已经提供了上面功能:

    var speechSU = new window.SpeechSynthesisUtterance();

    speechSU.text = '你好,世界!';

    window.speechSynthesis.speak(speechSU);

    复制到浏览器控制台看看能不能听到声音呢?(需要Chrome 33+、Firefox 49+ 或 IE-Edge)

    利用一下两个API即可:

    SpeechSynthesisUtterance 用于语音合成

    lang : 语言 Gets and sets the language of the utterance.

    pitch : 音高 Gets and sets the pitch at which the utterance will be spoken at.

    rate : 语速 Gets and sets the speed at which the utterance will be spoken at.

    text : 文本 Gets and sets the text that will be synthesised when the utterance is spoken.

    voice : 声音 Gets and sets the voice that will be used to speak the utterance.

    volume : 音量 Gets and sets the volume that the utterance will be spoken at.

    onboundary : 单词或句子边界触发,即分隔处触发 Fired when the spoken utterance reaches a word or sentence boundary.

    onend : 结束时触发 Fired when the utterance has finished being spoken.

    onerror : 错误时触发 Fired when an error occurs that prevents the utterance from being succesfully spoken.

    onmark : Fired when the spoken utterance reaches a named SSML "mark" tag.

    onpause : 暂停时触发 Fired when the utterance is paused part way through.

    onresume : 重新播放时触发 Fired when a paused utterance is resumed.

    onstart : 开始时触发 Fired when the utterance has begun to be spoken.

    SpeechSynthesis : 用于朗读

    paused : Read only 是否暂停 A Boolean that returns true if the SpeechSynthesis object is in a paused state.

    pending : Read only 是否处理中 A Boolean that returns true if the utterance queue contains as-yet-unspoken utterances.

    speaking : Read only 是否朗读中 A Boolean that returns true if an utterance is currently in the process of being spoken — even if SpeechSynthesis is in a paused state.

    onvoiceschanged : 声音变化时触发

    cancel() : 情况待朗读队列 Removes all utterances from the utterance queue.

    getVoices() : 获取浏览器支持的语音包列表 Returns a list of SpeechSynthesisVoice objects representing all the available voices on the current device.

    pause() : 暂停 Puts the SpeechSynthesis object into a paused state.

    resume() : 重新开始 Puts the SpeechSynthesis object into a non-paused state: resumes it if it was already paused.

    speak() : 读合成的语音,参数必须为SpeechSynthesisUtterance的实例 Adds an utterance to the utterance queue; it will be spoken when any other utterances queued before it have been spoken.

    详细api和说明可参考:

    那么上面的两个方法可以写为:

    var speaker = new window.SpeechSynthesisUtterance();

    var speakTimer,

    stopTimer;

    // 开始朗读

    function speakText(text) {

    clearTimeout(speakTimer);

    window.speechSynthesis.cancel();

    speakTimer = setTimeout(function () {

    speaker.text = text;

    window.speechSynthesis.speak(speaker);

    }, 200);

    }

    // 停止朗读

    function stopSpeak() {

    clearTimeout(stopTimer);

    clearTimeout(speakTimer);

    stopTimer = setTimeout(function () {

    window.speechSynthesis.cancel();

    }, 20);

    }

    因为语音合成本来是个异步的操作,因此在过程中进行以上处理。

    现代浏览器已经内置了这个功能,两个API接口兼容性如下:

    Feature

    Chrome

    Edge

    Firefox (Gecko)

    Internet Explorer

    Opera

    Safari

    (WebKit) Basic

    support 33

    (Yes)

    49 (49)

    No support

    ?

    7

    如果要兼容其他浏览器或者需要一种完美兼容的解决方案,可能就需要服务端完成了,根据给定文本,返回相应语音即可,百度语音 http://yuyin.baidu.com/docs就提供这样的服务。

    展开全文
  • url='换成需要朗读的网页页面地址' r = requests.get(url) r.encoding='GBK' htmlData = r.text html = etree.HTML(htmlData) title=html.xpath('//div[@class="wrapper_main"]//h1//span[@id="htmltimu"]//...
  • 我挺喜欢听小说的,喜马拉雅,懒人听书都充过会员,但爬他们网站的资源是不是有被禁的风险,思来想去还是爬个没有版权保护的听书网站,找了一会儿,发现有个叫(恋)(听)网的还不错。网站底下的免责声明 并且有...
  • MSTTS语音朗读引擎

    2009-11-12 13:09:11
    MSTTS语音朗读引擎,让支持MSTTS技术的程序发声
  • 语音朗读源码

    2013-03-08 17:43:02
    语音朗读阴郁克保存为文件 保存为语音问文件效果更加
  • 使用URL在线语音合成

    千次阅读 2015-12-29 11:57:17
    最近一直在做手机的项目,用到了语音合成与识别的功能,就找了几个网址做了分析,这里仅仅实现了...使用这个URL,你需要POST content 数据到这个URL上面,会返回一个MP3的URL播放地址,然后使用这个地址播放就可以了
  • 最近自己做了个小说阅读器,就是下面这个东西啦,目前仅支持Window系统 软件的特点: 导入本地txt书籍,自动提取目录; 记录阅读进度,下次打开自动跳转至上次离开位置; 支持书籍分组管理,可以自己创建/删除分组...
  • var rootUrl = "http://114.115.220.1:91";//各位大神小弟自己的服务器别黑谢谢 var storaySign = "FanqieXiaoShuo0412326@163.com"; var woolStorage = storages.create(storaySign);//创建本地存储 var
  • tts 语音朗读 语音报时 语音提醒 文字转WAV
  • 项目开源地址 1. https://github.com/ShanaMaid/oho-reader   小说数据接口地址: 1.http://api.zhuishushenqi.com/book/50865988d7a545903b000009
  • 使用微软TTS语音引擎实现文本朗读

    千次阅读 2019-03-15 15:38:09
    使用微软TTS语音引擎实现文本朗读 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/byxdaz/article/details/78443954 TTS(Text-To-Speech)是指文本语音的简称,即通过TTS引擎把...
  • http://tts.baidu.com/text2audio?lan=zh&ie=UTF-8&text=百度翻译女声语音播报apihttp://api.microsofttranslator.com/v2/http.svc/speak?appId=TJnIprF8gfKIzzWSJUYbWZBxOdX4nQDJK4o5BoiI42GE*&language=zh-TW&...
  • 推荐几个好的URL

    2005-09-21 15:51:00
    个人图书馆www.360doc.com/大型软件下载www.51windows.net
  • 2、示例代码 百度语音测试 3、参考资料 以上所述是小编给大家介绍的在网页上通过JS实现文本的语音朗读详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对...
  • TTS实现文字语音朗读

    千次阅读 2010-04-15 11:50:00
    一. TTS概述随着语音技术的发展,微软也推出了相应的语音开发工具...它其中的TTS(text-to-speech)引擎可以用于实现语音合成,我们通过TTS引擎可以分析文本内容并且将其朗读出。实现TTS技术的方法有很多种,现在主要采
  • 自己做的一个小测试程序(读memo里的内容),测试文本朗读功能,配上TTS语音库,效果还不错,大家共同学习吧!(注意看里边的说明文件)
  • 阅读引擎开源项目调研总结

    千次阅读 2018-02-02 09:56:29
    [NOT MAINTAINED]轻小说文库(Wenku8)安卓版第三方公益App,Material Design风格、无广告、不盈利的轻小说阅读器(light novel reader)。 P.S. 下一代阅读器—— Project PRPR!已在设计中!欢迎关注以及建议!已获取...
  • 写了一下用pyTTS来朗读本地方件或在线朗读RFC文档,当然也可以修改一下,做成在线朗读新闻之类的,另本来想实现一个读中文小说的小程序,目前没有发现对中文支持得非常好的,且是免费的语音处理引擎,只能使用TTS...
  • 实用小工具 之 阿里云语音合成

    千次阅读 2021-01-24 14:49:10
    语音合成TTS,由微软提供的合成引擎,不过电脑上的语音引擎还是有点机械,效果不是很好 这几年,几大公司也退出了自己的语音引擎,之所以选择阿里云的语音引擎,是因为,可以提供3月免费语音合成功能,合成效果虽然...
  • 写了一下用pyTTS来朗读本地方件或在线朗读RFC文档,当然也可以修改一下,做成在线朗读新闻之类的,另本来想实现一个读中文小说的小程序,目前没有发现对中文支持得非常好的,且是免费的语音处理引擎,只能使用TTS...
  • 前言 本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,版权归原作者所有,如有...pyttsx3(Text to Speech)是一个语音转换模块,它可以在离线的环境下工作,支持多个引擎,而且兼容于Python2和Pyt

空空如也

空空如也

1 2 3 4
收藏数 61
精华内容 24
关键字:

小说朗读引擎url