昨非 发表于 2021-4-22 19:26:42

基于爬虫和PyQt5的【小说阅读器】

本帖最后由 昨非 于 2021-4-22 21:22 编辑



前言:摸爬滚打、现学现卖,总算是做出了基本框架
先分享出来,希望大家帮忙找找bug
由于从一开始构思就是一个人凭空想出来的,没有项目作参考
所以可能有许多不规范的设计,希望大家指点一下
后续会努力完善的


最后插个广告:求顶!求分享!求评分!
能不能贡献破300就靠诸位了
老规矩,撒币加热度(虽然效果越来越差了)






【咳咳,麻烦教教我那个演示动态图是怎么做的,我这low爆了】

一、初次运行,首先弹出书架供选择,当然如果是空的,下面提供了按钮,懂得都懂哈
https://z3.ax1x.com/2021/04/22/cL7bRA.png

二、选择小说后,跳转到相应的章节目录供选择
https://z3.ax1x.com/2021/04/22/cL7OMt.png

三、之后打开的主页面
https://z3.ax1x.com/2021/04/22/cLHCGj.png

四、菜单栏添加新书的输入框
https://z3.ax1x.com/2021/04/22/cL7jqf.png

五、一个么的卵用的小窗口(刷一下存在感哈哈)
https://z3.ax1x.com/2021/04/22/cLHSIg.png

六、菜单栏调用书架
https://z3.ax1x.com/2021/04/22/cLHkMq.png

七、菜单栏调用章节列表
https://z3.ax1x.com/2021/04/22/cL7xZ8.png

八、下方状态栏信息显示(没啥大用哈)
https://z3.ax1x.com/2021/04/22/cL7XsP.png

总结:有部分界面测试条件比较特殊(如异常提醒等)就不贴出来了
当然,还有很多奇奇怪怪的情况没有考虑到,就拜托大家帮忙找找了
欢迎评论指出



文字描述就算了
编辑费劲,大家看着也费劲
三张图,应该能解释的差不多了

一、整体框架结果
https://z3.ax1x.com/2021/04/22/cL7zdS.png




二、主窗口设计
https://z3.ax1x.com/2021/04/22/cLqFbV.png

三、爬虫部分框架
https://z3.ax1x.com/2021/04/22/cLH9iQ.png






一、主窗口Interface.py

import sys,os,re
from lxml import html
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QIcon,QFont
# 自定义界面
import modules.inputNovel as inputNovel
import modules.showVersion as showVersion
import modules.chapterList as chapterList
import modules.bookList as bookList
import modules.reminders as reminders
from find_novel_list import FindNovelList

#阅读器主页面
class QinterFace(QMainWindow):
    def __init__(self):
      super().__init__()
      self.novelName = None
      self.chapterNum = None
      self.allNum_of_novel = None
      self.chapterNames = []
      self.root = os.getcwd()# 获取主题程序的工作目录

      self.initUI()
      # 初始化时需要首次选择 小说 和 章节 作为首次打开的依据
      main_bL_first = bookList.QbookList()
      main_bL_first.Signal_of_novelName.connect(self.get_nn_from_bl)
      main_bL_first.exec()
      while self.novelName == None:#初次未选择小说,循环打开书架
            main_bL_second = bookList.QbookList()
            main_bL_second.Signal_of_novelName.connect(self.get_nn_from_bl)
            main_bL_second.exec()
      main_cL_first = chapterList.QchapterList(self.novelName)
      main_cL_first.Signal_of_c_num.connect(self.get_cn_from_cl)
      main_cL_first.Signal_of_chapterNames.connect(self.get_cnames_from_cl)
      main_cL_first.Signal_of_all_num.connect(self.get_allnum_from_cl)
      main_cL_first.exec()
      while self.chapterNum == None:
            main_cL_second = chapterList.QchapterList(self.novelName)
            main_cL_second.Signal_of_c_num.connect(self.get_cn_from_cl)
            main_cL_second.Signal_of_chapterNames.connect(self.get_cnames_from_cl)
            main_cL_second.Signal_of_all_num.connect(self.get_allnum_from_cl)
            main_cL_second.exec()

      # 为保证“章节名称”和内容随章节索引同步刷新,需要读取出章节列表
      self.showTheTxt(self.novelName, self.chapterNum) #刷新文本内容

    def initUI(self):
      self.setFixedSize(800, 975)# 固定窗口大小
      self.setWindowTitle('小说阅读器')# 设置窗口标题
      self.setWindowIcon(QIcon('./images/book.ico'))# 图标设置
      # 居中
      screen = QDesktopWidget().screenGeometry()
      size = self.geometry()
      self.move((screen.width() - size.width()) / 2,0)

      # 1、菜单栏及其功能设置
      bar = self.menuBar()# 获取菜单栏
      chapterList = bar.addMenu("章节目录")
      novelList = bar.addMenu("我的书架")
      showMsg = bar.addMenu("显示信息")
      novelReaderhelp = bar.addMenu("帮助")

      inputNewNovel = QAction("添加新书",self)# 必加self
      novelList.addAction(inputNewNovel)
      inputNewNovel.triggered.connect(self.inputNewBook)# 事件绑定

      catalog = QAction('查看目录',self)
      chapterList.addAction(catalog)
      catalog.triggered.connect(self.chapterList)

      bookshelf = QAction("查看书架",self)
      novelList.addAction(bookshelf)
      bookshelf.triggered.connect(self.bookList)

      statusMsg = QAction("显示当前小说信息",self)
      showMsg.addAction(statusMsg)
      statusMsg.triggered.connect(self.showStatusbar)

      version = QAction("Version",self)
      novelReaderhelp.addAction(version)
      version.triggered.connect(self.version)

      # 2、界面主体的设置(章节名称+内容+前后章跳转按钮)
      self.cNamebutton = QPushButton(self)
      self.cNamebutton.setEnabled(False)
      self.cNamebutton.setGeometry(0,25,800,30)
      self.cNamebutton.setFont(QFont('微软雅黑',12))
      self.textEdit = QTextEdit(self)
      self.textEdit.setGeometry(0,55,800,870)
      self.textEdit.setFont(QFont('楷体',12))

      self.pre_button = QPushButton(self)
      self.pre_button.setGeometry(0,925,200,25)
      self.pre_button.setText("上一章")
      self.pre_button.clicked.connect(self.preChapter)   # 事件绑定,章节跳转

      self.next_button = QPushButton(self)
      self.next_button.setGeometry(600,925,200,25)
      self.next_button.setText("下一章")

      self.next_button.clicked.connect(self.nextChapter)# 事件绑定,章节跳转

    # 自书架到主窗口的参数传递
    def get_nn_from_bl(self,datastr):
      self.novelName = datastr

    # 自目录到主窗口的参数传递
    def get_cn_from_cl(self,dataint):
      self.chapterNum = dataint

    # 自目录到主窗口的参数传递
    def get_cnames_from_cl(self,datalist):
      self.chapterNames = datalist

    # 自目录到主窗口的参数传递
    def get_allnum_from_cl(self,dataint):
      self.allNum_of_novel = dataint


    # 包括数据解析和主页面文本显示部分(待改动)

    def showTheTxt(self,novel_name,c_num):

      # 1、获取小说内容的先
      if os.getcwd() == self.root:
            os.chdir('./books/' + novel_name + '/chapters')
      elif os.getcwd() == self.root+'./books/':
            os.chdir('./' + novel_name + '/chapters')
      elif os.getcwd() == self.root + './books/' + novel_name:# 新增分支
            os.chdir("./chapters")
      elif os.getcwd() == self.root+'./books/'+ novel_name+'/chapters':
            pass

      file_name = ""
      c_list = os.listdir()
      for item in c_list:
            num_str = ""
            for j in re.findall(r'\d',item):
                num_str += j
            if int(num_str) == c_num+1:
                file_name = item

      if file_name == "":# 注意工作目录的转换
            main_rm = Qreminder_of_download(novel_name)
            os.chdir(self.root)
            main_rm.exec()
      else:
            f = open(file_name, 'r', encoding='utf-8')# 默认顺序尚有问题,暂且不处理
            chapter_html = f.read()

            # 后期处理
            selector = html.fromstring(chapter_html)
            txt_list = selector.xpath('//div[@id = "content"]/text()')

            txt = ''
            for i in txt_list:# 先拼接
                if i != '\n':
                  i = repr(i).replace(r'\xa0', '').replace("'", '')
                  txt += i
            txt = repr(txt).replace("\\n", '\n').replace('\\', '')# 最终处理
            os.chdir(self.root)# 工作目录改回去

         # 2、界面文本显示
            self.cNamebutton.setText(self.chapterNames)# 确保章节名称随索引同步刷新
            self.textEdit.setPlainText(txt)
            self.textEdit.setReadOnly(True)   # 只读设置


    def inputNewBook(self):
      main_iN = inputNovel.QinputNovel()
      main_iN.exec()#以exec()代替show(),避免子窗口闪退

    def chapterList(self):
      main_cL = chapterList.QchapterList(self.novelName)
      main_cL.Signal_of_c_num.connect(self.get_cn_from_cl)
      main_cL.exec()

      self.showTheTxt(self.novelName, self.chapterNum)# 小说切换并选定章节后,刷新文本
    def bookList(self):# 基本搞定
      main_bL = bookList.QbookList()
      main_bL.Signal_of_novelName.connect(self.get_nn_from_bl)
      main_bL.exec()
      main_cL = chapterList.QchapterList(self.novelName)
      main_cL.Signal_of_c_num.connect(self.get_cn_from_cl)
      main_cL.Signal_of_chapterNames.connect(self.get_cnames_from_cl)
      main_cL.Signal_of_all_num.connect(self.get_allnum_from_cl)
      main_cL.exec()
      self.showTheTxt(self.novelName, self.chapterNum)# 小说切换并选定章节后,刷新文本

    def showStatusbar(self):
      self.statusBar = QStatusBar()
      self.setStatusBar(self.statusBar)
      self.statusBar.showMessage('《'+self.novelName+"》共有%d章" % self.allNum_of_novel)
      self.statusBar

    def version(self):
      main_sV = showVersion.Qversion()
      main_sV.exec()

    def preChapter(self):
      if self.chapterNum == 0:
            """
                弹窗提醒:已经是第一章了。
            """
            main_rm = reminders.Qreminder("已经是第一章了")
            main_rm.exec()
      else:
            self.chapterNum -= 1
            self.showTheTxt(self.novelName, self.chapterNum)

    def nextChapter(self):
      if self.chapterNum == self.allNum_of_novel-1:
            """
                弹窗提醒:已经是第一章了。
            """
            main_rm = reminders.Qreminder("已经是最后一章了")
            main_rm.exec()
      else:
            self.chapterNum += 1
            self.showTheTxt(self.novelName, self.chapterNum)

# 继续下载界面
class Qreminder_of_download(QDialog):
    def __init__(self,novelName):
      super().__init__()
      self.novelName = novelName
      self.initUI()

    def initUI(self):
      self.setWindowTitle('阅读提示')
      self.setWindowIcon(QIcon('./images/book.ico'))
      self.setFixedSize(300,180)
      vLabel1 = QLabel(self)
      vLabel1.setText("此章节尚未下载")
      vLabel1.setFont(QFont("宋体",10))
      vLabel1.setGeometry(90,30,120,20)

      vLabel2 = QLabel(self)
      vLabel2.setText("是否继续下载?")
      vLabel2.setFont(QFont("宋体", 10))
      vLabel2.setGeometry(90, 70, 120, 20)

      btn_OK = QPushButton('确定',self)
      btn_OK.setGeometry(50,110,60,30)
      btn_Cancel = QPushButton('取消',self)
      btn_Cancel.setGeometry(190, 110, 60, 30)

      # 事件绑定
      btn_OK.clicked.connect(self.onClick_Ok)
      btn_Cancel.clicked.connect(self.onClick_Cancel)

    def onClick_Ok(self):
      """
            此处为多线程爬虫模块的调用
      """
      inputNovel.Runspyder(self.novelName)
      self.close()

    def onClick_Cancel(self):
      self.close()

if __name__=="__main__":
    #检测novel_list.json是否存在
    if 'novel_list.json' not in os.listdir():
      FindNovelList()
    app = QApplication(sys.argv)
    mainW = QinterFace()
    mainW.show()
    sys.exit(app.exec_())




二、辅助爬虫find_novel_list.py
from lxml import etree
import requests
from fake_useragent import UserAgent
import json
def FindNovelList():
    url = "http://www.xbiquge.la/xiaoshuodaquan/"

    headers = {
      "User-Agent": UserAgent().chrome
    }
    response = requests.get(url, headers=headers)
    e = etree.HTML(response.text)# 返回字符串
    #由网页源码而定
    names = e.xpath('//a/text()')
    urls = e.xpath('//a/@href')

    novel_list = []
    novel = {}
    for name,url in zip(names,urls):
      novel=url
      novel_list.append(novel)
      novel = {}
    with open('novel_list.json','w',encoding='utf-8') as f:
      f.write(json.dumps(novel_list,ensure_ascii=False))





三、自定义模块——bookList.py

from PyQt5.QtWidgets import *
from PyQt5.QtGui import QIcon,QFont
from PyQt5.QtCore import QStringListModel,Qt,pyqtSignal
import sys,os

# 自定义模块
if __name__=="__main__":
    import inputNovel
else:
    import modules.inputNovel as inputNovel

# 对应小说搜索框界面
class QbookList(QDialog):
    Signal_of_novelName = pyqtSignal(str)
    def __init__(self):
      super().__init__()
      self.newNovel = None
      self.initUI()

    def initUI(self):
      self.setWindowTitle('我的书架')
      if __name__ == "__main__":
            self.setWindowIcon(QIcon('../images/book.ico'))
      else:
            self.setWindowIcon(QIcon("./images/book.ico"))
      self.setFixedSize(300, 600)

      layout = QVBoxLayout()

      # 创捷列表组件
      listview = QListView()
      listModel = QStringListModel()
      if __name__ == "__main__":
            os.chdir("../books")
      else:
            os.chdir("./books")

      # 小说数目显示标签
      bookNum = len(os.listdir())
      booknumLable = QLabel("共有%d本书" % bookNum)
      booknumLable.setFont(QFont("宋体", 12))
      self.b_list = os.listdir()
      listModel.setStringList(self.b_list)

      listview.setModel(listModel)
      listview.setFont(QFont('楷体',13))
      listview.clicked.connect(self.clicked)

      inputButton = QPushButton()
      inputButton.setText("添加新书")
      inputButton.clicked.connect(self.inputNewbook)# 按钮事件绑定

      # 加入垂直布局
      booknumLable.setAlignment(Qt.AlignCenter)
      layout.addWidget(booknumLable)
      layout.addWidget(listview)
      layout.addWidget(inputButton)

      self.setLayout(layout)
      os.chdir("..")

    def clicked(self,item):
      QMessageBox.information(self,"小说选择","是否跳转到:" + self.b_list) # 考虑修改(O/C)
      self.Signal_of_novelName.emit(self.b_list)
      self.close()

    def inputNewbook(self):
      inputnew = inputNovel.QinputNovel()
      inputnew.exec()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = QbookList()
    main.show()
    sys.exit(app.exec_())






四、自定义模块——chapterList.py

from PyQt5.QtWidgets import *
from PyQt5.QtCore import QStringListModel,pyqtSignal
from PyQt5.QtGui import QIcon,QFont
import sys,os,json

class QchapterList(QDialog):
    Signal_of_c_num = pyqtSignal(int)
    Signal_of_all_num = pyqtSignal(int)
    Signal_of_chapterNames = pyqtSignal(list)

    def __init__(self,novelName):
      super().__init__()
      self.novelName = novelName
      self.all_num = None
      self.initUI()

    def initUI(self):
      self.setWindowTitle(self.novelName+"章节目录")
      if __name__ == "__main__":
            self.setWindowIcon(QIcon('../images/book.ico'))
      else:
            self.setWindowIcon(QIcon("./images/book.ico"))
      self.setFixedSize(400, 800)
      layout = QVBoxLayout()
      # 创捷列表组件
      listview = QListView()
      listModel = QStringListModel()
      self.c_list = []
      if __name__ == "__main__":
            os.chdir("../books/"+self.novelName)
      else:
            os.chdir("./books/"+self.novelName)

      with open("chapter_list.json", mode='r', encoding="utf-8") as f:
            chapters = json.loads(f.read())# 注:read读取出来的时字符串,需要转为json对象
            for chapter in chapters:
                c_name = (str(chapter).split(":", 1))
                self.c_list.append(c_name)

      self.all_num = len(self.c_list)
      listModel.setStringList(self.c_list)

      listview.setModel(listModel)
      listview.setFont(QFont("楷体",11))
      listview.clicked.connect(self.clicked)
      layout.addWidget(listview)

      self.setLayout(layout)
      os.chdir("..")
      os.chdir("..")

    def clicked(self,item):
      QMessageBox.information(self,self.novelName,"是否跳转到:" + self.c_list)
      self.Signal_of_c_num.emit(item.row())
      self.Signal_of_chapterNames.emit(self.c_list)
      self.Signal_of_all_num.emit(self.all_num)
      self.close()

if __name__ == "__main__":
    novelName = "斗破苍穹"
    app = QApplication(sys.argv)
    win = QchapterList(novelName)
    win.show()
    sys.exit(app.exec_())






五、自定义模块——inputNovel.py

from PyQt5.QtWidgets import *
from PyQt5.QtGui import QIcon,QFont
from lxml import etree
import requests
from fake_useragent import UserAgent
import json,os,sys
from pathlib import Path
from threading import Thread #多线程
from queue import PriorityQueue,Queue #优先队列 普通队列
#自定义库
try:
    from reminders import Qreminder
except:
    from modules.reminders import Qreminder

# 对应小说搜索框界面
class QinputNovel(QDialog):
    def __init__(self):
      super().__init__()
      self.newNovel = None
      self.initUI()

    def initUI(self):
      self.setWindowTitle('请输入小说名称')
      self.setWindowIcon(QIcon('./images/book.ico'))
      self.setFixedSize(280,160)
      nameLabel = QLabel('名称:',self)
      nameLabel.setFont(QFont("宋体",12))
      self.nameLineEdit = QLineEdit(self)# 必须设为类属性才能由onClick_Ok访问输入内容

      btnOK = QPushButton('确定')
      btnCancel = QPushButton('取消')
      #栅格布局
      mainLayout = QGridLayout(self)
      mainLayout.addWidget(nameLabel,0,0,2,2)
      mainLayout.addWidget(self.nameLineEdit,0,1,2,2)

      mainLayout.addWidget(btnOK,2,1)
      mainLayout.addWidget(btnCancel,2,2)

      #事件绑定
      btnOK.clicked.connect(self.onClick_Ok)
      btnCancel.clicked.connect(self.onClick_Cancel)

    def onClick_Ok(self):
      self.newNovel = self.nameLineEdit.text()
      """
            此处为多线程爬虫模块的调用(必要的报错窗口必须有)
      """
      Runspyder(self.newNovel)#调用
      self.close()

    def onClick_Cancel(self):
      self.close()

# 请求头
headers = {
    "User-Agent": UserAgent().chrome
}

# 据小说名保存章节列表
def find_chapter_list(novel_name,url):
    response = requests.get(url, headers=headers)
    e = etree.HTML(response.content.decode('utf-8'))# 返回字符串
    # 由网页源码而定
    chapter_names = e.xpath('//div[@class="box_con"]/div[@id="list"]/dl/dd/a/text()')
    urls = e.xpath('//div[@class="box_con"]/div[@id="list"]/dl/dd/a/@href')

    chapter_list = []
    chapter = {}
    for name,url in zip(chapter_names,urls):
      chapter = 'http://www.xbiquge.la'+url
      chapter_list.append(chapter)
      chapter={}

    os.chdir(novel_name) # 切换目录
    with open('chapter_list.json','w',encoding='utf-8') as f:
      f.write(json.dumps(chapter_list,ensure_ascii=False))

# 读取小说章节列表,规范处理后保存到优先队列里,将队列返回
def getChapterUrl():
    chapters_queue = PriorityQueue()
    # 为网页源码的保存建立文件夹
    my_file = Path('chapters')
    if not my_file.exists():# 判断路径是否存在
      os.mkdir('chapters')
    with open("chapter_list.json", mode='r', encoding="utf-8") as f:
      chapters = json.loads(f.read())# 注:read读取出来的时字符串,需要转为json对象

    os.chdir('./chapters')# 切换目录
    i = 0# 计数器,用以规范章节序号
    for chapter in chapters:# 由于字典键值不可哈希,所以转为字符串处理
      c_name_f = (str(chapter).split(":", 1))
      c_url = (str(chapter).split(":", 1))

      try:
            c1, c2 = c_name_f.split(" ")# 规范章节序号,很关键
      except ValueError:
            c2 = "无题(或违规标题)"# 防止章节名称为空

      finally:
            if c2[-1] in ['?', '!','*']:# 排除特殊字符
                c2 = c2[:-1]
            if c2 in ['?',"!",'*']:
                c2 = c2
            c_name = '第' + str(i + 1) + '章 ' + c2 + ".html"
            chapters_queue.put((i,c_name,c_url))# 以i排序
      i += 1
    return chapters_queue


class GetHtml(Thread):
    def __init__(self,chapters_queue):
      Thread.__init__(self)
      self.chapters_queue = chapters_queue

    def run(self):
      while self.chapters_queue.empty() == False:
            this_chapter =self.chapters_queue.get()
            if this_chapter not in os.listdir(): #避免重复下载
                response = requests.get(this_chapter, headers=headers)
                if response.status_code == 200:
                  response = response.content.decode("utf-8")
                  with open(this_chapter, 'w', encoding="utf-8") as f:
                        f.write(response)
                        print('正在写入第' + str(this_chapter + 1) + '章')

            else:
                print(this_chapter,"已存在")
      print('下载完成')


def Runspyder(n_name):
    url = ''
    if __name__ =="__main__":
      with open("../novel_list.json", mode='r', encoding="utf-8") as f:
            novels = json.loads(f.read())# 注:read读取出来的时字符串,需要转为json对象
    else:
      with open("novel_list.json", mode='r', encoding="utf-8") as f:
            novels = json.loads(f.read())# 注:read读取出来的时字符串,需要转为json对象

    for novel in novels:
      if n_name in novel:
            url = novel
            if __name__ == "__main__":
                os.chdir('../books')
            else:
                os.chdir('./books')
            my_file = Path(n_name)
            if not my_file.exists():# 判断路径是否存在
                os.mkdir(n_name)
            break
      else: #不是当前小说
            continue
    else:
      main_rm = Qreminder('Sorry!您所搜索的小说不存在!')
      main_rm.exec()
    if url != '':
      find_chapter_list(n_name, url)
      print('小说目录加载完成!')
      chapters_queue = getChapterUrl()
      print('小说目录队列加载完成!')

      # 创建各个爬虫
      crawl_list = []

      for i in range(0, 20):
            crawl1 = GetHtml(chapters_queue)
            crawl_list.append(crawl1)
            crawl1.start()
      for crawl in crawl_list:
            crawl.join()# 阻塞

      main_rm = Qreminder('全部下载结束!')
      print("下载完后的工作目录:",os.getcwd())
      os.chdir('..')
      os.chdir('..')
      os.chdir('..')# 将工作目录改回去
      main_rm.exec()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = QinputNovel()
    main.show()
    sys.exit(app.exec_())




六、自定义模块——reminders.py

from PyQt5.QtWidgets import *
from PyQt5.QtGui import QIcon,QFont
from PyQt5.QtCore import Qt
import sys

# 对应各种小提示弹窗界面
class Qreminder(QDialog):
    def __init__(self,tips):
      super().__init__()
      self.tips = tips
      self.initUI()

    def initUI(self):
      self.setWindowTitle('阅读提示')
      self.setWindowIcon(QIcon('./images/book.ico'))
      self.setFixedSize(280,120)
      vLabel = QLabel(self.tips,self)
      vLabel.setAlignment(Qt.AlignCenter)
      vLabel.setFont(QFont("宋体",10))
      # 垂直布局
      mainLayout = QVBoxLayout(self)
      mainLayout.addWidget(vLabel)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    tips = "这是一条提示!"
    main = Qreminder(tips)
    main.show()
    sys.exit(app.exec_())



七、自定义模块——showVersion.py

from PyQt5.QtWidgets import *
from PyQt5.QtGui import QIcon,QFont
from PyQt5.QtCore import Qt
import sys

#对应小说搜索框界面
class Qversion(QDialog):
    def __init__(self):
      super().__init__()
      self.initUI()

    def initUI(self):
      self.setWindowTitle('关于阅读器')
      self.setWindowIcon(QIcon('./images/book.ico'))
      self.setFixedSize(280,120)
      vLabel = QLabel('当前版本:1.0',self)
      author = QLabel("@author: 昨非",self)
      vLabel.setAlignment(Qt.AlignCenter)
      author.setAlignment(Qt.AlignCenter)
      vLabel.setFont(QFont("宋体",12))
      author.setFont(QFont("宋体", 12))
      # 垂直布局
      mainLayout = QVBoxLayout(self)
      mainLayout.addWidget(vLabel)
      mainLayout.addWidget(author)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = Qversion()
    main.show()
    sys.exit(app.exec_())





给大家的压缩包是最“纯净”的版本
没有任何保存的小说和爬取小说小说的范围
(部分文件的不存在情况之前也考虑到了,我这边测试暂时没问题)
当然,我的考虑不一定全面,如有问题,还请大家及时通知哈
由于整体尚未完成,所以就没有打包exe,大家用得自己运行啦

注:1、各模块是支持单独运行的,但请先保证自己./book文件夹下有运行需要的东西
如有不合理的bug,欢迎指出,评分奖励
2、由于爬取范围尚未扩展,大家测试时还是尽量以下图中的小说为依据吧,不然很容易找不到
https://z3.ax1x.com/2021/04/22/cLj6wq.png


昨非 发表于 2021-4-23 19:52:31

捞一手

昨非 发表于 2021-4-23 22:15:48

@小甲鱼 这个可以申精吗

hornwong 发表于 2021-4-22 21:18:59

感谢分享!

yayc_zcyd 发表于 2021-4-22 21:25:10

嘿,我最近正在学pyqt5,感觉挺好玩的{:10_256:}

昨非 发表于 2021-4-22 21:26:08

yayc_zcyd 发表于 2021-4-22 21:25
嘿,我最近正在学pyqt5,感觉挺好玩的

我这纯是现学现卖,加油加油

yayc_zcyd 发表于 2021-4-22 21:26:58

昨非,把pycharm背景交出来{:10_256:}

昨非 发表于 2021-4-22 21:27:14

本帖最后由 昨非 于 2021-4-22 21:28 编辑

yayc_zcyd 发表于 2021-4-22 21:26
昨非,把pycharm背景交出来

啊这

yayc_zcyd 发表于 2021-4-22 21:27:28

昨非 发表于 2021-4-22 21:27
啊这

{:10_256:}

yayc_zcyd 发表于 2021-4-22 21:28:33

我问个问题,啥时候能评贡献啊{:10_245:}

yayc_zcyd 发表于 2021-4-22 21:29:03

昨非 发表于 2021-4-22 21:27
啊这

图片名称好评{:10_256:}

昨非 发表于 2021-4-22 21:29:14

yayc_zcyd 发表于 2021-4-22 21:28
我问个问题,啥时候能评贡献啊

暂时只有VIP可以好像
不过不强求的,心意到了,没事的{:10_297:}

hrp 发表于 2021-4-22 21:56:32

学习

yuedong 发表于 2021-4-22 22:01:57

1

昨非 发表于 2021-4-22 22:09:17

hrp 发表于 2021-4-22 21:56
学习

不敢当,闻道有先后,我刚开始学这个

yuedong 发表于 2021-4-22 23:23:16

。点错了

rsj0315 发表于 2021-4-23 08:21:59

学习学习

rsj0315 发表于 2021-4-23 09:08:22

测试了一下,下载的时候,每次下载一个,对话框就关闭了。
想要继续下载,还需要再次运行ide。

还有一个是,在下载的时候,是多线程在运行没问题,但是那个对话框是显示未响应的。(不影响使用)

昨非 发表于 2021-4-23 09:11:23

rsj0315 发表于 2021-4-23 09:08
测试了一下,下载的时候,每次下载一个,对话框就关闭了。
想要继续下载,还需要再次运行ide。



继续下载第二本建议再次菜单栏打开“添加新书”,如果不设置自动关闭,会有更多问题,至于下载进度条提示,我尝试过,暂时还搞不定{:10_266:}

昨非 发表于 2021-4-23 09:12:17

rsj0315 发表于 2021-4-23 09:08
测试了一下,下载的时候,每次下载一个,对话框就关闭了。
想要继续下载,还需要再次运行ide。



这个我会考虑的,谢谢提示(主要现在想法还不太成熟哈)
页: [1] 2 3 4 5 6 7 8 9 10
查看完整版本: 基于爬虫和PyQt5的【小说阅读器】