Flask制作-奇葩玩转电子书

文摘   科技   2024-01-16 19:09   北京  


ISEE小语


    昔日立誓远离烟,如今烟雾伴身边。狂言不变的你,怎能敌得过生活的变迁呢?




    看书的时候,突然有一个奇葩有意思的想法,将电子书解析到数据库中,前端搜索曾经看到过的金句,就可以找到出自哪本书、哪个章节,甚至是定位到准备的位置。

    挺有意思的,可以试试看!



环境:

Pycharm

Python 3.9.16



安装:

pip install 以下所有的包

alembic==1.13.1beautifulsoup4==4.12.2blinker==1.7.0EbookLib==0.18Flask==2.3.1Flask-Migrate==4.0.4Flask-SQLAlchemy==3.0.5greenlet==3.0.3itsdangerous==2.1.2lxml==5.1.0Mako==1.3.0six==1.16.0soupsieve==2.5SQLAlchemy==2.0.25typing_extensions==4.9.0Werkzeug==3.0.1




实现原理:

    使用Flask+SQLAlchemy,主要特点是方便、简单、快速,最重要的一点就是前面文章分享过基本使用,不需要使用多的时间去研究了!

    主要包括三大块: 

    一、解析电子书并保存到数据库

    二、服务端查询和返回逻辑实现

    三、前端页面查询入口及返回显示


项目结构:

新创建一个Flask项目,具体结构如下:

```结构book_read_flask├─instance  # 项目初始化的数据库文件│  └─database.db  # Sqlite数据库├─templates  # 静态模板文件│  └─index.html  # 搜索页面├─static  # 样式文件├─app.py  # 应用├─config.py  # 数据库链接配置├─models.py  # 数据库表结构├─requirements.txt  # 依赖包文件└─一句顶一万句.epub  # 电子书```



解析电子书

    解析电子书,用到了EbookLib和beautifulsoup4这两个三方库。

    EbookLib是一个用于处理电子书文件的Python第三方库。它提供了一组简单易用的API,可以用于读取、解析和操作常见的电子书格式,如EPUB、MOBI和AZW3等。

    BeautifulSoup是用于从HTML或XML文档中提取数据的工具。EbookLib解析出来的源文会带有html标签,需要再次进行数据处理

    本次解析的是【刘震云】老师的《一句顶一万句》,epub格式。

# -*- coding: utf-8 -*-import ebooklibfrom bs4 import BeautifulSoupfrom ebooklib import epub
book_name = '一句顶一万句.epub'author = '刘震云'introduction = '作家'
# 读取EPUB文件book_content = epub.read_epub(book_name)# 遍历电子书中的所有项目for item in book_content.get_items(): if item.get_type() == ebooklib.ITEM_DOCUMENT: # 使用BeautifulSoup解析HTML内容 soup = BeautifulSoup(item.get_content(), 'html.parser') chapter_tag = soup.find('h1') chapter_text = chapter_tag.get_text(separator=' ', strip=True) if chapter_tag is not None else '' if chapter_text != '': print("章节:", chapter_text) print(soup.get_text())

(左右滑动查看完整代码)

创建Flask项目

    数据库选择的是Sqlite。

    框架是Flask+SQLAlchemy。

    首先,创建一个Flask项目,设计两个数据表books和books_detail,在项目根目录下新建models.py

from flask_sqlalchemy import SQLAlchemyfrom sqlalchemy.orm import relationshipfrom datetime import datetime
db = SQLAlchemy()

class Books(db.Model): __tablename__ = 'books'
id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50)) author = db.Column(db.String(20)) introduction = db.Column(db.Text) add_time = db.Column(db.String(255), default=datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
details = relationship('BookDetail', back_populates='book')

class BookDetail(db.Model): __tablename__ = 'books_detail'
id = db.Column(db.Integer, primary_key=True) book_id = db.Column(db.Integer, db.ForeignKey('books.id')) chapter = db.Column(db.String(255)) content = db.Column(db.Text) add_time = db.Column(db.String(255), default=datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
book = relationship('Books', back_populates='details')

(左右滑动查看完整代码)


    然后,配置数据库链接,在项目根目录下新建config.py

# -*- coding: utf-8 -*-
# 连接数据库SQLALCHEMY_DATABASE_URI = 'sqlite:///database.db'SQLALCHEMY_TRACK_MODIFICATIONS = False

(左右滑动查看完整代码)


    最后,在应用app.py中创建init_app初化数据库,以及创建Migrate

from flask import Flaskfrom flask_migrate import Migratefrom models import dbimport config
app = Flask(__name__)app.config.from_object(config)
db.init_app(app)
with app.app_context(): db.create_all()migrate = Migrate(app, db)

@app.route('/')def hello(): return 'hello world!'

if __name__ == '__main__': app.run(host='0.0.0.0')

(左右滑动查看完整代码)

    运行app.py,启动项目,在项目根目录下将自动创建instance文件夹,其中database.db被初始化成功创建。

如果当Models发生变更时,更新表结构是常规性的操作。

在终端中进入项目目录,并执行命令初始化数据库迁移

flask db init


执行命令生成数据库迁移脚本

flask db migrate -m "Initial migration"


执行命令应用数据库迁移:

flask db upgrade


最后重启Flask应用后,就可以看到Models的变更已经反映在数据库表结构中


电子书写入DB

    解析电子书完成后,我们按章节存到数据库中。

    app.py中构造一个read_epud函数

@app.route('/read_epud')def read_epud():    book_name = '一句顶一万句.epub'    author = '刘震云'    introduction = '作家'    # 检查书籍是否存在    book_exist = db.session.query(Books.query.filter_by(name=book_name).exists()).scalar()    if not book_exist:        book_ = Books(name=book_name, author=author, introduction=introduction)        db.session.add(book_)        db.session.commit()
# 读取EPUB文件 book_content = epub.read_epub(book_name) book = Books.query.filter_by(name=book_name).first() # 检查书箱详细内容是否存在 book_detail_exist = db.session.query(BookDetail.query.filter_by(book_id=book.id).exists()).scalar() if not book_detail_exist: # 遍历电子书中的所有项目 for item in book_content.get_items(): if item.get_type() == ebooklib.ITEM_DOCUMENT: # 使用BeautifulSoup解析HTML内容 soup = BeautifulSoup(item.get_content(), 'html.parser') chapter_tag = soup.find('h1') chapter_text = chapter_tag.get_text(separator=' ', strip=True) if chapter_tag is not None else '' if chapter_text != '': book_detail = BookDetail(chapter=chapter_text, content=soup.get_text(), book_id=book.id) # 将新的书籍详情对象添加到会话中 db.session.add(book_detail) # 提交会话,将新的书籍详情对象插入到数据库中 db.session.commit()
return '电子书解析入库成功!'

(左右滑动查看完整代码)


    启动服务,打开浏览器,运行网址:

http://127.0.0.1:5000/read_epud

说明调用电子书解析入库已经成功!

注:这个地方的电子书没有做传参,如果换其他电子书写入,需要在源码中修改,

    book_name = '一句顶一万句.epub'    author = '刘震云'    introduction = '作家'

后期抽时间再做优化!


指定内容搜索

    电子书存到数据库后,接下来我们就进行指定的内容搜索。

    app.py中构造一个sentence_search函数

@app.route('/sentence_search', methods=['GET'])def sentence_search():    sentence = request.args.get('sentence', '')    if not sentence:        return jsonify([{'sentence': '请输入搜索的内容!', 'book_name': '', 'book_author': '', 'book_chapter': '',                         'chapter_content': ''}])
    # 查询包含特定内容的书籍信息 book_details = BookDetail.query.join(Books).filter(BookDetail.content.contains(sentence)).all()
# 创建book_list返回结果 book_list = [ { 'sentence': sentence, 'book_name': book_detail.book.name, 'book_author': book_detail.book.author, 'book_chapter': book_detail.chapter, 'chapter_content': book_detail.content } for book_detail in book_details ]
return jsonify(book_list)

(左右滑动查看完整代码)


    启动服务,打开浏览器,运行网址:

http://127.0.0.1:5000/sentence_search?sentence=

说明调用电子书指定内容搜索接口是成功的。

    

设计前端搜索页面

    设计一个前端页面,指定的内容搜索框及返回内容显示。

    templates文件夹中新建一个index.html页面,页面主体如下(样式太多就不全贴了,有兴趣的看源码):

<body>    <div class="Search_content">        <div class="Search_input__1">            <i class="fas fa-search"></i>            <input type="search" id="search_id" value="" placeholder="请输入内容">        </div>        <button class="Search_btn" id="go_search">去找寻</button>    </div>    <div class="Output_box">        <div class="label_class">出自:</div>        <div id="output"></div>    </div></body>

(左右滑动查看完整代码)

    服务返回内容处理及显示:

<script>    document.getElementById('go_search').addEventListener('click', function() {        const searchInput = document.getElementById('search_id').value;
// 发送请求到后端 const xhr = new XMLHttpRequest(); xhr.open('GET', '/sentence_search?sentence=' + searchInput, true); xhr.onreadystatechange = function() { if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) { const responses = JSON.parse(xhr.responseText);
// 清空之前的内容 document.getElementById('output').innerHTML = '';
// 遍历每个返回的 JSON 数据对象 responses.forEach(function(response) { // 创建显示的元素 const element = document.createElement('div'); element.innerHTML = ` <div class="sentence">搜索:${response.sentence}</div> <div class="book_name">出自:${response.book_name}</div> <div class="author">作者:${response.book_author}</div> <div class="chapter">章节:${response.book_chapter}</div> 章节内容:<div class="chapter_content">${highlightSentence(response.chapter_content)}</div> <div>-----------------------------</div> `; // 添加到输出框中 document.getElementById('output').appendChild(element); }); } }; xhr.send(); });
function highlightSentence(content) { const searchInput = document.getElementById('search_id').value; const regex = new RegExp(searchInput, 'gi'); const replacedContent = content.replace(regex, '<span class="highlight">$&</span>'); const replacedWithBreaks = replacedContent.replace(/\n/g, '<br>'); return replacedWithBreaks; }</script>

(左右滑动查看完整代码)    


    服务添加路由,调用index.html页面:

@app.route('/')def index():    return render_template('index.html', chart_html='')

    

启动服务,打开浏览器,运行网址:

http://127.0.0.1:5000

成功!

接下来输入搜索内容,看看实际效果:


总结

    这个小项目前端页面有点单调,在处理上也可能会有些Bug,但不会有大的影响,后续再丰富吧。

    本次除了解析电子书《一句顶一万句》,还解析了《影响力》,解析、入库、搜索都正常。

    这两本电子书也会一同分享出来,有兴趣的也可以看看书,这两本书其实还挺不错的!



点个“”和“在看”,是对小栈最大的支持!

后台回复“book_read”即可获取源码和电子书!


     

文章就分享到这儿,喜欢就点个吧!



推荐阅读  点击标题可跳转


ISEE小栈
没有花里胡哨,简单才是王道。
 最新文章