【PyQt6】小说下载DrissionPage及阅读PyQt6

2024-02-25 22:44

本文主要是介绍【PyQt6】小说下载DrissionPage及阅读PyQt6,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 1 简介
  • 2 DrissionPage
    • demo
  • 3 阅读界面
    • 3.1 Qt Designer
  • 3.2 界面类
  • 总结
  • 2024年2月25日 更新

1 简介

看到一本小说 《无敌六皇子》 【https://www.xsobiquge.org/book/178299/】看小说简介觉得挺有意思的,想读一读。浏览器阅读 不能保存进度,就好烦。想着就爬下来,本地看。

看着挺简单的网站,requests 就只能爬个目录页,分章内容总是被拒,UA Refer Cookie 以及所有的请求头都加了,也没有效果,最终还是回到浏览器去,此时 DrissionPage 就用上了。

2 DrissionPage

DrissionPage 号称同时实现“写得快”和“跑得快”,试过以后还真是巨方便。
DrissionPage 的教程我就略过不谈了,网上有总结的,感谢哪些前辈们的分享。
我就直接分享一下 具体的爬虫代码吧, 代码量真的很少

demo

from DrissionPage import SessionPage
import os
import time
import random
import re# 创建页面对象
page = SessionPage()subpages = []reg = r"第(\d+)章.*"
pat = re.compile(reg)def formatTitle(title):match = pat.search(title)if match:idx = match.group(1)res = title.replace(idx, f'{idx:0>4}')return resreturn titledef download_catalog(url):page.get(start_url)# 根据 xpath 或 css selector 查找xpath = '//*[@id="list"]/dl/dd'lists = page.eles(f'xpath:{xpath}')for li in lists:a = li.ele('tag:a')href = a.attr('href')title = a.texttitle = formatTitle(title)# print(a.attr('href'), a.text)subpages.append({'href': href, 'title': title})print(f'{url} 下载完成')def download_chapter():for i in range(min_chapters-1, max_chapters):dic = subpages[i]time.sleep(random.random() * 2)ret = page.get(dic['href'])if not ret:print(ret)return# //*[@id="content"]xpath = '//*[@id="content"]'elem = page.ele(f'xpath:{xpath}')context = elem.textwith open(f"{dic['title']}.txt", 'w', encoding='utf-8') as f:lines = context.splitlines()for line in lines:line = line.strip()if line == '网页版章节内容慢,请下载爱阅小说app阅读最新内容':breakif line:f.write('\t'+line+'\n')print(f'{dic['title']} 下载完成')if __name__ == '__main__':book_name = "无敌六皇子"start_url = 'https://www.xsobiquge.org/book/178299/'min_chapters = 401max_chapters = 600if not os.path.exists(book_name):os.mkdir(book_name)download_catalog(start_url)os.chdir(book_name)download_chapter()

3 阅读界面

小说的分章终于保存到了本地,txt 格式,直接使用 VSC 看,那个阅读体验真的不好。于是就顺手写了一个阅读器,大体上就是用 QTextEdit 来阅读,调整一下字体大小,行高,宽度,上一章 下一章的功能,基本就能满足要求,阅读进度使用 json 保存
在这里插入图片描述

3.1 Qt Designer

用 Designer 简单写个界面,东西很少,看图就明白

加载页面使用 self.ui = load_ui.loadUi(“Novel.ui”, self)
这种方式有利于看界面效果,但没代码提示,写代码不友好
建议界面定型后,使用 pyuic6 把ui文件转成 py文件,再导入
在这里插入图片描述
在这里插入图片描述

3.2 界面类

界面类,这一部分也没啥东西,直接上代码看吧

from PyQt6.QtCore import QTimer, QSettings, Qt
from PyQt6.QtGui import QCloseEvent, QKeyEvent, QPalette, QColor
from PyQt6.QtWidgets import (QMainWindow,QWidget,QApplication,QFileDialog,QSplitter,QStyleFactory,
)
from PyQt6.uic import load_ui
import os
import jsonclass MainWindow(QMainWindow):# ================= 构造函数 =============================def __init__(self, parent: QWidget = None):super().__init__(parent)# --------------------------------- 加载界面 -------------------------------------------self.ui = load_ui.loadUi("Novel.ui", self)# --------------------------------- 设置属性 -------------------------------------------self.dir_path = Noneself.filename = Noneself.verBar = 0# --------------------------------- 设置 splitter -------------------------------------splitter = self.ui.splittersplitter.setStretchFactor(0, 1)splitter.setStretchFactor(1, 4)splitter.setHandleWidth(1)# --------------------------------- 设置 菜单项  -------------------------------------opd = self.ui.opendir_actopd.triggered.connect(self.opendir_act_triggered)# -- 设置 QListWidget 文件目录listw = self.ui.listWidgetlistw.currentTextChanged.connect(self.currentFileChanged)# -----------------设置 QPlainTextEdit 文件阅读区 -------------------------------------pte = self.ui.plainTextEditfont = pte.font()font.setFamily("楷体")font.setPointSize(30)pte.setFont(font)pte.setReadOnly(True)# pte.setViewportMargins(0, 10, 0, 10)# -- 导入设置数据       -------------------------------------------------------if not os.path.exists("data.txt"):returnwith open("data.txt", "r", encoding="utf-8") as f:dic = json.loads(f.read())self.dir_path = dic["path"]self.file = dic["file"]font.setPointSize(dic["pointSize"])pte.setFont(font)self.verBar = dic["verBar"]self.update_listWidget()# -- 链接信号# pte.cursorPositionChanged.connect(self.cursorPositionChanged)# pte.verticalScrollBar().valueChanged.connect(self.cursorPositionChanged)def cursorPositionChanged(self, value):pte = self.ui.plainTextEdit# pte.verticalScrollBar().blockSignals(True)max = pte.verticalScrollBar().maximum()if max - value > 50:value -= 50else:value = maxpte.verticalScrollBar().setValue(value)# def f():#     pte.verticalScrollBar().blockSignals(False)# QTimer.singleShot(100, f)passdef update_listWidget(self):listw = self.ui.listWidgetlistw.blockSignals(True)# 保存当前目录cur_dir = os.getcwd()os.chdir(self.dir_path)files = os.listdir(self.dir_path)if not files:returnlistw.clear()listw.addItems(files)# 切换回当前目录os.chdir(cur_dir)def f():listw.setCurrentItem(None)listw.blockSignals(False)idx = files.index(self.file)listw.setCurrentRow(idx)QTimer.singleShot(100, f)def opendir_act_triggered(self):self.dir_path = QFileDialog.getExistingDirectory()if self.dir_path:listw = self.ui.listWidgetlistw.blockSignals(True)# 保存当前目录cur_dir = os.getcwd()os.chdir(self.dir_path)files = os.listdir(self.dir_path)if not files:returnfiles = [file for file in files if os.path.isfile(file) and file != "data.txt"]listw.clear()listw.addItems(files)# 切换回当前目录os.chdir(cur_dir)def f():listw.setCurrentItem(None)listw.blockSignals(False)QTimer.singleShot(100, f)def currentFileChanged(self, file):self.setWindowTitle(file)self.filename = filepte = self.ui.plainTextEdit# 保存当前目录cur_dir = os.getcwd()os.chdir(self.dir_path)with open(file, "r", encoding="utf-8") as f:lines = f.readlines()os.chdir(cur_dir)# text_cursor = QTextCursor()pte.clear()text_cursor = pte.textCursor()width = pte.width()TextBlockFormat = text_cursor.blockFormat()TextBlockFormat.setLeftMargin(width * 0.1)TextBlockFormat.setRightMargin(width * 0.1)TextBlockFormat.setBottomMargin(50)TextBlockFormat.setLineHeight(150, 1)TextBlockFormat.setTextIndent(20 * 4)text_cursor.setBlockFormat(TextBlockFormat)for line in lines:text_cursor.insertText(line.strip() + "\n")pte.verticalScrollBar().setValue(self.verBar)def closeEvent(self, a0: QCloseEvent) -> None:pte = self.ui.plainTextEditif self.filename:pte = self.ui.plainTextEditfont = pte.font()dict = {"path": self.dir_path,"file": self.filename,"pointSize": font.pointSize(),"verBar": pte.verticalScrollBar().value(),}# os.chdir(self.dir_path)with open("data.txt", "w", encoding="utf-8") as f:f.write(json.dumps(dict, ensure_ascii=False))# 保存 self.ui.splitter 的状态splitter_saveState(self.ui.splitter)return super().closeEvent(a0)def keyReleaseEvent(self, a0: QKeyEvent) -> None:# print('*'*20)pte = self.ui.plainTextEditmatch a0.key():# 上一章case Qt.Key.Key_Left:nextrow = self.ui.listWidget.currentRow() - 1if nextrow > -1:self.ui.listWidget.setCurrentRow(nextrow)# self.verBar = 0pte.verticalScrollBar().setValue(0)a0.accept()# 下一章case Qt.Key.Key_Right:nextrow = self.ui.listWidget.currentRow() + 1if nextrow < self.ui.listWidget.count():self.ui.listWidget.setCurrentRow(nextrow)self.verBar = 0pte.verticalScrollBar().setValue(0)a0.accept()return super().keyReleaseEvent(a0)def splitter_restoreState(splitter: QSplitter):set = QSettings("splitterSizes", QSettings.Format.IniFormat)splitter.restoreState(set.value("splitterSizes"))def splitter_saveState(splitter: QSplitter):set = QSettings("splitterSizes", QSettings.Format.IniFormat)set.setValue("splitterSizes", splitter.saveState())if __name__ == "__main__":qApp = QApplication([])qApp.setStyle(QStyleFactory.create("fusion"))palette = qApp.palette()palette.setColor(QPalette.ColorRole.Base, QColor(31, 31, 31))palette.setColor(QPalette.ColorRole.Text, QColor(78, 201, 176))palette.setColor(QPalette.ColorRole.Window, QColor(43, 43, 43))palette.setColor(QPalette.ColorRole.Highlight, QColor(38, 79, 120))palette.setColor(QPalette.ColorRole.HighlightedText, QColor(255, 255, 255))palette.setColor(QPalette.ColorRole.ButtonText, QColor(204, 204, 204))qApp.setPalette(palette)mw = MainWindow()mw.showMaximized()splitter_restoreState(mw.ui.splitter)qApp.exec()

总结

到此这个阅读器也就能马马虎虎的使用了,翻页的时候不太友好,因为 QTextEdit 翻页的时候,默认翻的是viewport 的大小,对于文字来说,有时会卡半行,真想重写 QTextEdit 的空格键啊,有机会再说。
最后再说一句 Python 真的很方便啊,能随手写写小工具

2024年2月25日 更新

阅读器代码有了更新, QTextEdit 加了 事件过滤器, 重写了 空格键, 翻页的时候少移动 30像素, 另外如果页面到底自动下一章功能

我一直还在想 怎么把 QEvent类 转成 QKeyEvent , 结果完全没有必要, 只要事件类型是 keypress ,就直接当 QKeyEvent 用

代码就不发了, 发链接吧

小说爬虫

这篇关于【PyQt6】小说下载DrissionPage及阅读PyQt6的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/746936

相关文章

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

常用的jdk下载地址

jdk下载地址 安装方式可以看之前的博客: mac安装jdk oracle 版本:https://www.oracle.com/java/technologies/downloads/ Eclipse Temurin版本:https://adoptium.net/zh-CN/temurin/releases/ 阿里版本: github:https://github.com/

论文阅读笔记: Segment Anything

文章目录 Segment Anything摘要引言任务模型数据引擎数据集负责任的人工智能 Segment Anything Model图像编码器提示编码器mask解码器解决歧义损失和训练 Segment Anything 论文地址: https://arxiv.org/abs/2304.02643 代码地址:https://github.com/facebookresear

2. 下载rknn-toolkit2项目

官网链接: https://github.com/airockchip/rknn-toolkit2 安装好git:[[1. Git的安装]] 下载项目: git clone https://github.com/airockchip/rknn-toolkit2.git 或者直接去github下载压缩文件,解压即可。

前端form表单+ifarme方式实现大文件下载

// main.jsimport Vue from 'vue';import App from './App.vue';import { downloadTokenFile } from '@/path/to/your/function'; // 替换为您的函数路径// 将 downloadTokenFile 添加到 Vue 原型上Vue.prototype.$downloadTokenF

软件架构模式:5 分钟阅读

原文: https://orkhanscience.medium.com/software-architecture-patterns-5-mins-read-e9e3c8eb47d2 软件架构模式:5 分钟阅读 当有人潜入软件工程世界时,有一天他需要学习软件架构模式的基础知识。当我刚接触编码时,我不知道从哪里获得简要介绍现有架构模式的资源,这样它就不会太详细和混乱,而是非常抽象和易

【干货分享】基于SSM的体育场管理系统的开题报告(附源码下载地址)

中秋送好礼 中秋佳节将至,祝福大家中秋快乐,阖家幸福。本期免费分享毕业设计作品:《基于SSM的体育场管理系统》。 基于SSM的体育场管理系统的开题报告 一、课题背景与意义 随着全民健身理念的深入人心,体育场已成为广大师生和社区居民进行体育锻炼的重要场所。然而,传统的体育场管理方式存在诸多问题,如资源分配不均、预约流程繁琐、数据统计不准确等,严重影响了体育场的使用效率和用户体验。

Tomcat下载压缩包解压后应有如下文件结构

1、bin:存放启动和关闭Tomcat的命令的路径。 2、conf:存放Tomcat的配置,所有的Tomcat的配置都在该路径下设置。 3、lib:存放Tomcat服务器的核心类库(JAR文件),如果需要扩展Tomcat功能,也可将第三方类库复制到该路径下。 4、logs:这是一个空路径,该路径用于保存Tomcat每次运行后产生的日志。 5、temp:保存Web应用运行过程中生成的临时文件

下载/保存/读取 文件,并转成流输出

最近对文件的操作又熟悉了下;现在记载下来:学习在于 坚持!!!不以细小而不为。 实现的是:文件的下载、文件的保存到SD卡、文件的读取输出String 类型、最后是文件转换成流输出;一整套够用了; 重点: 1:   操作网络要记得开线程; 2:更新网络获取的数据 切记用Handler机制; 3:注意代码的可读性(这里面只是保存到SD卡,在项目中切记要对SD卡的有无做判断,然后再获取路径!)

【阅读文献】一个使用大语言模型的端到端语音概要

摘要 ssum框架(Speech Summarization)为了 从说话人的语音提出对应的文本二题出。 ssum面临的挑战: 控制长语音的输入捕捉 the intricate cross-mdoel mapping 在长语音输入和短文本之间。 ssum端到端模型框架 使用 Q-Former 作为 语音和文本的中介连接 ,并且使用LLMs去从语音特征正确地产生文本。 采取 multi-st