爬虫工作量由小到大的思维转变---<第十一章 Scrapy之sqlalchemy模版和改造(番外)>

前言:

正常的pymysql当然问题不大,但是我个人还是建议:sqlalchemy!  因为他更能让我们把精力放在表单设计上,而不执着于代码本身了.

(-----版权所有。未经作者书面同意,不得转载或用于任何商业用途!----)

正文:

先提供一个基础模版:

表图:
创建表的sql:
CREATE TABLE match_info (
  id INT PRIMARY KEY,
  home_team VARCHAR(30), 

  full_score VARCHAR(8),  

  half_score VARCHAR(8), 

  away_team VARCHAR(30),  

  match_time DATETIME,   
#比赛时间如 '2023-12-15 14:30:00'包括年、月、日、时、分、秒
  league VARCHAR(10),   

  corners VARCHAR(10),   

  zhuangtai INT,    
 #状态,1(完成收录) 0(未开始) -1(数据待补)
  created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
 #修改时间
);
代码:
from datetime import datetime
from sqlalchemy import create_engine, Table, Column, Integer, String, MetaData, DateTime
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import sessionmaker

class MatchInfoCRUD:
    # 初始化类并建立数据库连接
    def __init__(self):
       
        self.db_uri = 'mysql+pymysql://user:password@localhost/mydatabase'  #填入自己的信息:user:password@localhost/mydatabase
        self.engine = create_engine(self.db_uri)  # 使用数据库URI创建引擎
        self.metadata = MetaData()  # 元数据对象用于收集表对象
        # 定义match_info表结构
        self.match_info = Table('match_info', self.metadata,
                                Column('id', Integer, primary_key=True),  # 主键不自增
                                Column('zhuangtai', Integer),  # 整型状态列
                                Column('league', String(10)),  # 长度为10的字符串类型的联赛列
                                Column('match_time', DateTime),  # 日期时间类型的比赛时间列
                                Column('home_team', String(30)),  # 长度为30的字符串类型的主队列
                                Column('full_score', String(8)),  # 长度为8的字符串类型的全场比分列
                                Column('half_score', String(8)),  # 长度为8的字符串类型的半场比分列
                                Column('away_team', String(30)),  # 长度为30的字符串类型的客队列
                                Column('corners', String(10)),  # 长度为10的字符串类型的角球数列
                                )
        self.metadata.create_all(self.engine)  # 在数据库中创建表
        self.Session = sessionmaker(bind=self.engine)  # 创建与数据库会话的会话工厂

    # 创建新的比赛记录
    def create_match(self, match_data):
        session = self.Session()  # 开启新的会话
        try:
            
            # 创建插入对象并插入数据
            insert_object = self.match_info.insert().values(match_data)
            session.execute(insert_object)  # 执行插入操作
            session.commit()  # 提交事务
            print("数据插入成功。")
        except SQLAlchemyError as e:  # 捕获并处理SQLAlchemy异常
            print(f"插入数据时出现问题: {e}")
        finally:
            session.close()  # 关闭会话

    # 读取比赛记录
    def read_match(self, match_id):
         session = self.Session()  # 开启新的会话
        try:
           
            query = session.query(self.match_info).filter_by(id=match_id)  # 创建查询对象
            match = query.first()  # 获取查询结果的第一条记录
            if match:
                return match  # 返回那条记录
            else:
                return None  # 如果没找到记录,返回None
        except SQLAlchemyError as e:
            print(f"读取数据时出现问题: {e}")
        finally:
            session.close()  # 关闭会话

    # 更新比赛记录
    def update_match(self, match_id, update_data):
         session = self.Session()  # 开启新的会话
        try:
           
            query = session.query(self.match_info).filter_by(id=match_id)  # 创建查询对象
            query.update(update_data)  # 执行更新操作
            session.commit()  # 提交事务
            print("数据更新成功。")
        except SQLAlchemyError as e:
            print(f"更新数据时出现问题: {e}")
        finally:
            session.close()  # 关闭会话

    # 删除比赛记录
    def delete_match(self, match_id):
            session = self.Session()  # 开启新的会话
        try:
            
            query = session.query(self.match_info).filter_by(id=match_id)  # 创建查询对象
            match = query.first()  # 获取查询结果的第一条记录
            if match:
                query.delete()  # 如果找到记录则执行删除操作
                session.commit()  # 提交事务
                print("数据删除成功。")
            else:
                print("未找到相应比赛。")
        except SQLAlchemyError as e:
            print(f"删除数据时出现问题: {e}")
        finally:
            session.close()  # 关闭会话


# 创建MatchInfoCRUD的一个实例
crud = MatchInfoCRUD()

# 创建并插入新的比赛记录
match_data = {
    'id': 1,
    'zhuangtai': 1,
    'league': '联赛数据',
    'match_time': datetime(2023, 12, 15, 14, 30),
    'home_team': 'Team A',
    'full_score': '2-1',
    'half_score': '1-0',
    'away_team': 'Team B',
    'corners': '5-4',
}
crud.create_match(match_data)

# 读取id为1的比赛记录
match_record = crud.read_match(1)
if match_record:
    print(f"读取到比赛记录: {match_record}")
else:
    print("没有找到对应的比赛记录。")




说明:

这里是4个基本属性,增删改查!!!  直接调用就好了...

潜在改进点,往下看


优化方案:

  • 1. 异常处理:
    •    - 可以更精细地管理异常。目前代码中出现任何错误都执行同样的处理,实际应用中可能需要对不同的异常类型进行不同的处理。
  • 2. 封装会话管理:
    •    - 代码中反复出现创建和关闭会话的模式,这可以通过上下文管理器或装饰器来优化,减少代码重复并自动管理资源。
  • 3. 返回信息:
    •    - `create_match` 方法和其他修改操作只是简单地打印了结果,现实场景中可能需要将操作结果(如新创建的对象)返回给调用者。
  • 4. 优化查询:
    •    - 在 `delete_match` 方法中,无需先查询再删除。可以直接使用 `.delete()`,如果有必要确保记录存在,可以在删除后检查 `result.rowcount`。
  • 5. 输入检验:
    •    - 创建和更新数据前进行输入有效性检查,防止无效或恶意数据被写入数据库。
  • 6. 代码组织:
    •    - 根据 Python 的约定,长的导入语句可以分行。
    •    - ORM 映射通常使用更高级的 `declarative_base` 系统进行,这有助于简化模型定义。
  • 7. SQLAlchemy ORM 的使用:
    •    - 目前代码使用了 `Table` 对象和底层的 `insert` 方法。可以让SQLAlchemy ORM 的能力进行映射,并且允许使用会话直接操作对象模型!
案例:
from datetime import datetime
from sqlalchemy import create_engine, Column, Integer, String, DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import sessionmaker, scoped_session

# 定义基类
Base = declarative_base()

# 定义 MatchInfo ORM 模型
class MatchInfo(Base):
    __tablename__ = 'match_info'

    id = Column(Integer, primary_key=True)
    home_team = Column(String(30))
    full_score = Column(String(8))
    half_score = Column(String(8))
    away_team = Column(String(30))
    match_time = Column(DateTime)
    league = Column(String(10))
    corners = Column(String(10))
    zhuangtai = Column(Integer)
    created_time = Column(DateTime, default=datetime.now)
    updated_time = Column(DateTime, default=datetime.now, onupdate=datetime.now)

# MatchInfoCRUD 类使用 ORM 模型和会话管理
class MatchInfoCRUD:
    def __init__(self):
        self.db_uri = 'mysql+pymysql://user:password@localhost/mydatabase'
        self.engine = create_engine(self.db_uri)
        Base.metadata.create_all(self.engine)
        self.Session = scoped_session(sessionmaker(bind=self.engine))

    def create_match(self, match_data):
        """创建新的比赛记录"""
        try:
            match = MatchInfo(**match_data)
            self.Session.add(match)
            self.Session.commit()
            print("数据插入成功。")
        except SQLAlchemyError as e:
            self.Session.rollback()
            print(f"插入数据时出现问题: {e}")
        finally:
            self.Session.remove()

    def read_match(self, match_id):
        """读取比赛记录"""
        try:
            match = self.Session.query(MatchInfo).get(match_id)
            return match
        except SQLAlchemyError as e:
            print(f"读取数据时出现问题: {e}")
        finally:
            self.Session.remove()

    def update_match(self, match_id, update_data):
        """更新比赛记录"""
        try:
            match = self.Session.query(MatchInfo).get(match_id)
            for key, value in update_data.items():
                setattr(match, key, value)
            self.Session.commit()
            print("数据更新成功。")
        except SQLAlchemyError as e:
            self.Session.rollback()
            print(f"更新数据时出现问题: {e}")
        finally:
            self.Session.remove()

    def delete_match(self, match_id):
        """删除比赛记录"""
        try:
            match = self.Session.query(MatchInfo).get(match_id)
            if match:
                self.Session.delete(match)
                self.Session.commit()
                print("数据删除成功。")
            else:
                print("未找到相应比赛记录。")
        except SQLAlchemyError as e:
            self.Session.rollback()
            print(f"删除数据时出现问题: {e}")
        finally:
            self.Session.remove()
  1. 使用 declarative_base 来创建 ORM 基础类并定义表结构;
  2. 采用了 scoped_session 以自动管理会话的生命周期,避免手动关闭会话;
  3. 更新 delete_match 方法,现在它会首先尝试获取记录,如果找到则删除,这样还是需要先查询再删除,但这确保了操作的准确性;
  4. 删掉了直接操作 Table 对象,改为使用 ORM 映射的类和实例来管理数据。

接下来对提供的MatchInfoCRUD类进行几个关键方面的优化,包括封装会话管理、优化查询处理,以及使用 SQLAlchemy ORM 更优雅地定义和交互数据库模型。这里需要使用 SQLAlchemy 的声明式基类declarative_base来简化模型定义,以及使用上下文管理器来自动化会话的生命周期管理。

from datetime import datetime
from sqlalchemy import create_engine, Column, Integer, String, DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import sessionmaker, scoped_session

# 使用declarative_base创建ORM模型的基类
Base = declarative_base()

# 定义MatchInfo ORM模型
class MatchInfo(Base):
    __tablename__ = 'match_info'
    id = Column(Integer, primary_key=True)
    zhuangtai = Column(Integer)
    league = Column(String(10))
    match_time = Column(DateTime)
    home_team = Column(String(30))
    full_score = Column(String(8))
    half_score = Column(String(8))
    away_team = Column(String(30))
    corners = Column(String(10))
    created_time = Column(DateTime)
    updated_time = Column(DateTime)

# 自定义上下文管理器,管理数据库会话的生命周期
class DBSessionManager:
    def __init__(self, db_uri):
        self.engine = create_engine(db_uri)
        self.Session = scoped_session(sessionmaker(bind=self.engine, autocommit=False, autoflush=False))

    def __enter__(self):
        self.session = self.Session()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.session.close()

class MatchInfoCRUD:
    # 初始化类并建立数据库连接
    def __init__(self, db_uri):
        self.db_manager = DBSessionManager(db_uri)
        Base.metadata.create_all(self.db_manager.engine)

    # 创建新的比赛记录
    def create_match(self, match_data):
        with self.db_manager as db:
            try:
                match = MatchInfo(**match_data)
                db.session.add(match)
                db.session.commit()
                print("数据插入成功。")
            except SQLAlchemyError as e:
                db.session.rollback()
                print(f"插入数据时出现了问题: {e}")

    # 查询等其他方法同理可以通过db_manager动态管理会话

# 使用新的CRUD接口进行操作
db_uri = 'mysql+pymysql://user:password@localhost/mydatabase'  # 请填入数据库URI
crud = MatchInfoCRUD(db_uri)

match_data = {
    'id': 1,
    'zhuangtai': 1,
    'league': '联赛数据',
    'match_time': datetime(2023, 12, 15, 14, 30),
    'home_team': 'Team A',
    'full_score': '2-1',
    'half_score': '1-0',
    'away_team': 'Team B',
    'corners': '5-4',
    'created_time': datetime.now(),
    'updated_time': datetime.now(),
}

crud.create_match(match_data)

# 后续其他增删改查操作可以类似地实现
  1. 封装会话管理:通过DBSessionManager上下文管理器类来管理会话的开启和关闭,使得对于每个数据库会话,无需重复编写打开和关闭的代码。
  2. 优化查询:利用ORM的能力来直接添加、查询和更新数据,没有使用底层的表和查询语句。
  3. SQLAlchemy ORM 的使用:使用了declarative_base来定义SQLAlchemy ORM模型,从而提供ORM的完全功能,并写了一个ORM类MatchInfo来映射match_info表。

总结:

    一个强大的 Python SQL 工具包和 ORM(对象关系映射器),来改善数据库操作的效率和代码的整洁性。首先定义了一个 ORM 模型来映射数据库表,然后构建了一个管理数据库会话生命周期的上下文管理器。在实际的 CRUD(创建、读取、更新、删除)操作中,直接对 ORM 对象进行操作,而不是执行原始 SQL 语句。这样使得代码更加简洁、容易理解和维护,也更加面向对象。通过这种方式,我们将耗时的数据库管理工作交给 SQLAlchemy,自己就能专注于业务逻辑和数据的设计上了。简而言之,就是让代码更加简洁、高效,同时也降低了出错的几率。

(-----版权所有。未经作者书面同意,不得转载或用于任何商业用途!----)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/251310.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

软件设计师——法律法规(三)

📑前言 本文主要是【法律法规】——软件设计师——法律法规的文章,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是听风与他🥇 ☁️博客首页:CSDN主页听风与他 &#x1f304…

《科技风》期刊发表投稿方式、收稿方向

《科技风》杂志是经国家新闻出版总署批准,河北省科学技术协会主管,河北省科技咨询服务中心主办的国内公开发行的大型综合类科技期刊。 该刊集科技性、前瞻性、创新性和专业性于一体,始终以“把脉科技创新 引领发展风尚”为办刊宗旨&#xff…

ES-脚本

脚本 简单使用 POST product/_update/2 {"script": {"source": "ctx._source.salary1" #将薪水字段的值 1} }预定义变量 POST product/_update/2 {"script": {"lang": "painless","source": "…

Android studio中文汉化教程

相比于jetbrains的软件直接在软件内搜索chinese 就可以找到中文包相比,Android studio需要手动安装,接下来就给大家介绍下如何汉化 一、确认版本号 根据版本下载对应的中文汉化包,如果安装的汉化包版本不对应,可能会导致安装失败。…

升华 RabbitMQ:解锁一致性哈希交换机的奥秘【RabbitMQ 十】

欢迎来到我的博客,代码的世界里,每一行都是一个故事 升华 RabbitMQ:解锁一致性哈希交换机的奥秘【RabbitMQ 十】 前言第一:该插件需求为什么需要一种更智能的消息路由方式?一致性哈希的基本概念: 第二&…

大华 DSS 数字监控系统 itcBulletin SQL 注入漏洞复现

0x01 产品简介 大华 DSS 数字监控系统是大华开发的一款安防视频监控系统,拥有实时监视、云台操作、录像回放、报警处理、设备管理等功能。 0x02 漏洞概述 大华 DSS存在SQL注入漏洞,攻击者 /portal/services/itcBulletin 路由发送特殊构造的数据包,利用报错注入获取数据库…

WPF-UI HandyControl 控件简单实战

文章目录 前言UserControl简单使用新建项目直接新建项目初始化UserControlGeometry:矢量图形额外Icon导入最优解决方案 按钮Button切换按钮ToggleButton默认按钮图片可切换按钮加载按钮切换按钮 单选按钮和复选按钮没有太大特点,就不展开写了总结 DataGrid数据表格G…

【机器学习】044_Kaggle房价预测(机器学习模型实战)

参考自《动手学深度学习》中“Kaggle比赛实战:预测房价”一节 一、数据准备 首先从网站上下载要获取的房价数据。 DATA_HUB是一个字典,用来将数据集名称的字符串和数据集相关的二元组一一对应。 二元组包含两个值:数据集的URL和用来验证文…

基于linux系统的Tomcat+Mysql+Jdk环境搭建(二)jdk1.8 linux 上传到MobaXterm 工具的已有session里

【JDK安装】 1.首先下载一个JDK版本 官网地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 下载1.8版本,用红框标注出来了: 也许有的同学看到没有1.8版本,你可以随便下载一个linux的…

本地运行大语言模型并可视化(Ollama+big-AGI方案)

目前有两种方案支持本地部署,两种方案都是基于llamacpp。其中 Ollama 目前只支持 Mac,LM Studio目前支持 Mac 和 Windows。 LM Studio:https://lmstudio.ai/ Ollama:https://ollama.ai/download 本文以 Ollama 为例 step1 首先下…

限流常用算法以及基于Sentinel的微服务限流及熔断

一、服务限流的作用及实现 在没有任何保护机制的情况下,如果所有的流量都进入服务器,很可能造成服务器宕机导致整个系统不可用,从而造成巨大的损失。为了保证系统在这些场景中仍然能够稳定运行,就需要采取一定的系统保护策略&…

智能优化算法应用:基于天牛须算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用:基于天牛须算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于天牛须算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.天牛须算法4.实验参数设定5.算法结果6.参考文…

Ubuntu 常用命令之 ls 命令用法介绍

Ubuntu ls 命令用法介绍 ls是Linux系统下的一个基本命令,用于列出目录中的文件和子目录。它有许多选项可以用来改变列出的内容和格式。 以下是一些基本的ls命令选项 -l:以长格式列出文件,包括文件类型、权限、链接数、所有者、组、大小、最…

Java 第10、11章 本章作业

目录 6 综合编程题7 成员内部类应用8 枚举类 & switch 6 综合编程题 3. 交通工具工厂类:由于在任务中只需要调用其中获得交通工具的方法,可以将方法定义为静态方法,这样就不用先创建工厂类的对象,直接“类名.方法” 即可。为了…

基于Java SSM框架实现疫情居家办公OA系统项目【项目源码+论文说明】

基于java的SSM框架实现疫情居家办公OA系统演示 摘要 21世纪的今天,随着社会的不断发展与进步,人们对于信息科学化的认识,已由低层次向高层次发展,由原来的感性认识向理性认识提高,管理工作的重要性已逐渐被人们所认识…

3.1 内容管理模块 - 工程搭建、课程查询、配置Swagger、数据字典

文章目录 内容管理模块一、基础工程搭建1.1 需求分析1.2 业务流程1.3 数据模型1.4 创建模块工程1.4.1 介绍1.4.2 xuecheng-plus-content 聚合工程1.4.3 模块演示 二、课程查询准备2.1 需求分析2.1.1 业务流程2.1.2 数据模型 2.2 生成PO类2.2.1 新增Maven配置2.2.2 课程基本信息…

文档安全加固:零容忍盗窃,如何有效预防重要信息外泄

文档安全保护不仅需要从源头着手,杜绝文档在使用和传播过程中产生的泄密风险,同时还需要对文档内容本身进行有效的保护。为了防范通过拷贝、截屏、拍照等手段盗窃重要文档内容信息的风险,迅软DSE加密软件提供了文档加密保护功能,能…

用23种设计模式打造一个cocos creator的游戏框架----(十八)责任链模式

1、模式标准 模式名称:责任链模式 模式分类:行为型 模式意图:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处…

MLX:苹果 专为统一内存架构(UMA) 设计的机器学习框架

“晨兴理荒秽,带月荷锄归” 夜深闻讯,有点兴奋~ 苹果为 UMA 设计的深度学习框架真的来了 统一内存架构 得益于 CPU 与 GPU 内存的共享,同时与 MacOS 和 M 芯片 交相辉映,在效率上,实现对其他框架的降维打…

Redis设计与实现之压缩列表

目录 一、 压缩列表 1、ziplist的构成 2、节点的构成 pre_entry_length encoding 和 length content 3、创建新 ziplist 4、将节点添加到末端 5、将节点添加到某个/某些节点的前面 6、删除节点 7、遍历 8、查找元素、根据值定位节点 二、小结 一、 压缩列表 Zipli…