请选择 进入手机版 | 继续访问电脑版
搜索
房产
装修
汽车
婚嫁
健康
理财
旅游
美食
跳蚤
二手房
租房
招聘
二手车
教育
茶座
我要买房
买东西
装修家居
交友
职场
生活
网购
亲子
情感
龙城车友
找美食
谈婚论嫁
美女
兴趣
八卦
宠物
手机

scrapy+baiduapi搭建一个私人小说阅读器(智能爬取加智能朗读)(二)

[复制链接]
查看: 10|回复: 0

2万

主题

3万

帖子

8万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
81333
发表于 2020-1-14 12:19 | 显示全部楼层 |阅读模式
写在前面的话

上章说了智能爬取,拿到了网上小说的信息,这章起头利用这些数据举行智能朗诵。搜索网上朗诵的方式,垂危包含微软自带的speeker,三方智能语音api。经过挑选,我挑选了语音包还算丰富(垂危妹子声音甜蜜)的百度api举行智能朗诵(文本转语音,这里垂危是MP3格式,wav貌似测试有题目),阅读功用用微软com自带的控件。

小说数据UI展现

小说的信息垂危包含小说的底子信息,小说的章节信息,小说的文本具体信息。这里围绕这个,按照window form筹齐截个界面。
scrapy+baiduapi搭建一个私人小说阅读器(智能爬取加智能朗读)(二)  游戏 448179-20200114095806878-1118221298
(本人非专业UI,界面丑陋请关心)



  • 小说列表UI展现
  左侧展现数据库办事器里面的小说列表(数据绑定),代码以下:
  1.   DataSet dataSet= dbProvider.ExecuteDataSet($"select BookName,Id from BookBasic");            if (dataSet != null)            {                List bookInfos = new List();                foreach (DataRow item in dataSet.Tables[0].Rows)                {                    bookInfos.Add(new BookInfo()                    {                        Id = item[1].ToString(),                        BookName = item[0].ToString()                    });                }                listBox1.DataSource = bookInfos;                listBox1.DisplayMember = "BookName";            }         
复制代码
  挑选功用:
  1.   private void textBox2_TextChanged(object sender, EventArgs e)        {            string text = textBox2.Text;            if (text == "请输入小说名")                return;            DataSet dataSet = dbProvider.ExecuteDataSet($"select BookName,Id from BookBasic where BookName like '%{text}%'");            if (dataSet != null)            {                List bookInfos = new List();                foreach (DataRow item in dataSet.Tables[0].Rows)                {                    bookInfos.Add(new BookInfo()                    {                        Id = item[1].ToString(),                        BookName = item[0].ToString()                    });                }                listBox1.DataSource = bookInfos;            }        }
复制代码

  • 小说详情UI展现
  右侧列表展现左侧选中小说的具体信息,包含小说的称号、作者、图标(图标用blob存储)等,点击起头阅读,检察小说列表信息
scrapy+baiduapi搭建一个私人小说阅读器(智能爬取加智能朗读)(二)  游戏 448179-20200114100539985-795223250

  代码以下:
  1. private void listBox1_SelectedIndexChanged(object sender, EventArgs e)        {            pnlBookInfo.Visible = true;            pnlList.Visible = false;            pnlDetail.Visible = false;            BookInfo bookInfo = listBox1.SelectedItem as BookInfo;            DataSet dataSet = dbProvider.ExecuteDataSet($"select * from BookBasic where Id='{bookInfo.Id}'");            if (dataSet != null)            {                DataRow dataRow = dataSet.Tables[0].Rows[0];                bookInfo.Author = dataRow["Author"].ToString();                bookInfo.LatestChapter = dataRow["LatestChapter"].ToString();                bookInfo.Desc1 = dataRow["Desc1"].ToString();                try                {                    bookInfo.Image = (byte[])dataRow["Image"];                    string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + ".jpg");                    using (FileStream stream = new FileStream(tempPath, FileMode.Create))                    {                        stream.Write(bookInfo.Image, 0, bookInfo.Image.Length);                    }                    pictureBox1.Image = Image.FromFile(tempPath);                }                catch                {                }            }            bindingSource1.DataSource = bookInfo;        }
复制代码

  • 小说列表信息展现
  检察小说的列表信息,供给返回和排序的功用
scrapy+baiduapi搭建一个私人小说阅读器(智能爬取加智能朗读)(二)  游戏 448179-20200114101351116-10792532



  代码以下:
  1. private void SetChapterLst(string order="asc")        {            BookInfo bookInfo = bindingSource1.DataSource as BookInfo;            //初始化小说列表            DataSet dataSet = dbProvider.ExecuteDataSet($"select Title,DId from BookContent where Id='{bookInfo.Id}' order by cast(Chapter as decimal(6,0)) {order}");            List bookInfos = new List();            foreach (DataRow item in dataSet.Tables[0].Rows)            {                bookInfos.Add(new BookInfo()                {                    Id = item[1].ToString(),                    BookName = item[0].ToString()                });            }            listBox2.DataSource = bookInfos;            listBox2.DisplayMember = "BookName";        }
复制代码

  • 小说内容展现
  点击章节列表信息展现小说信息
scrapy+baiduapi搭建一个私人小说阅读器(智能爬取加智能朗读)(二)  游戏 448179-20200114102129266-8934810



  代码以下:
  1.      private void SetDetail(string Id)        {            //初始化小说列表            DataSet dataSet = dbProvider.ExecuteDataSet($"select * from BookContent where DId='{Id}'");            DataRow dataRow = dataSet.Tables[0].Rows[0];            BookInfo bookInfo = new BookInfo()            {                Desc1 = dataRow["Content"].ToString().Replace("笔趣阁手机端  http://m.biquwu.cc    ", ""),                BookName = dataRow["Title"].ToString(),            };            bindingSource2.DataSource = bookInfo;        }
复制代码
 
朗诵功用

  朗诵功用的实现垂危包含2个部分,一个部分是将小说文本转为语音文件,一部分是将语音文本依照必定的次第播放出来。

  • 文本转语音
  百度api供给了很多野生智能的功用(必要申请账号和秘钥),有爱好自己可以研讨。此次用到文本转语音的接口,垂危是以接口的形式请求返回(必要token),代码以下:
  
  1.      ///         /// 获得Token        ///         ///         ///         ///         private string getTokon()        {            string token = redisConfig._GetKey("baidu_token");            if (string.IsNullOrEmpty(token))            {                WebClient webClient = new WebClient();                webClient.BaseAddress = "https://openapi.baidu.com";                string result = webClient.DownloadString($"https://openapi.baidu.com/oauth/2.0/token?grant_type=client_credentials&client_id={API_key}&client_secret={API_secret_key}");                webClient.Dispose();                dynamic json = JToken.Parse(result);                token = json.access_token;                long expires_in = json.expires_in;                redisConfig._AddKey("baidu_token", token, new TimeSpan(expires_in * 1000 * 1000 * 10));            }            return token;        }        public void GetAudio(string filePath,string text)        {            //获得参数            int vol = redisConfig._GetKey("vol");            if (vol == default(int))                vol = 5;            int pit = redisConfig._GetKey("pit");            if (pit == default(int))                pit = 5;            int spd = redisConfig._GetKey("spd");            if (spd == default(int))                spd = 5;            int per = redisConfig._GetKey("per");            if (per == default(int))                per = 0;            string token = getTokon();            var handler = new HttpClientHandler() { AutomaticDecompression = DecompressionMethods.GZip };            HttpClient httpClient = new HttpClient(handler);            httpClient.BaseAddress = new Uri("http://tsn.baidu.com/text2audio");            //await异步等待回应            var response = httpClient.PostAsync($"http://tsn.baidu.com/text2audio?lan=zh&ctp=2&vol={vol}&per={per}&spd={spd}&pit={pit}&aue=3&tok={token}&tex={HttpUtility.UrlEncode(HttpUtility.UrlEncode(text))}&cuid={Guid.NewGuid()}&aue=6", null).Result;            //确保HTTP乐成状态值            response.EnsureSuccessStatusCode();            //await异步读取末端的JSON(留意此时gzip已经被自动解紧缩了,由于上面的AutomaticDecompression = DecompressionMethods.GZip)            byte[] result = response.Content.ReadAsByteArrayAsync().Result;            string resonse= response.Content.ReadAsStringAsync().Result;            using (FileStream fileStream=new FileStream(filePath,FileMode.Create))            {                fileStream.Write(result, 0, result.Length);            }        }
复制代码
  小说的内容是一串长文本内容,这里假如自己用baiduapi请求会提醒超长(官网提醒最长200字符),所以我们必要经过标记和长度举行截取,在将各个语音文件逐一播放,不就实现了次第播放了。
  代码以下:
  
  1.     private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)        {            BookInfo bookInfo = e.Argument as BookInfo;            string dir = Path.Combine(Path.GetTempPath(), bookInfo.BookName);            if (Directory.Exists(dir) == false)            {                Directory.CreateDirectory(dir);            }            int index = 0;            int lastLen = 0;            //播放章节题目            string filePath = Path.Combine(dir, index + ".mp3");            baiduApi.GetAudio(filePath, bookInfo.BookName);            backgroundWorker1.ReportProgress(0, filePath);            keyValuePairs.Add(index, new int[] { 0, 0 });            index++;            //请求资本            if (!string.IsNullOrEmpty(bookInfo.Desc1))            {                string[] content = bookInfo.Desc1.Split('。', ',', ';', ',', '.');                int current = 1;                foreach (var txt in content)                {                    string item = txt.Trim();                    if (string.IsNullOrEmpty(item))                    {                        continue;                    }                    int len = item.Length;                    for (int i = 0; i  0 && played == playList.count)                {                    //清空播放列表                    playList.clear();                    keyValuePairs.Clear();                    played = 0;                    richTextBox1.Text = string.Empty;                    //删除播放文件                    BookInfo bookInfo = bindingSource2.DataSource as BookInfo;                    string dir = Path.Combine(Path.GetTempPath(), bookInfo.BookName);                    try                    {                        Directory.Delete(dir, true);                    }                    catch                    {                    }                    //自动播放下一章                    bookInfo = listBox2.SelectedItem as BookInfo;                    List bookInfos = listBox2.DataSource as List;                    int index = bookInfos.IndexOf(bookInfo);                    if (index > 0 && index < bookInfos.Count - 1)                    {                        button3_Click(null, null);                        bookInfo = bindingSource2.DataSource as BookInfo;                        if (!backgroundWorker1.IsBusy)                            backgroundWorker1.RunWorkerAsync(bookInfo);                    }                    else                    {                        if (!backgroundWorker1.IsBusy)                            backgroundWorker1.RunWorkerAsync(new BookInfo() { BookName = "当前目录已播放完" });                    }                }            }        }   ///         /// 高亮表现文本        ///         private void HighlightText()        {            if (keyValuePairs.ContainsKey(played))            {                int[] selected = keyValuePairs[played];                if (richTextBox1.Text.Length >= selected[0] + selected[1])                {                    int index = richTextBox1.Find(richTextBox1.Text.Substring(selected[0], selected[1]));                    if (index >= 0)                    {                        richTextBox1.SelectionStart = selected[0];                        richTextBox1.SelectionLength = played < (keyValuePairs.Count - 1) ? (keyValuePairs[played + 1][0] - selected[0]) : selected[1];                        //richTextBox1.SelectionFont = new Font(richTextBox1.SelectionFont, FontStyle.Regular);                        richTextBox1.SelectionBackColor = SystemColors.Highlight;                        richTextBox1.SelectionColor = Color.White;                    }                }            }        }
复制代码

  • 小说语速、语和谐语音库切换(实现不实时,姑且未优化)
  
scrapy+baiduapi搭建一个私人小说阅读器(智能爬取加智能朗读)(二)  游戏 448179-20200114104325481-1259765023


  用到redis缓存设备(设备参数百度官网可以看到),布景请求api的参数静态redis获得实现
参数可需描摹tex必填分解的文本,利用UTF-8编码。小于2048其中翰墨大要英文数字。(文本在百度办事器内转换为GBK后,长度必须小于4096字节)tok必填开放平台获得到的斥地者access_token(见上面的“鉴权认证机制”段落)cuid必填用户唯一标识,用来盘算UV值。倡议填写能区分用户的呆板 MAC 地点或 IMEI 码,长度为60字符之内ctp必填客户端典范挑选,web端填写牢固值1lan必填牢固值zh。说话挑选,现在只要中英文肴杂形式,填写牢固值zhspd选填语速,取值0-15,默以为5中语速pit选填音调,取值0-15,默以为5中腔调vol选填音量,取值0-15,默以为5中音量per(底子音库)选填度小宇=1,度小美=0,度安宁=3,度丫丫=4per(宏构音库)选填度博文=106,度幼童=110,度小萌=111,度米朵=103,度小娇=5aue选填3为mp3格式(默许); 4为pcm-16k;5为pcm-8k;6为wav(内容同pcm-16k); 留意aue=4大要6是语音识别要求的格式,可是音频内容不是语音识别要求的自然人发音,所以识别结果会受影响。  代码以下:
  
  1.   private void FormSetting_Load(object sender, EventArgs e)        {            //初始化语音库            List perInfos = new List();            perInfos.Add(new PerInfo() { Val = 0, Display = "度小美" });            perInfos.Add(new PerInfo() { Val = 1, Display = "度小宇" });            perInfos.Add(new PerInfo() { Val = 3, Display = "度安宁" });            perInfos.Add(new PerInfo() { Val = 4, Display = "度丫丫" });            perInfos.Add(new PerInfo() { Val = 106, Display = "度博文" });            perInfos.Add(new PerInfo() { Val = 110, Display = "度幼童" });            perInfos.Add(new PerInfo() { Val = 111, Display = "度小萌" });            perInfos.Add(new PerInfo() { Val = 103, Display = "度米朵" });            perInfos.Add(new PerInfo() { Val = 5, Display = "度小娇" });            per.DataSource = perInfos;            per.DisplayMember = "Display";            per.ValueMember = "Val";            //初始化设备Redis            foreach (Control ctl in groupBox1.Controls)            {                string key = ctl.Name;                int val = redisConfigInfo._GetKey(key);                if (ctl.GetType()==typeof(TrackBar))                {                    TrackBar trackBar = ctl as TrackBar;                                        if (val == default(int))                    {                        val = 5;                    }                    trackBar.Value = val;                }                else if(ctl.GetType()==typeof(ComboBox))                {                    ComboBox comboBox = ctl as ComboBox;                    if (val == default(int))                    {                        val = 0;                    }                    comboBox.SelectedValue = val;                }            }        }
复制代码

代码地点

  完整github代码地点
  


免责声明:假如加害了您的权益,请联系站长,我们会实时删除侵权内容,感谢合作!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Copyright © 2006-2014 妈妈网-中国妈妈第一,是怀孕、育儿、健康等知识交流传播首选平台 版权所有 法律顾问:高律师 客服电话:0791-88289918
技术支持:迪恩网络科技公司  Powered by Discuz! X3.2
快速回复 返回顶部 返回列表