Python进阶-数据库编程-04

Python进阶系列
Python进阶-网络编程-01
Python进阶-网络编程-02
Python进阶-网络编程-03
Python进阶-多任务编程-01
Python进阶-多任务编程-02
Python进阶-多任务编程-03
Python进阶-正则表达式
Python进阶-数据库编程-01
Python进阶-数据库编程-02
Python进阶-数据库编程-03
Python进阶-数据库编程-04
Python进阶-数据拷贝问题
Python进阶-模块导入问题
Python进阶-miniWeb框架

13.1. 索引

  • 索引作用:提升查询效率

  • 索引的使用

    • 查看索引 show index from 表名

    • 创建索引 create index 索引名 on 表名(表中的字段名(字段长度))

      • 如果字段是字符串类型,需要指定长度

      • 如果字段不是字符串类型,可以不指定长度

    • 删除索引 drop index 索引名 on 表名;

  • 插入10万条数据到数据库中

    • pymysql 操作步聚:
      1. 导入模块
      2. 创建连接对象
      3. 创建游标对象
      4. for循环,插入10万条数据
      5. 提交数据
      6. 关闭游标
      7. 关闭连接
  • 验证索引效果

    • 开启检测 set profiling = 1;
    • 执行sql
    • 查看每一个sql执行的时间 show profiles;
    • 添加索引
    • 执行sql
    • 查看执行效率 show profiles;
  • 代码实例:

    # 1.导入模块
    import pymysql
    
    # 2.创建连接对象
    conn = pymysql.connect(host="localhost",user="root",password="107314",database="python_index_db")
    
    # 3.创建游标对象
    cur = conn.cursor()
    
    try:
        # 4.for循环,插入10万条数据
        for i in range(100000):
            cur.execute("insert into test_index(title) values('ha-%d')" % i)
    
        # 5.提交数据
        conn.commit()
    except Exception as e:
        print(e)
        conn.rollback()
    finally:
        # 6.关闭游标
        cur.close()
        # 7.关闭连接
        conn.close()
    

13.2. 用户管理(一)

  • 创建用户

    create user '用户名'@'主机'  identified by '密码'
    
  • 授权

    权限:create drop select insert update

    所有权限:all privileges;

    grant  权限  on  数据库.表  to  '用户名'@'主机';
    
  • 查询权限

    show grants for '用户名'@'主机名'
    
  • 刷新权限

    flush privileges;
    

13.3. 用户管理(二)

  • 修改用户权限

    grant 权限 on 数据表.表 to '用户名'@'主机' with grant option;
    
  • 修改用户密码

    • 知道密码,改新密码
    alter user '用户名'@'主机' identified by '新密码';
    
    • 忘记密码,重置密码

      • 停止服务,设置跳过正常验证,设置密码为空
      • 设置正常验证模式,重启服务,用空密码登录,改成新密码
  • 删除用户

    drop user '用户名'@'主机';
    

13.4. 爬虫实战:爬取数据并保存到数据库中

  • 思路:

    1. 定义专门的函数,负责保存数据add_film()

      ​ 1) 定义SQL语句,准备插入数据

      ​ 2) 执行SQL语句

    2. 定义专门函数,负责检测数据库中是否存在相同的数据film_exist()

      ​ 1)定义sql 根据影片名称和地址 查询

      ​ 2)执行查询,并获取查询的记录数

      ​ 3)如果获取的记录数>0 return True

      ​ 4) 如果获取的记录数=0 return False

    3. 创建连接对象(全局)

    4. 创建游标对象(全局)

    5. 关闭操作

  • 简单爬虫-数据库版

    import urllib.request
    import re
    import pymysql
    
    
    def main():
        # 获取电影的影片名称和下载地址字典
        films_dict = get_movie_links()
    
        # 把字典遍历输出
        # films_dict.items()把字典转换为可遍历的元组
        for film_name,film_link in films_dict.items():
            if film_exist(film_name,film_link):
                print("保存失败!影片%s" % film_name)
                continue
            # 调用add_film方法添加数据
            add_film(film_name,film_link)
    
    
    def add_film(film_name,film_link):
        """保存影片到数据库中"""
        # 定义sql 准备插入数据   底层防注入
        sql = "insert into movie_link values (null,%s,%s)"
        # 执行SQL语句
        ret = cur.execute(sql,[film_name,film_link])
        if ret:
            print("保存成功!影片[%s]" % film_name)
    
    
    def film_exist(film_name,film_link):
        """用于检测数据是否已经存在"""
        sql = "select id from movie_link where film_name = %s and film_link=%s limit 1"
        ret = cur.execute(sql, [film_name, film_link])
        if ret:
            return True
        else:
            return False
    
    
    def get_movie_links():
        """获取列表页影片信息"""
        # 1.定义列表页的地址 https://www.ygdy8.net/html/gndy/dyzz/index.html
        file_list_url = "https://www.ygdy8.net/html/gndy/dyzz/list_23_1.html"
    
        # 2.打开url地址,获取数据
        response_list = urllib.request.urlopen(file_list_url)
        # 通过read()读取网络资源数据
        response_list_data = response_list.read()
    
        # 3.解码获取到的数据
        response_list_text = response_list_data.decode("GBK")
    
        # 4.使用正则得到所有的影片内容页地址
        # print(response_list_text)
        # 4.1 使用findall() 根据正则查找所用影片对应的内容页地址
        url_list = re.findall(r"<a href=\"(.*)\" class=\"ulink\">(.*)</a>",response_list_text)
        # 4.2 保存地址,定义一个字典用于保存影片信息
        films_dict = {}
    
        i=1
        # 4.3 循环遍历 url_list
        for content_url,file_name in url_list:
            content_url = "https://www.ygdy8.net" + content_url
            # print("影片名称:%s,  内容页地址:%s" % (file_name,content_url))
    
            # 4.4 打开内容页地址
            response_content = urllib.request.urlopen(content_url)
            # 4.5 接收内容页数据
            # 4.6 读取网络资源
            response_content_data = response_content.read()
            # 4.7 解码得到内容页的文本内容
            response_content_text = response_content_data.decode("GBK")
            # 4.8 取出下载地址
            # print(response_content_text)
            result = re.search(r"magnet:\?xt=urn:btih:(.*)fannounce",response_content_text)
            # print("下载地址%d:" % i,result.group())
    
            # 字典
            # {"xxx":"XXX地址"}
            films_dict[file_name] = result.group()
            print("已经获取%d条信息" % i)
            i += 1
    
        return films_dict
    
    
    if __name__ == '__main__':
        # 3.创建连接对象
        conn = pymysql.connect(host="localhost",user="root",password="107314",database="movie_db")
    
        # 4.创建游标对象
        cur = conn.cursor()
    
        # 爬取数据
        main()
        conn.commit()
    
        # 5.关闭操作
        cur.close()
        conn.close()
    

13.5. 爬虫实战:展示电影数据到网页中

  • 思路:

    1. 把web服务器返回固定内容 代码拷贝过来

    2. 把原本固定的内容变为从数据库动态读取

    ​ 1)导入pymusql模块

    ​ 2)连接数据库,并且查询影片的所有信息

    ​ 3)遍历查询结果集,拼接响应的主体

  • 简单爬虫-展示影片信息

    import socket
    import pymysql
    
    
    def request_handler(new_client_socket,ip_port):
        """接收信息,做出响应"""
        # 7、接收客户端刘觉器发送的请求协议
        request_data = new_client_socket.recv(1024)
        # 8、判断协议是否为空
        if not request_data:
            print("%s客户端已经下线" % str(ip_port))
            new_client_socket.close()
            return
    
        # 9、拼接响应的报文
        # 响应行
        response_line = "HTTP/1.1 200 OK\r\n"
        # 响应头
        response_header = "Server:Python20WS/2.1\r\n"
        response_header += "Content-type:text/html;charset=utf-8\r\n"
        # 响应空行
        response_blank = "\r\n"
        # 响应主体
    
        response_body = ""
        # 1)导入pymusql模块
        # 2)连接数据库,并且查询影片的所有信息
        conn = pymysql.connect(host="localhost",user="root",password="107314",database="movie_db")
        cur = conn.cursor()
        # 3)遍历查询结果集,拼接响应的主体
        cur.execute("select * from movie_link order by id desc ")
        # 返回元组值
        result_list = cur.fetchall()
        for row in result_list:
            response_body += "%d.%s  下载地址:[<a href='%s'>%s</a>] <br>" % (row[0],row[1],row[2],row[2])
    
    
        cur.close()
        conn.close()
    
        response_data = response_line + response_header + response_blank + response_body
    
        # 10、发送响应报文
        new_client_socket.send(response_data.encode())
    
        # 11.关闭当前连接
        new_client_socket.close()
    
    
    def main():
        # 1、导入模块
        # 2、创建套接字
        tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    
        # 3、设置地址重用
        tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)
    
        # 4、绑定端口
        tcp_server_socket.bind(("",8080))
    
        # 5、设置监听,让套接字由主动变为被动接收
        tcp_server_socket.listen(128)
    
        # 6、接受客户端连接定义函数request handler()
        while True:
            new_client_socket,ip_port = tcp_server_socket.accept()
            # 调用函数处理请求并且响应
            request_handler(new_client_socket,ip_port)
    
    
        # 11、关闭操作
        tcp_server_socket.close()
    
    
    if __name__ == '__main__':
        main()
    

13.6. 闭包的概念及基本使用

  • 概念:在一个外函数中定义了一个内函数,内函数里用了外函数的临时变量,并且外函数的返回值是内函数的引用,这就构成了一个闭包。

  • 闭包构成的条件

    • 存在函数的嵌套关系
    • 内层函数引用了外层函数的临时变量
    • 外层函数返回内层函数
  • 代码实例:

    def function_out(num):
        print("function_out num =",num)
    
        def function_in(num_in):
            print("function_in num=",num)
            print("function_in num_in=",num_in)
    
        return function_in
    
    ret = function_out(100)
    
    ret(88)
    

13.7. 闭包中变量问题

  • 内层定义了和外层同名的变量

    内层优先使用内层定义的变量,即使定义变量的代码在内层的最后面

  • 解决办法:当内层存在和外层同名变量,而且内层需要使用外层定义的变量,此时应该使用nonlocal 关键字进行约束

  • 代码实例:

    def function_out(num):
        def function_in():
            # 造成错误的原因:编译器认为内层函数已经定义了num变量,优先使用内层
            # 如果在内层定义了和外层同名的变量,而且需要使用外层的变量
            # nonlocal不使用内部的变量,使用外层的变量
            nonlocal num
            print("num=",num)
    
            num = 88
            print(num)
    
        return function_in
    
    ret = function_out(10)
    ret()
    

13.8. 装饰器入门

  • 定义: 装饰器本质上是一个Python函数(其实就是闭包),它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。装饰器用于有以下场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。

  • 装饰器的使用

    1. 存在闭包(用于拓展新的功能)
    2. 需要装饰的函数
  • 代码实例1:

    def function_out(func):
        def function_in():
            print("开始验证")
            func()
    
        return function_in
    
    
    @function_out
    def login():
       print("开始登录")
        
    login()
    
  • 代码实例2:

    import time
    import threading
    
    
    # 为函数添加一个统计运行时长的装饰器
    def how_much_time(func):
        def inner():
            t_start = time.time()
            func()
            t_end = time.time()
            print("一共花费了{0}秒时间".format(t_end - t_start, ))
    
        return inner
        # 将增加的新功能代码以及被装饰函数运行代码func()一同打包返回,
        # 返回的是一个内部函数,这个被返回的函数就是装饰器
    
    
    def sleep_5s():
        time.sleep(5)
        print("%d秒结束了" % (5,))
    
    
    def sleep_6s():
        time.sleep(6)
        print("%d秒结束了" % (6,))
    
    
    sleep_5s = how_much_time(sleep_5s)
    # 因为sleep_5s函数的功能就是睡5秒钟,虽然增加了统计运行时间的功能,
    # 但是他本身功能没变(还是睡5秒钟),所以仍然用原来函数名接收增加功能了的自己
    sleep_6s = how_much_time(sleep_6s)
    
    t1 = threading.Thread(target=sleep_5s)
    t2 = threading.Thread(target=sleep_6s)
    t1.start()
    t2.start()
    

在这里插入图片描述
在这里插入图片描述

  • 代码实例3:

    @mylog
    @how_much_time
    def sleep_5s():
        time.sleep(5)
        print("%d秒结束了" % (5,))
    

在这里插入图片描述


13.9. 装饰有参数的函数

  • 代码实例:

    def function_out(func):
        def function_in(num):
            print("开始验证 num =",num)
            func(num)
    
        return function_in
    
      
    # login = function_out(login)
    @function_out
    def login(num):
        print("开始登录 num = ",num)
    
        
    login(10)
    

13.10. 装饰有可变参数的装饰器

  • 代码实例:

    def function_out(func):
        def function_in(*args,**kwargs):
            print("function_in login:args=", args)
            print("function_in login:kwargs=", kwargs)
            func(*args,**kwargs)
    
        return function_in
    
    
    @function_out
    def login(*args,**kwargs):
        print("login:args=",args)
        print("login:kwargs=",kwargs)
    
    
    login(10,a=10)
    

13.11. 装饰有返回值的函数

  • 步骤

    • 待装饰的函数必须有返回值(return)
    • 闭包的内层函数func(*args , **kwargs) 改为 return func(*args , **kwargs)
  • 代码实例:

    def function_out(func):
        def function_in(num):
            print("开始验证")
            return func(num)
    
        return function_in
    
    
    @function_out # login = function_out(login)
    def login(num):
       print("开始登录")
       return num + 10
    
    result = login(8)
    print(result)
    

13.12. 通用版装饰器

  • 代码实例

    def function_out(func):
        def function_in(*args,**kwargs):
            print("function_in login:args=", args)
            print("function_in login:kwargs=", kwargs)
            return func(*args,**kwargs)
    
        return function_in
    
    
    @function_out
    def login(*args,**kwargs):
        print("login:args=",args)
        print("login:kwargs=",kwargs)
        return 10
    
    
    result = login(10,a=10)
    print(result)
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值