最近在学习python,写了一款简单的小说下载器,基本功能都已经实现,废话不多说 直接上效果

简单说下功能把

1.支持在线阅读,翻页 键盘快捷键上下(阅读) 左右(翻页)。可以导出TXT到本地,默认是当前目录。

2.支持搜索,暂停下载,继续下载 。由于采用的是轻量化sqlite数据库存储。好处是方便迁移。

3.已经打成EXE文件 放到文末,所需要的安装文件都有,可以直接去下载享用。

目录

源代码:

seachbook.py (主程序页面)

bookQThread.py 多线程调用(下载功能)

sqlFactory.py (sql文件)

Ui_rebook.py (ui页面)

下载地址


源代码:

seachbook.py (主程序页面)

1.样式使用了官方的qt_material 默认皮肤

2.播放声音需要下载解码器,可以自己搜索安装下 LAVFilters,很简单直接傻瓜式下一步

import requests
import parsel
import uuid
import datetime
import time
import sys
import os
from sqlFactory import sqlFactory
from Ui_rebook import Ui_MainWindow
import PyQt5.QtWidgets as QtWidgets
import PyQt5.QtCore as QtCore
import PyQt5.QtGui as QtGui
from qt_material import apply_stylesheet
from bs4 import BeautifulSoup
from bookQThread import downQThread
import ctypes
import pyttsx3
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContentctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("myappid")
class mainstart(QtWidgets.QMainWindow, Ui_MainWindow):def __init__(self):# 初始化父类super().__init__()self.player = QMediaPlayer()    # 调用Ui_Form的setupUi()方法构建页面self.setupUi(self)#透明度self.setWindowOpacity(0.95)#self.setAttribute(PyQt5.QtCore.Qt.WA_TranslucentBackground)  # 设置窗口背景透明self.setWindowFlag(QtCore.Qt.FramelessWindowHint)  # 隐藏边框self.setWindowTitle("小说搜索阅读器")   # 设置窗口名self.setWindowIcon(QtGui.QIcon("./bookicon.jpeg")) #self.setWindowFlag(QtCore.Qt.FramelessWindowHint)self.timer = QtCore.QTimer(self)self.timer.start(1000)self.timer.timeout.connect(self.playByMode)self.pushButton.clicked.connect(self.pushButton_click)self.pushButton_2.clicked.connect(self.pushButton_2_click)self.pushButton_3.clicked.connect(self.pushButton_3_click)#下一章self.pushButton_4.clicked.connect(self.pushButton_4_click)#上一章self.pushButton_5.clicked.connect(self.pushButton_5_click)#展示self.pushButton_6.clicked.connect(self.pushButton_6_click)#刷新self.pushButton_7.clicked.connect(self.pushButton_7_click)self.pushButton_8.clicked.connect(self.pushButton_8_click)#取消self.pushButton_9.clicked.connect(self.pushButton_9_click)#转语音self.pushButton_10.clicked.connect(self.pushButton_10_click)#播放self.pushButton_11.clicked.connect(self.pushButton_11_click)#暂停self.pushButton_12.clicked.connect(self.pushButton_12_click)self.horizontalSlider.valueChanged.connect(self.pushButton_13_click)self.tabWidget.currentChanged.connect(self.tabCurrentIndex)self.treeWidget.clicked.connect(self.treeWidget_Clicked)#self.treeWidget.itemClicked.connect(self.treeWidget_Clicked)self.treeWidget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)  # 打开右键菜单的策略self.treeWidget.customContextMenuRequested.connect(self.treeWidgetItem_fun)  # 绑定事件#异步操作 处理后台任务self.p = downQThread(mainstart=self)  # 把主函数对象传给服务,方便服务操作控件#self.tab_2.mousePressEvent# 设置搜索列表总列数self.tableWidget.setColumnCount(6)self.textEdit.setReadOnly(True)self.textEdit.setFont(QtGui.QFont("宋体",10))#自适应列宽 占满空间self.tableWidget.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch)# 设置表头(excel_data.columns可以获取表头列表,默认第一列为表头)self.tableWidget.setHorizontalHeaderLabels(["小说地址","小说名称","最新章节","作者","更新日期","操作"])self.tableWidget.setColumnHidden(0, True)# 向下拉框中添加选型,具体为在下拉框第index+1个选型设置为内容nameself.comboBox.addItems(['10','12','14'])self.comboBox.currentIndexChanged.connect(self.comboBoxChanged)#重置进度条self.progressBar.reset()self.sql = sqlFactory()self.count = 0self.content = Noneself.istree = Trueself.islose = Noneself.bookurl = Noneself.bookname = Noneself.chapter = Noneself.autoname = Noneself.chapterurl = Noneself.isdownend = Noneself.is_pause = Trueself.ismp3 = Falset = time.time()now=datetime.datetime.now()self.mill = int(round(t * 1000))self.date = now.strftime("%Y-%m-%d %H:%M:%S")def comboBoxChanged(self):# 将下拉框中所有的选项删除#self.comboBox.clear()# 根据索引获取当前的下拉框内容index = self.comboBox.currentIndex()text = self.comboBox.itemText(index)self.textEdit.setFont(QtGui.QFont("宋体",int(text)))def treeWidgetItem_fun(self):item=self.treeWidget.currentItem()#item1= self.treeWidget.itemAt(pos)if item!=None : # 判断菜单是否为空popMenu =QtWidgets.QMenu()popMenu.addAction(QtWidgets.QAction(u'导出小说', self.treeWidget))popMenu.addAction(QtWidgets.QAction(u'删除小说', self.treeWidget))popMenu.triggered[QtWidgets.QAction].connect(self.processtrigger) # 右键点击清空之后执行的操作popMenu.exec_(QtGui.QCursor.pos())def processtrigger(self,q):#判断是项目节点还是任务节点item=self.treeWidget.currentItem()command=q.text()#item=self.taskTreeWidget.currentItem()if command=="导出小说":if item.parent() is None:if item.text(2)!='':self.sql.sqlquery =(item.text(2),)rows = self.sql.sql_select()with open(rows[0][3]+'.txt','a',encoding='utf-8') as f:for row in rows:f.write(row[4])elif item.parent() is not None:self.sql.sqlquery =(item.text(2),item.text(1),)row = self.sql.sql_selectchapter()with open(row[1]+'.txt','a',encoding='utf-8') as f:f.write(row[4])QtWidgets.QMessageBox.about(self, '提示', '导出小说成功')elif command=="删除小说":if item.parent() is None:if item.text(2)!='':self.sql.sqlquery =(item.text(2),)rows = self.sql.sql_delbook()elif item.parent() is not None:self.sql.sqlquery =(item.text(2),item.text(1),)row = self.sql.sql_delbookchapter()QtWidgets.QMessageBox.about(self, '提示', '删除小说成功')self.pushButton_7_click()def treeWidget_Clicked(self):te = self.treeWidget.currentItem().text(1)self.chapter = self.treeWidget.currentItem().text(0)self.ismp3 = Falseself.is_pause = Trueself.pushButton_10.setEnabled(True)self.pushButton_11.setEnabled(False)self.pushButton_12.setEnabled(False)self.label_3.setText('')self.label_4.setText('')if te =='':self.pushButton_10.setEnabled(False)self.textEdit.setText('') returnif os.path.exists('./'+str(self.chapter)+'.mp3'):self.player.setMedia(QMediaContent(QtCore.QUrl('./'+str(self.chapter)+'.mp3')))self.ismp3 = Trueself.pushButton_10.setEnabled(False)self.pushButton_11.setEnabled(True)self.pushButton_12.setEnabled(True)self.horizontalSlider.setMinimum(0)self.horizontalSlider.setMaximum(self.player.duration())self.label_3.setText('00:00')self.label_4.setText('00:00')chapterId = self.treeWidget.currentItem().text(1)bookId = self.treeWidget.currentItem().text(2)#print(bookId,chapterId)if bookId !="":self.sql.sqlquery =(bookId,chapterId,)row = self.sql.sql_selectchapter()self.textEdit.setFont(QtGui.QFont("宋体",10))self.textEdit.setText(row[4])self.bookname =row[1]self.chapter =row[3]#print(row[4])def gettree(self):self.treeWidget.setColumnCount(3)self.treeWidget.setHeaderLabels(['目录','章节id','书籍id'])self.treeWidget.setColumnWidth(0,150)#隐藏章节id和目录idself.treeWidget.setColumnHidden(1,True)self.treeWidget.setColumnHidden(2,True)#self.sql.sqlquery = (str("14930"),)rows = self.sql.sql_selectbook()rootlist = []if rows is not None:for row in rows:root = QtWidgets.QTreeWidgetItem(self.treeWidget)     #创建节点root.setText(0, row[1])root.setText(2, row[0]) #bookidself.sql.sqlquery = (row[0],)chapterrows = self.sql.sql_select()for chapter in chapterrows:child = QtWidgets.QTreeWidgetItem(root)   #创建子节点child.setText(0, chapter[0])   #设置第一列的值child.setText(1, chapter[1]) #设置第二列的值child.setText(2, row[0]) #设置第三列的值#self.treeWidget.setAlternatingRowColors(True)rootlist.append(child)self.treeWidget.insertTopLevelItems(0,rootlist)   #将创建的树节点添加到树控件中def tabCurrentIndex(self):if self.tabWidget.currentIndex() == 0:print('000')elif self.tabWidget.currentIndex() == 1:print('111')else:passdef keyPressEvent(self, a0: QtGui.QKeyEvent):print("key press response", a0.key())# if a0.key() == QtCore.Qt.Key_PageUp:#     self.on_back_image_view()# if a0.key() == QtCore.Qt.Key_PageDown:#     self.on_forward_image_view()def keyReleaseEvent(self, a0: QtGui.QKeyEvent):#print("key release response", a0.key())if a0.key() == QtCore.Qt.Key_Left:self.pushButton_5_click()if a0.key() == QtCore.Qt.Key_Right:self.pushButton_4_click()def mousePressEvent(self, event):  ##重写鼠标点击事件if event.button() == QtCore.Qt.LeftButton:self.Move = True  ##鼠标按下时设置为移动状态self.Point = event.globalPos() - self.pos()  ##记录起始点坐标event.accept()def mouseMoveEvent(self, QMouseEvent):  ##移动时间try:# 仅监听标题栏if QtCore.Qt.LeftButton and self.Move and self.label.underMouse():# 更改鼠标图标#self.setCursor(QtGui.QCursor(Qt.OpenHandCursor))# 更改窗口位置self.move(QMouseEvent.globalPos() - self.Point)QMouseEvent.accept()except Exception as e:print("报错信息=", e)def mouseReleaseEvent(self, QMouseEvent):  ##结束事件 self.Move = Falsedef pushButton_click(self):self.close()def pushButton_2_click(self):self.content = self.lineEdit.text()self.seachtext()def pushButton_3_click(self):self.lineEdit.setText("")def pushButton_4_click(self):t = self.treeWidget.currentItem()if t is None or t=='' or t.text(1) =='':return#获取当前索引childint = t.parent().indexOfChild(t)t.setSelected(False)childints = t.parent().child(childint+1)if childints is None:QtWidgets.QMessageBox.warning(self, '提示', '已经到底啦!')return#设置显示选中childints.setSelected(True)#设置显示选中的是当前项   (当前项不一定是选中项 所以需要指定显示项为当前项)self.treeWidget.setCurrentItem(childints)self.treeWidget_Clicked()def pushButton_5_click(self):t = self.treeWidget.currentItem()if t is None or t=='' or t.text(1) =='':return#获取当前索引childint = t.parent().indexOfChild(t)if childint==0:QtWidgets.QMessageBox.warning(self, '提示', '已经到顶啦!')returnt.setSelected(False)childints = t.parent().child(childint-1)#设置显示选中childints.setSelected(True)#设置显示选中的是当前项   (当前项不一定是选中项 所以需要指定显示项为当前项)self.treeWidget.setCurrentItem(childints)self.treeWidget_Clicked()def pushButton_6_click(self):if self.istree:self.treeWidget.setHidden(True)self.istree = Falseelse:self.treeWidget.setVisible(True)self.istree = Truedef pushButton_7_click(self):self.treeWidget.clear()self.gettree()def pushButton_8_click(self):self.showMinimized()def pushButton_9_click(self):self.pushButton_9.setEnabled(False)self.isdownend = Falseself.progressBar.reset()def pushButton_11_click(self):# self.player.setPosition(10000)self.player.play()self.is_pause = Falseif self.player.duration() == self.horizontalSlider.value():self.is_pause = Trueself.horizontalSlider.setSliderPosition(1000)#duration = self.player.duration()#print(int(duration/1000/60))#self.horizontalSlider.setSliderPosition(50)def pushButton_12_click(self):self.is_pause = Trueself.player.pause()def pushButton_13_click(self):self.player.setPosition(self.horizontalSlider.value())#self.player.pause()#self.player.setCurPlaying()def pushButton_10_click(self):str = self.textEdit.toPlainText()if str!='':engine = pyttsx3.init() #初始化语音引擎engine.setProperty('rate', 125)   #设置语速engine.setProperty('volume',1)  #设置音量voices = engine.getProperty('voices') engine.setProperty('voice',voices[0].id)   #设置第一个语音合成器engine.save_to_file(str,self.chapter+'.mp3')engine.runAndWait()engine.stop()self.ismp3 = Trueself.pushButton_10.setEnabled(False)self.pushButton_11.setEnabled(True)self.pushButton_12.setEnabled(True)# 根据播放模式自动播放,并刷新进度条def playByMode(self):# 刷新进度条if (not self.is_pause) :self.horizontalSlider.setMinimum(0)self.horizontalSlider.setMaximum(self.player.duration())self.horizontalSlider.setSliderPosition(self.horizontalSlider.value() + 1000)if self.ismp3:self.label_3.setText(time.strftime('%M:%S', time.localtime(self.player.position()/1000)))self.label_4.setText(time.strftime('%M:%S', time.localtime(self.player.duration()/1000)))def pushButton_down_click(self):if self.isdownend:return QtWidgets.QMessageBox.warning(self, '提示', '其他任务正在下载!')self.isdownend = Trueself.pushButton_9.setEnabled(True)#获取当前列#self.tableWidget.currentColumn()#获取当前行row = self.tableWidget.currentRow()self.bookurl = self.tableWidget.item(row,0).text()self.bookname = self.tableWidget.item(row,1).text()self.autoname = self.tableWidget.item(row,3).text()self.p.start()#self.getbook()#  #开启线程池# with ThreadPoolExecutor(50) as f:#     f.submit(self.getbook())#     f.shutdown()    def seachtext(self):header = {"User-Agent":'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'}#搜索书香url = "https://www.ibiquge.la/modules/article/waps.php"param = {"searchkey":self.content}response = requests.post(url,headers = header,params=param)response.encoding = 'utf-8'selector = parsel.Selector(response.text)trlist = selector.xpath('//table[@class="grid"]/tr')self.tableWidget.setColumnWidth(2, 200)data_table_current = 0for tr in trlist:self.bookname = tr.xpath('./td[1]/a/text()').get()chaptername = tr.xpath('./td[2]/a/text()').get()self.autoname = tr.xpath('./td[3]/text()').get()uptime = tr.xpath('./td[4]/text()').get()self.bookurl =  tr.xpath('./td[1]/a/@href').get()self.chapterurl =  tr.xpath('./td[2]/a/@href').get()if chaptername is None:continueself.tableWidget.setRowCount(data_table_current+1)#隐藏列#self.tableWidget.setColumnHidden(0, True)#展示行#self.tableWidget.setRowHidden(0, False)columns = [str(self.bookurl),self.bookname,chaptername,self.autoname,uptime]but = QtWidgets.QPushButton()#创建QPushButton控件but.setText('下载')self.tableWidget.setCellWidget(data_table_current,5,but)#绑定按钮but.clicked.connect(self.pushButton_down_click)#插入值for j in range(len(columns)):# 创建QTableWidgetItem对象,并设置值new_item = QtWidgets.QTableWidgetItem(columns[j])# 设置QTableWidgetItem对象启用、可以选中和可以编辑new_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEnabled)# 设置QTableWidgetItem对象里面的值水平,垂直居中new_item.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)# 将新建的QTableWidgetItem添加到tableWidget中,参数分别是(行索引,列索引,QTableWidgetItem对象)self.tableWidget.setItem(data_table_current, j, new_item)# 写数据的当前索引加1data_table_current += 1def getbook(self):books = str(self.bookurl).split('/')[4]self.sql.sqlquery = (books,)rows = self.sql.sql_select()print(len(rows))header = {"User-Agent":'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'}response = requests.get(self.bookurl,headers = header)response.encoding = 'utf-8'selector = parsel.Selector(response.text)dllist = selector.xpath('//div[@id="list"]/dl[1]//dd')cont = 0for dl in dllist:cont+=1self.progressBar.setMaximum(cont)con = 0for dl in dllist:if self.isdownend == False: returnchapterurl = dl.xpath('./a/@href').get()sp = str(chapterurl).split('/')chapterid = sp[3].replace('.html','')exist = Falsecon+=1for row in rows:if chapterid == row[1]:exist = Trueif exist:continueresponse = requests.get('https://www.ibiquge.la/'+str(chapterurl),headers = header)response.encoding = 'utf-8'selector = parsel.Selector(response.text)chaptername = selector.xpath('//div[@class="bookname"]/h1/text()').get()#content = selector.xpath('//div[@id="content"]').extract()content = selector.xpath('//div[@id="content"]').getall()ss ='\n'+'  '+chaptername+'\n'+str(content).replace('\\xa0',' ').replace('\\r<br>\\r<br>','\n').replace('[','').replace(']','')soup = BeautifulSoup(ss[0:ss.index("亲,点击进去,给个好评呗")],'html.parser').get_text()self.sql.sqlquery = (str(uuid.uuid4()), self.bookname, self.autoname, chaptername,soup,sp[2],chapterid,self.date,self.date,con,len(soup),)#保存入库self.sql.sql_insert()self.progressBar.setValue(con)if con == cont:self.isdownend = Falseself.pushButton_9.setEnabled(False)self.label_2.setText(self.bookname+' '+chaptername+'下载成功!')def selectlose(self):loserows = self.sql.sql_selectlose()if loserows is not None:self.islose = 1for row in loserows:bookId = row[5]chapterId = row[6]catePid = row[7]self.getbookchapter(bookId,chapterId,catePid,None,None)def getbookchapter(self,bookId,chapterId,catePid,wordNum,createTime):header = {"User-Agent":'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'}url = "https://book.zongheng.com/chapter/"+str(bookId)+"/"+str(chapterId)+".html"response = requests.get(url,headers = header)time.sleep(0.1)selector = parsel.Selector(response.text)#获取书名warp = selector.xpath('//div[@id="reader_warp"]/div/a[3]/text()').get()#获取章节chapter = selector.xpath('//div[@class="title_txtbox"]/text()').get()#获取作者auto = selector.xpath('//div[@class="bookinfo"]/a[1]/text()').get()#获取内容readers = selector.xpath('//div[@class="reader_box"]/div[@class="content"]/p')reader = ''for reader_line in readers:readerl = reader_line.xpath('./text()').get()reader +=readerl+'\n'#print(reader)if self.islose == 0:self.sql.sqlquery = (str(uuid.uuid4()), warp, auto, chapter,reader,bookId,chapterId,createTime,self.date,catePid,wordNum,)#保存入库self.sql.sql_insert()elif self.islose == 1:self.sql.sqlquery = (warp,auto,chapter,reader,bookId,chapterId,)#补录数据self.sql.sql_update()if __name__=='__main__':app = QtWidgets.QApplication(sys.argv)apply_stylesheet(app, theme='dark_teal.xml')# 实例化页面并展示demo_win = mainstart()demo_win.gettree()demo_win.show()sys.exit(app.exec_())app.sql.con.close()

bookQThread.py 多线程调用(下载功能)

由于图形页面需要一些耗时的操作,需要处理成异步任务否则页面就会卡死,此处使用了pyqt自带的多线程模块。

import PyQt5.QtCore as QtCore
import timeclass downQThread(QtCore.QThread):  signal =QtCore.pyqtSignal(int)def __init__(self, *args, **kwargs):super(downQThread, self).__init__()self.main_win = kwargs.get('mainstart')self.signal.connect(self.refresh)def run(self):self.main_win.getbook()print('任务执行中'+self.main_win.bookname)def refresh(self, m):self.main_win.progressBar.setValue(m)

sqlFactory.py (sql文件)

这块没啥好说的就是简单的CRUD,数据库采用的轻量级sqlite。好处是迁移方便,直接把db文件拷走就可以读取。不熟悉的可以搜索下,安装包我也上传了。

import sqlite3
#数据库操作类
class sqlFactory:sqlquery = Nonedef __init__(self):self.con = sqlite3.connect('book.db',timeout=10, check_same_thread=False)# dict_factoryの定義def dict_factory(cursor, row):d = {}for idx, col in enumerate(cursor.description):d[col[0]] = row[idx]return ddef sql_insert(self):cursorObj = self.con.cursor()sql = '''INSERT INTO book(id,title,auto,chapter,content,bookId,chapterId,createTime,inserttime,catePid,wordNum) VALUES(?,?,?,?,?,?,?,?,?,?,?);'''cursorObj.execute(sql,self.sqlquery)self.con.commit()#print(self.sqlquery[0])#print(self.sqlquery[3]+'添加成功!' if (self.sqlquery[3] is not None and self.sqlquery[3]!= '') else self.sqlquery[0]+'添加成功!')def sql_selectchapter(self):cursorObj = self.con.cursor()cursorObj.execute('SELECT * FROM book where bookId = ? and chapterId = ?',self.sqlquery)rows = cursorObj.fetchone()return rowsdef sql_selectbook(self):cursorObj = self.con.cursor()cursorObj.execute('SELECT bookId,title,auto FROM book group by bookId,title,auto ')rows = cursorObj.fetchall()return rowsdef sql_select(self):#self.con.row_factory = sqlFactory.dict_factorycursorObj = self.con.cursor()cursorObj.execute('SELECT chapter,chapterId,auto,title,content FROM book where bookId = ? order by catePid ',self.sqlquery)rows = cursorObj.fetchall()return rowsdef sql_selectlose(self):cursorObj = self.con.cursor()cursorObj.execute('SELECT * FROM book where title is null and auto is null')rows = cursorObj.fetchall()return rowsdef sql_update(self):cursorObj = self.con.cursor()cursorObj.execute('update book set title = ?,auto =?,chapter = ?,content = ? where  bookId = ? and chapterId = ?',self.sqlquery)self.con.commit()print(str(self.sqlquery[0])+str(self.sqlquery[2])+'补录成功!')def sql_delbook(self):cursorObj = self.con.cursor()sql = '''delete from book where bookId = ? '''cursorObj.execute(sql,self.sqlquery)self.con.commit()print(str(self.sqlquery[0])+'删除成功!')def sql_delbookchapter(self):cursorObj = self.con.cursor()sql = '''delete from book where bookId = ?  and chapterId = ?'''cursorObj.execute(sql,self.sqlquery)self.con.commit()print(str(self.sqlquery[1])+'删除成功!')def sql_delorinert(self):cursorObj = self.con.cursor()sql = '''delete from book where bookId = ?  and chapterId =(select chapterId from book where bookId = ?  order by createTime DESC limit 1);'''cursorObj.execute(sql,self.sqlquery)self.con.commit()print(str(self.sqlquery[1])+'最新一篇删除成功!')if __name__=='__main__':aa = sqlFactory()aa.sqlquery = ('1212','asdas',)aa.sql_select()print(aa)

Ui_rebook.py (ui页面)

from PyQt5 import QtCore, QtGui, QtWidgetsclass Ui_MainWindow(object):def setupUi(self, MainWindow):MainWindow.setObjectName("MainWindow")MainWindow.setEnabled(True)MainWindow.resize(800, 600)MainWindow.setMinimumSize(QtCore.QSize(800, 2))MainWindow.setMaximumSize(QtCore.QSize(800, 600))MainWindow.setAutoFillBackground(False)self.centralwidget = QtWidgets.QWidget(MainWindow)self.centralwidget.setMinimumSize(QtCore.QSize(800, 600))self.centralwidget.setMaximumSize(QtCore.QSize(800, 600))self.centralwidget.setObjectName("centralwidget")self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.centralwidget)self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)self.verticalLayout_2.setSpacing(1)self.verticalLayout_2.setObjectName("verticalLayout_2")self.horizontalLayout = QtWidgets.QHBoxLayout()self.horizontalLayout.setSpacing(1)self.horizontalLayout.setObjectName("horizontalLayout")self.label = QtWidgets.QLabel(self.centralwidget)self.label.setAlignment(QtCore.Qt.AlignCenter)self.label.setObjectName("label")self.horizontalLayout.addWidget(self.label)self.pushButton_8 = QtWidgets.QPushButton(self.centralwidget)self.pushButton_8.setMaximumSize(QtCore.QSize(30, 30))self.pushButton_8.setObjectName("pushButton_8")self.horizontalLayout.addWidget(self.pushButton_8)self.pushButton = QtWidgets.QPushButton(self.centralwidget)self.pushButton.setEnabled(True)self.pushButton.setMaximumSize(QtCore.QSize(30, 30))self.pushButton.setIconSize(QtCore.QSize(10, 10))self.pushButton.setObjectName("pushButton")self.horizontalLayout.addWidget(self.pushButton)self.verticalLayout_2.addLayout(self.horizontalLayout)self.tabWidget = QtWidgets.QTabWidget(self.centralwidget)self.tabWidget.setEnabled(True)self.tabWidget.setMinimumSize(QtCore.QSize(0, 2))self.tabWidget.setTabBarAutoHide(False)self.tabWidget.setObjectName("tabWidget")self.tab = QtWidgets.QWidget()self.tab.setObjectName("tab")self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.tab)self.verticalLayout_5.setContentsMargins(0, 0, 0, 11)self.verticalLayout_5.setSpacing(1)self.verticalLayout_5.setObjectName("verticalLayout_5")self.horizontalLayout_2 = QtWidgets.QHBoxLayout()self.horizontalLayout_2.setSpacing(0)self.horizontalLayout_2.setObjectName("horizontalLayout_2")self.comboBox_2 = QtWidgets.QComboBox(self.tab)self.comboBox_2.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))self.comboBox_2.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)self.comboBox_2.setObjectName("comboBox_2")self.comboBox_2.addItem("")self.comboBox_2.addItem("")self.horizontalLayout_2.addWidget(self.comboBox_2)self.lineEdit = QtWidgets.QLineEdit(self.tab)self.lineEdit.setObjectName("lineEdit")self.horizontalLayout_2.addWidget(self.lineEdit)self.pushButton_2 = QtWidgets.QPushButton(self.tab)self.pushButton_2.setMinimumSize(QtCore.QSize(60, 0))self.pushButton_2.setMaximumSize(QtCore.QSize(15, 25))self.pushButton_2.setObjectName("pushButton_2")self.horizontalLayout_2.addWidget(self.pushButton_2)self.pushButton_3 = QtWidgets.QPushButton(self.tab)self.pushButton_3.setMinimumSize(QtCore.QSize(60, 0))self.pushButton_3.setMaximumSize(QtCore.QSize(60, 25))self.pushButton_3.setObjectName("pushButton_3")self.horizontalLayout_2.addWidget(self.pushButton_3)self.verticalLayout_5.addLayout(self.horizontalLayout_2)self.tableWidget = QtWidgets.QTableWidget(self.tab)self.tableWidget.setLineWidth(1)self.tableWidget.setObjectName("tableWidget")self.tableWidget.setColumnCount(0)self.tableWidget.setRowCount(0)self.verticalLayout_5.addWidget(self.tableWidget)self.verticalLayout = QtWidgets.QVBoxLayout()self.verticalLayout.setSpacing(1)self.verticalLayout.setObjectName("verticalLayout")self.horizontalLayout_6 = QtWidgets.QHBoxLayout()self.horizontalLayout_6.setSpacing(1)self.horizontalLayout_6.setObjectName("horizontalLayout_6")self.progressBar = QtWidgets.QProgressBar(self.tab)self.progressBar.setProperty("value", 24)self.progressBar.setObjectName("progressBar")self.horizontalLayout_6.addWidget(self.progressBar)self.pushButton_9 = QtWidgets.QPushButton(self.tab)self.pushButton_9.setEnabled(False)self.pushButton_9.setMinimumSize(QtCore.QSize(100, 0))self.pushButton_9.setMaximumSize(QtCore.QSize(100, 25))self.pushButton_9.setObjectName("pushButton_9")self.horizontalLayout_6.addWidget(self.pushButton_9)self.verticalLayout.addLayout(self.horizontalLayout_6)self.verticalLayout_5.addLayout(self.verticalLayout)self.horizontalLayout_8 = QtWidgets.QHBoxLayout()self.horizontalLayout_8.setSpacing(1)self.horizontalLayout_8.setObjectName("horizontalLayout_8")spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)self.horizontalLayout_8.addItem(spacerItem)self.label_2 = QtWidgets.QLabel(self.tab)self.label_2.setText("")self.label_2.setObjectName("label_2")self.horizontalLayout_8.addWidget(self.label_2)spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)self.horizontalLayout_8.addItem(spacerItem1)self.verticalLayout_5.addLayout(self.horizontalLayout_8)self.tabWidget.addTab(self.tab, "")self.tab_2 = QtWidgets.QWidget()self.tab_2.setObjectName("tab_2")self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.tab_2)self.verticalLayout_6.setObjectName("verticalLayout_6")self.horizontalLayout_3 = QtWidgets.QHBoxLayout()self.horizontalLayout_3.setSpacing(0)self.horizontalLayout_3.setObjectName("horizontalLayout_3")self.pushButton_6 = QtWidgets.QPushButton(self.tab_2)self.pushButton_6.setMaximumSize(QtCore.QSize(16777215, 20))self.pushButton_6.setObjectName("pushButton_6")self.horizontalLayout_3.addWidget(self.pushButton_6)self.pushButton_7 = QtWidgets.QPushButton(self.tab_2)self.pushButton_7.setMaximumSize(QtCore.QSize(16777215, 20))self.pushButton_7.setObjectName("pushButton_7")self.horizontalLayout_3.addWidget(self.pushButton_7)spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)self.horizontalLayout_3.addItem(spacerItem2)self.comboBox = QtWidgets.QComboBox(self.tab_2)self.comboBox.setMaximumSize(QtCore.QSize(16777215, 20))self.comboBox.setCurrentText("")self.comboBox.setObjectName("comboBox")self.horizontalLayout_3.addWidget(self.comboBox)self.verticalLayout_6.addLayout(self.horizontalLayout_3)self.horizontalLayout_4 = QtWidgets.QHBoxLayout()self.horizontalLayout_4.setContentsMargins(-1, -1, -1, 10)self.horizontalLayout_4.setSpacing(1)self.horizontalLayout_4.setObjectName("horizontalLayout_4")self.treeWidget = QtWidgets.QTreeWidget(self.tab_2)self.treeWidget.setObjectName("treeWidget")self.treeWidget.headerItem().setText(0, "1")self.horizontalLayout_4.addWidget(self.treeWidget)self.verticalLayout_4 = QtWidgets.QVBoxLayout()self.verticalLayout_4.setSpacing(1)self.verticalLayout_4.setObjectName("verticalLayout_4")self.textEdit = QtWidgets.QTextEdit(self.tab_2)self.textEdit.setObjectName("textEdit")self.verticalLayout_4.addWidget(self.textEdit)self.horizontalLayout_5 = QtWidgets.QHBoxLayout()self.horizontalLayout_5.setSpacing(4)self.horizontalLayout_5.setObjectName("horizontalLayout_5")self.pushButton_5 = QtWidgets.QPushButton(self.tab_2)self.pushButton_5.setObjectName("pushButton_5")self.horizontalLayout_5.addWidget(self.pushButton_5)spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)self.horizontalLayout_5.addItem(spacerItem3)self.pushButton_4 = QtWidgets.QPushButton(self.tab_2)self.pushButton_4.setObjectName("pushButton_4")self.horizontalLayout_5.addWidget(self.pushButton_4)self.verticalLayout_4.addLayout(self.horizontalLayout_5)self.horizontalLayout_4.addLayout(self.verticalLayout_4)self.horizontalLayout_4.setStretch(1, 2)self.verticalLayout_6.addLayout(self.horizontalLayout_4)self.verticalLayout_3 = QtWidgets.QVBoxLayout()self.verticalLayout_3.setSpacing(11)self.verticalLayout_3.setObjectName("verticalLayout_3")self.horizontalSlider = QtWidgets.QSlider(self.tab_2)self.horizontalSlider.setOrientation(QtCore.Qt.Horizontal)self.horizontalSlider.setObjectName("horizontalSlider")self.verticalLayout_3.addWidget(self.horizontalSlider)self.horizontalLayout_7 = QtWidgets.QHBoxLayout()self.horizontalLayout_7.setContentsMargins(-1, -1, -1, 20)self.horizontalLayout_7.setObjectName("horizontalLayout_7")self.label_3 = QtWidgets.QLabel(self.tab_2)self.label_3.setText("")self.label_3.setObjectName("label_3")self.horizontalLayout_7.addWidget(self.label_3)spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)self.horizontalLayout_7.addItem(spacerItem4)self.pushButton_10 = QtWidgets.QPushButton(self.tab_2)self.pushButton_10.setEnabled(False)self.pushButton_10.setMaximumSize(QtCore.QSize(16777215, 25))self.pushButton_10.setObjectName("pushButton_10")self.horizontalLayout_7.addWidget(self.pushButton_10)self.pushButton_11 = QtWidgets.QPushButton(self.tab_2)self.pushButton_11.setEnabled(False)self.pushButton_11.setMaximumSize(QtCore.QSize(16777215, 25))self.pushButton_11.setObjectName("pushButton_11")self.horizontalLayout_7.addWidget(self.pushButton_11)self.pushButton_12 = QtWidgets.QPushButton(self.tab_2)self.pushButton_12.setEnabled(False)self.pushButton_12.setMaximumSize(QtCore.QSize(16777215, 25))self.pushButton_12.setObjectName("pushButton_12")self.horizontalLayout_7.addWidget(self.pushButton_12)spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)self.horizontalLayout_7.addItem(spacerItem5)self.label_4 = QtWidgets.QLabel(self.tab_2)self.label_4.setText("")self.label_4.setObjectName("label_4")self.horizontalLayout_7.addWidget(self.label_4)self.verticalLayout_3.addLayout(self.horizontalLayout_7)self.verticalLayout_6.addLayout(self.verticalLayout_3)self.tabWidget.addTab(self.tab_2, "")self.verticalLayout_2.addWidget(self.tabWidget)MainWindow.setCentralWidget(self.centralwidget)self.statusbar = QtWidgets.QStatusBar(MainWindow)self.statusbar.setObjectName("statusbar")MainWindow.setStatusBar(self.statusbar)self.retranslateUi(MainWindow)self.tabWidget.setCurrentIndex(1)self.tabWidget.currentChanged['int'].connect(self.tabWidget.setCurrentIndex)QtCore.QMetaObject.connectSlotsByName(MainWindow)def retranslateUi(self, MainWindow):_translate = QtCore.QCoreApplication.translateMainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))self.label.setText(_translate("MainWindow", "小说搜索阅读器"))self.pushButton_8.setText(_translate("MainWindow", "-"))self.pushButton.setText(_translate("MainWindow", "X"))self.comboBox_2.setItemText(0, _translate("MainWindow", "线路一"))self.comboBox_2.setItemText(1, _translate("MainWindow", "线路二"))self.pushButton_2.setText(_translate("MainWindow", "搜索"))self.pushButton_3.setText(_translate("MainWindow", "重置"))self.pushButton_9.setText(_translate("MainWindow", "取消下载"))self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "搜索小说"))self.pushButton_6.setText(_translate("MainWindow", "展示/收起"))self.pushButton_7.setText(_translate("MainWindow", "刷新"))self.pushButton_5.setText(_translate("MainWindow", "上一章"))self.pushButton_4.setText(_translate("MainWindow", "下一章"))self.pushButton_10.setText(_translate("MainWindow", "小说转语音"))self.pushButton_11.setText(_translate("MainWindow", "播放"))self.pushButton_12.setText(_translate("MainWindow", "暂停"))self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "阅读小说"))

下载地址

https://download.csdn.net/download/vnfgh4/87579164

python +pyqt 小说下载阅读器 转语音合成 ,基于PyQt5生成图形页面(已打成exe可直接下载使用)相关推荐

  1. 小说下载阅读器_初始简单版

    小说下载阅读器_初始简单版 相信园子里面的很多人和我一样喜欢阅读小说,下面是这几年用的比较多一点的阅读器,功能相对完整. Windows本地程序/手机 1.http://www.mybook66.co ...

  2. 小说下载阅读器 官网

    Welcome to my blog! <script language="javascript" src="http://avss.b15.cnwg.cn/cou ...

  3. CSDN11期 软件创新 :小说下载阅读器 点评

    首先,"点评"只是个人看法,只是技术上的讨论,不带有褒贬色彩. 原项目在这里 http://chuang.csdn.net/mybook66 这是一个 小说下载阅读器 1.支持各小 ...

  4. Delphi 10.4.2 轻松实现Android/IOS txt小说电子书阅读器应用APP翻页效果

    Delphi 10.4.2是最新版本的跨平台本机应用开发工具,一套代码可编译到五个操作系统上:iOS.Android.Windows.macOS 和 Linux: 本代码仅仅数十行即可轻松实现Andr ...

  5. 基于PyQt5和requests的小说在线阅读器(小说爬虫)

    效果: 绝对布局 无章节预加载 在不关闭的情况下再次搜索存在bug 代码: python部分: import sys from PyQt5.QtGui import QIcon from PyQt5. ...

  6. Adobe Reader阅读器打开时显示上次看到的页面

    Adobe Reader阅读器打开时显示上次看到的页面 编辑-->首选项-->启动-->第二项(重新打开文档到上次启动的页面)中选择"所有文件" 即可!~ 转载于 ...

  7. 《OpenCv视觉之眼》Python图像处理二十三:OpenCV图像处理最终章之基于PyQt5的图像处理界面设计及功能实现

    本专栏主要介绍如果通过OpenCv-Python进行图像处理,通过原理理解OpenCv-Python的函数处理原型,在具体情况中,针对不同的图像进行不同等级的.不同方法的处理,以达到对图像进行去噪.锐 ...

  8. 用安卓手机看小说,阅读器APP怎么选

    安卓手机上看小说,有很多种阅读APP供大家选择.作为小说爱好者,经过多款测评,选出以下小说阅读器,体验相对较好,推荐给喜欢在手机上看小说的朋友们. 第一款:Neat Reader 这款阅读器界面设计比 ...

  9. 用Windows电脑看txt小说,阅读器软件怎么选

    Windows电脑上有哪些好用的TXT阅读器?综合来看,以下小说阅读器,体验相对较好.这些阅读器都支持TXT EPUB等常见小说格式. Top1:Neat Reader Neat Reader这款阅读 ...

最新文章

  1. python中bin是什么意思_Python之一、#!/usr/bin/python到底是什么意思
  2. qt tounicode 崩溃_吐槽大会丨细数那些打块的崩溃瞬间!看看你中了几枪?
  3. python摄像头人脸识别代码_python 实现摄像头人脸识别
  4. 【数据库题型大总结】简答题总结
  5. python dict方法_python dict()方法学习笔记
  6. IE报告“存储空间不足,无法完成此操作”的原因
  7. Windows10系统下PaddleOCR文本检测和文本识别安装
  8. Spring 2.5配置文件详解
  9. 博客linux系统下载器,linux的下载工具
  10. windows下 robocopy命令
  11. 城市供水调度平台(Axure高保真原型)
  12. 计算机组成原理实验数据通路,《计算机组成原理》实验报告——数据通路
  13. Java一步到位!彻底了解JDK、JRE、JVM分别是什么及它们之间的联系
  14. 怎样找一张图片的原图、出处?最全搜图网站+具体案例分享
  15. HTML header 标签的用法
  16. php1蛋白质带电情况,拿到一个蛋白以后,首先需要对蛋白进行全面的了解,所谓知彼知己方能百战不殆:...
  17. Linux基础命令(2)
  18. excel批量翻译-excel怎么批量翻译
  19. matlab铁路平板车装货问题,用数学建模解决两辆铁路平板车的装货问题
  20. L298N驱动模块电路图

热门文章

  1. ZYNQ7000搭建嵌入式Linux操作系统---增加PL端外设(以太网)篇
  2. mysql连接错误码1040,mySQL错误1040:太多连接
  3. keil5软件添加芯片
  4. OpenGL ES:视频加滤镜后导出
  5. 基于微信小程序外卖点餐系统小程序 系统的设计与实现 开题报告和效果图
  6. 关于微信小程序上传,在微信公众平台|小程序中找不到上传的代码
  7. 无线传输最远可以传输距离_无线电源传输的梦想可能很快成为现实
  8. springsecurity默认用户名密码_Spring Security概述
  9. 设计模式——状态模式(State Pattern)
  10. 以下构成python循环结构的方法中正确的是_关于Python循环结构,以下选项中描述错误的是...