前言

系列文章目录
[Python]目录
视频及资料和课件
链接:https://pan.baidu.com/s/1LCv_qyWslwB-MYw56fjbDg?pwd=1234
提取码:1234


文章目录

  • 前言
  • 1. web框架概述
    • 1.1 web框架和web服务器的关系介绍
    • 1.2 静态资源
    • 1.3 动态资源
    • 1.4 WSGI协议
  • 2. 框架程序开发
    • 2.1 框架职责介绍
    • 2.2 静态web服务器
    • 2.3 动态资源判断
  • 3. 模板替换功能开发
  • 4. 路由列表功能开发
    • 4.1 请求的页面为center.html的处理函数
    • 4.2 路由列表
    • 4.3 请求处理函数
    • 4.4 web框架代码
  • 5. 装饰器方式的添加路由
    • 5.1 装饰器的定义
    • 5.2 web框架代码
  • 6. 显示股票信息页面的开发
    • 6.1 数据准备
    • 6.2 根据sql语句查询股票信息 & 使用查询数据替换模板变量
  • 7. 个人中心数据接口的开发
  • 8. logging日志
    • 8.1 logging日志的介绍
    • 8.2 记录程序日志信息的目的是
    • 8.3 logging日志级别介绍
    • 8.4 logging日志的使用
      • 8.4.1 日志信息输出到控制台的示例代码
      • 8.4.2 logging日志等级和输出格式的设置
      • 8.4.3 日志信息保存到日志文件
      • 8.4.4 logging日志在mini-web项目中应用
        • 程序入口模块设置logging日志的设置
        • INFO级别的日志输出,示例代码

1. web框架概述

1.1 web框架和web服务器的关系介绍

静态web服务器用于静态资源数据请求。

动态资源请求使用web框架专门负责处理,这个web框架其实就是一个为web服务器提供服务的应用程序,简称web框架。


关系说明:

  1. web服务器接收浏览器发起的请求,如果是动态资源请求找web框架来处理
  2. web框架负责处理浏览器的动态资源请求,把处理的结果发生给web服务器
  3. web服务器再把响应结果发生给浏览器

1.2 静态资源

不需要经常变化的资源,这种资源web服务器可以提前准备好,比如: png/jpg/css/js等文件。

1.3 动态资源

和静态资源相反, 这种资源会经常变化,比如: 我们在京东浏览商品时经常会根据条件进行筛选,选择不同条件, 浏览的商品就不同,这种资源web服务器无法提前准备好,需要web框架来帮web服务器进行准备,在这里web服务器可以把.html的资源请求认为是动态资源请求交由web框架进行处理。

1.4 WSGI协议

它是web服务器和web框架之间进行协同工作的一个规则,WSGI协议规定web服务器把动态资源的请求信息传给web框架处理,web框架把处理好的结果返回给web服务器。

2. 框架程序开发

2.1 框架职责介绍

接收web服务器的动态资源请求,给web服务器提供处理动态资源请求的服务。

2.2 静态web服务器

  • 【[Python]静态Web服务器】
import socket
import sys
import threading# 定义web服务器类
class HttpWebServer(object):def __init__(self, port):# 创建tcp服务端套接字对象tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 设置端口号复用,程序退出端口号立即释放tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)# 绑定端口号tcp_server_socket.bind(('', port))# 服务端套接字监听tcp_server_socket.listen(128)# 将tcp服务端套接字对象作为属性self.tcp_server_socket = tcp_server_socket# 启动web服务器进行工作def start(self):# 循环等待客户端的连接while True:# 等待接受客户端的连接请求new_socket, ip_port = self.tcp_server_socket.accept()print(ip_port)# 客户端与服务端建立连接后,创建子线程sub_thread = threading.Thread(target=self.handle_client_request, args=(new_socket,))# 设置守护主线程sub_thread.setDaemon(True)# 启动线程sub_thread.start()# 处理客户端的请求@staticmethoddef handle_client_request(new_socket):# 接受客户端发送的数据# 由于浏览器一般不会发送大量的数据,所以一次接受的数据大小不用指定很大recv_client_data = new_socket.recv(4096)# 判断客户端是否处于连接转态if len(recv_client_data) == 0:new_socket.close()return# 对二进制数据进行解码recv_client_content = recv_client_data.decode('utf-8')print(recv_client_content)# 对字符串进行分割,分割两次,因为访问的资源路径在第二个位置request_list = recv_client_content.split(' ', maxsplit=2)# 获取请求资源地址request_path = request_list[1]print('请求的资源地址为:', request_path)# 如果请求的资源地址为 '/', 默认为首页index.htmlif request_path == '/':request_path = '/index.html'try:# 打开读取需要发送给客户端的文件with open('static' + request_path, 'rb') as f:# 读取文件数据file_data = f.read()except Exception as e:# 打开错误页面with open('static/error.html', 'rb') as f:# 读取文件数据file_data = f.read()# 将读取的数据封装为http格式的数据# 响应行response_line = 'HTTP/1.1 404 Not Found\r\n'# 响应头response_header = 'Server: PWS1.0\r\n'# 响应体response_body = file_data# 拼接为响应报文response_data = (response_line + response_header + '\r\n').encode('utf-8') + response_body# 发送数据给客户端new_socket.send(response_data)else:# 将读取的数据封装为http格式的数据# 响应行response_line = 'HTTP/1.1 200 OK\r\n'# 响应头response_header = 'Server: PWS1.0\r\n'# 响应体response_body = file_data# 拼接为响应报文response_data = (response_line + response_header + '\r\n').encode('utf-8') + response_body# 发送数据给客户端new_socket.send(response_data)finally:# 关闭与客户端的套接字new_socket.close()# 程序入口函数
def main():print('服务器运行在9090端口...')# 创建web服务器对象# 服务器运行的端口为 9090web_server = HttpWebServer(9090)# 启动web服务器进行工作web_server.start()# 判断是否为主模块
if __name__ == '__main__':main()

2.3 动态资源判断

根据请求资源路径的后缀名进行判断:
(1)如果请求资源路径的后缀名是.html则是动态资源请求, 让web框架程序进行处理。
(2)否则是静态资源请求,让web服务器程序进行处理。

静态web服务器:

     # 如果请求的资源地址为 '/', 默认为首页index.htmlif request_path == '/':request_path = '/index.html'# 判断是动态资源请求还是静态资源请求, 后缀为.html的为动态资源请求if request_path.endswith('.html'):# 动态资源请求# 动态资源请求找web框架处理,需要把请求参数给web框架# 准备给web框架的参数信息# env 环境变量,WSGI协议规定给web框架的参数信息最好使用env命名env = {'request_path': request_path# 目前只传请求路径# 需要传递其他的信息,可以在字典中添加}# 使用框架处理动态资源请求# 1. web框架需要把处理结果返回web服务器# 2. web服务器负责把返回的结果封装成响应报文发送给浏览器# web框架需要返回 响应状态信息、响应头、响应体status, headers, response_body = framework.handle_request(env)# 将web框架处理的数据封装成响应报文# 响应行response_line = 'HTTP/1.1 %s\r\n' % status# 响应头response_header = ''for header in headers:# 对元组进行拆包,同时拼接进字符串response_header += '%s: %s\r\n' % header# 响应报文response_data = (response_line + response_header + '\r\n' + response_body).encode('utf-8')# 响应报文发送给浏览器new_socket.send(response_data)new_socket.close()else:# 静态资源请求# 执行原先静态web服务器的代码# 因为原先写的静态web服务器用于处理静态资源try:...except Exception as e:...else:...finally:...
import socket
import sys
import threading
# 导入web框架
import framework# 定义web服务器类
class HttpWebServer(object):def __init__(self, port):# 创建tcp服务端套接字对象tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 设置端口号复用,程序退出端口号立即释放tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)# 绑定端口号tcp_server_socket.bind(('', port))# 服务端套接字监听tcp_server_socket.listen(128)# 将tcp服务端套接字对象作为属性self.tcp_server_socket = tcp_server_socket# 启动web服务器进行工作def start(self):# 循环等待客户端的连接while True:# 等待接受客户端的连接请求new_socket, ip_port = self.tcp_server_socket.accept()print(ip_port)# 客户端与服务端建立连接后,创建子线程sub_thread = threading.Thread(target=self.handle_client_request, args=(new_socket,))# 设置守护主线程sub_thread.setDaemon(True)# 启动线程sub_thread.start()# 处理客户端的请求@staticmethoddef handle_client_request(new_socket):# 接受客户端发送的数据# 由于浏览器一般不会发送大量的数据,所以一次接受的数据大小不用指定很大recv_client_data = new_socket.recv(4096)# 判断客户端是否处于连接转态if len(recv_client_data) == 0:new_socket.close()return# 对二进制数据进行解码recv_client_content = recv_client_data.decode('utf-8')print(recv_client_content)# 对字符串进行分割,分割两次,因为访问的资源路径在第二个位置request_list = recv_client_content.split(' ', maxsplit=2)# 获取请求资源地址request_path = request_list[1]print('请求的资源地址为:', request_path)# 如果请求的资源地址为 '/', 默认为首页index.htmlif request_path == '/':request_path = '/index.html'# 判断是动态资源请求还是静态资源请求, 后缀为.html的为动态资源请求if request_path.endswith('.html'):# 动态资源请求# 动态资源请求找web框架处理,需要把请求参数给web框架# 准备给web框架的参数信息# env 环境变量,WSGI协议规定给web框架的参数信息最好使用env命名env = {'request_path': request_path# 目前只传请求路径# 需要传递其他的信息,可以在字典中添加}# 使用框架处理动态资源请求# 1. web框架需要把处理结果返回web服务器# 2. web服务器负责把返回的结果封装成响应报文发送给浏览器# web框架需要返回 响应状态信息、响应头、响应体status, headers, response_body = framework.handle_request(env)# 将web框架处理的数据封装成响应报文# 响应行response_line = 'HTTP/1.1 %s\r\n' % status# 响应头response_header = ''for header in headers:# 对元组进行拆包,同时拼接进字符串response_header += '%s: %s\r\n' % header# 响应报文response_data = (response_line + response_header + '\r\n' + response_body).encode('utf-8')# 响应报文发送给浏览器new_socket.send(response_data)new_socket.close()else:# 静态资源请求# 执行原先静态web服务器的代码# 因为原先写的静态web服务器用于处理静态资源try:# 打开读取需要发送给客户端的文件with open('static' + request_path, 'rb') as f:# 读取文件数据file_data = f.read()except Exception as e:# 打开错误页面with open('static/error.html', 'rb') as f:# 读取文件数据file_data = f.read()# 将读取的数据封装为http格式的数据# 响应行response_line = 'HTTP/1.1 404 Not Found\r\n'# 响应头response_header = 'Server: PWS1.0\r\n'# 响应体response_body = file_data# 拼接为响应报文response_data = (response_line + response_header + '\r\n').encode('utf-8') + response_body# 发送数据给客户端new_socket.send(response_data)else:# 将读取的数据封装为http格式的数据# 响应行response_line = 'HTTP/1.1 200 OK\r\n'# 响应头response_header = 'Server: PWS1.0\r\n'# 响应体response_body = file_data# 拼接为响应报文response_data = (response_line + response_header + '\r\n').encode('utf-8') + response_body# 发送数据给客户端new_socket.send(response_data)finally:# 关闭与客户端的套接字new_socket.close()# 程序入口函数
def main():print('服务器运行在9090端口...')# 创建web服务器对象# 服务器运行的端口为 9090web_server = HttpWebServer(9090)# 启动web服务器进行工作web_server.start()# 判断是否为主模块
if __name__ == '__main__':main()

web框架:

"""web框架用于处理动态资源请求"""
import timedef index():# 状态信息status = '200 OK'# 响应头信息# 这里使用列表套元组的方法存放信息,每个元组为一个信息response_header = [('Server', 'PWS/1.1')]# web框架成立后的数据# 获取当前时间date_now = time.ctime()# 返回信息# 返回的是元组return status, response_header, date_nowdef not_found():# 状态信息status = '404 Not Found'# 响应头信息# 这里使用列表套元组的方法存放信息,每个元组为一个信息response_header = [('Server', 'PWS/1.1')]# web框架成立后的数据date_now = 'Not Found'# 返回信息# 返回的是元组return status, response_header, date_nowdef handle_request(env):# 获取动态资源请求路径request_path = env['request_path']print('动态资源请求路径:', request_path)# 判断请求的动态资源路径,选中指定的函数处理对应的动态资源请求if request_path == '/index.html':# 返回处理数据return index()else:# 没有动态资源信息,返回404return not_found()


3. 模板替换功能开发

模板功能需要实现能够将数据库中查询出来的数据添加到需要返回给浏览器的页面中。

web框架代码:

    # 1. 打开指定模板文件,读取模板文件中的数据with open('template/index.html', 'r') as f:f_data = f.read()# 2. 查询数据库,模板里面的模板变量({%content%})替换成从数据库中查询出来的数据# web框架处理后的数据# 获取当前时间,模拟从数据库中查询出来的数据date_now = time.ctime()response_body = f_data.replace('{%content%}', date_now)# 返回信息# 返回的是元组return status, response_header, response_body
"""web框架用于处理动态资源请求"""
import timedef index():# 状态信息status = '200 OK'# 响应头信息# 这里使用列表套元组的方法存放信息,每个元组为一个信息response_header = [('Server', 'PWS/1.1')]# 1. 打开指定模板文件,读取模板文件中的数据with open('template/index.html', 'r') as f:f_data = f.read()# 2. 查询数据库,模板里面的模板变量({%content%})替换成从数据库中查询出来的数据# web框架处理后的数据# 获取当前时间,模拟从数据库中查询出来的数据date_now = time.ctime()response_body = f_data.replace('{%content%}', date_now)# 返回信息# 返回的是元组return status, response_header, response_bodydef not_found():# 状态信息status = '404 Not Found'# 响应头信息# 这里使用列表套元组的方法存放信息,每个元组为一个信息response_header = [('Server', 'PWS/1.1')]# web框架成立后的数据date_now = 'Not Found'# 返回信息# 返回的是元组return status, response_header, date_nowdef handle_request(env):# 获取动态资源请求路径request_path = env['request_path']print('动态资源请求路径:', request_path)# 判断请求的动态资源路径,选中指定的函数处理对应的动态资源请求if request_path == '/index.html':# 返回处理数据return index()else:# 没有动态资源信息,返回404return not_found()

4. 路由列表功能开发

按照原先的写法,每次请求不同的页面都需要重新写一个if判断,如果不同页面的数量较多,代码书写麻烦。

为了避免这个问题,我们可以使用使用路由。

路由就是请求的URL到处理函数的映射,也就是说提前把请求的URL和处理函数关联好。

路由的管理, 可以使用一个路由列表进行管理,通过路由列表保存每一个路由。

4.1 请求的页面为center.html的处理函数

def center():# 状态信息status = '200 OK'# 响应头信息# 这里使用列表套元组的方法存放信息,每个元组为一个信息response_header = [('Server', 'PWS/1.1')]# 1. 打开指定模板文件,读取模板文件中的数据with open('template/center.html', 'r', encoding='utf-8') as f:f_data = f.read()# 2. 查询数据库,模板里面的模板变量({%content%})替换成从数据库中查询出来的数据# web框架处理后的数据# 获取当前时间,模拟从数据库中查询出来的数据date_now = time.ctime()response_body = f_data.replace('{%content%}', date_now)# 返回信息# 返回的是元组return status, response_header, response_body

4.2 路由列表

route_list = [('/index.html', index),('/center.html', center)
]

4.3 请求处理函数

def handle_request(env):# 获取动态资源请求路径request_path = env['request_path']print('动态资源请求路径:', request_path)# 判断请求的动态资源路径,选中指定的函数处理对应的动态资源请求for path, func in route_list:if request_path == path:# 找到了对应的函数,调用与请求路径对应的函数# 同时返回结果return func()else:# 没有动态资源信息,返回404return not_found()

4.4 web框架代码

"""web框架用于处理动态资源请求"""
import timedef index():# 状态信息status = '200 OK'# 响应头信息# 这里使用列表套元组的方法存放信息,每个元组为一个信息response_header = [('Server', 'PWS/1.1')]# 1. 打开指定模板文件,读取模板文件中的数据with open('template/index.html', 'r', encoding='utf-8') as f:f_data = f.read()# 2. 查询数据库,模板里面的模板变量({%content%})替换成从数据库中查询出来的数据# web框架处理后的数据# 获取当前时间,模拟从数据库中查询出来的数据date_now = time.ctime()response_body = f_data.replace('{%content%}', date_now)# 返回信息# 返回的是元组return status, response_header, response_bodydef center():# 状态信息status = '200 OK'# 响应头信息# 这里使用列表套元组的方法存放信息,每个元组为一个信息response_header = [('Server', 'PWS/1.1')]# 1. 打开指定模板文件,读取模板文件中的数据with open('template/center.html', 'r', encoding='utf-8') as f:f_data = f.read()# 2. 查询数据库,模板里面的模板变量({%content%})替换成从数据库中查询出来的数据# web框架处理后的数据# 获取当前时间,模拟从数据库中查询出来的数据date_now = time.ctime()response_body = f_data.replace('{%content%}', date_now)# 返回信息# 返回的是元组return status, response_header, response_bodydef not_found():# 状态信息status = '404 Not Found'# 响应头信息# 这里使用列表套元组的方法存放信息,每个元组为一个信息response_header = [('Server', 'PWS/1.1')]# web框架成立后的数据date_now = 'Not Found'# 返回信息# 返回的是元组return status, response_header, date_nowroute_list = [('/index.html', index),('/center.html', center)
]def handle_request(env):# 获取动态资源请求路径request_path = env['request_path']print('动态资源请求路径:', request_path)# 判断请求的动态资源路径,选中指定的函数处理对应的动态资源请求for path, func in route_list:if request_path == path:# 找到了对应的函数,调用与请求路径对应的函数# 同时返回结果return func()else:# 没有动态资源信息,返回404return not_found()



5. 装饰器方式的添加路由

每次添加路由都需要手动添加来完成,接下来我们想要完成路由的自动添加,可以通过装饰器来实现。

在使用装饰器对处理函数进行装饰的时候我们需要知道装饰的函数和那个请求路径进行关联,也就是说装饰器需要接收一个url参数,这样我们定义的装饰器是一个带有参数的装饰器。

5.1 装饰器的定义

# 定义带有参数的装饰器
def route(path):# 定义装饰器def decorator(func):# 将路由添加到路由列表中route_list.append((path, func))def inner():return func()# 返回装饰后的函数return inner# 返回装饰器return decorator

5.2 web框架代码

"""web框架用于处理动态资源请求"""
import timeroute_list = []# 定义带有参数的装饰器
def route(path):# 定义装饰器def decorator(func):# 将路由添加到路由列表中# 如果在 inner 内添加,那么添加路由只能在调用装饰后的函数时才会添加路由route_list.append((path, func))def inner():# 调用请求路径对应的处理函数# 并返回结果return func()# 返回装饰后的函数return inner# 返回装饰器return decorator# 装饰函数
@route('/index.html')
def index():# 状态信息status = '200 OK'# 响应头信息# 这里使用列表套元组的方法存放信息,每个元组为一个信息response_header = [('Server', 'PWS/1.1')]# 1. 打开指定模板文件,读取模板文件中的数据with open('template/index.html', 'r', encoding='utf-8') as f:f_data = f.read()# 2. 查询数据库,模板里面的模板变量({%content%})替换成从数据库中查询出来的数据# web框架处理后的数据# 获取当前时间,模拟从数据库中查询出来的数据date_now = time.ctime()response_body = f_data.replace('{%content%}', date_now)# 返回信息# 返回的是元组return status, response_header, response_body# 装饰函数
@route('/center.html')
def center():# 状态信息status = '200 OK'# 响应头信息# 这里使用列表套元组的方法存放信息,每个元组为一个信息response_header = [('Server', 'PWS/1.1')]# 1. 打开指定模板文件,读取模板文件中的数据with open('template/center.html', 'r', encoding='utf-8') as f:f_data = f.read()# 2. 查询数据库,模板里面的模板变量({%content%})替换成从数据库中查询出来的数据# web框架处理后的数据# 获取当前时间,模拟从数据库中查询出来的数据date_now = time.ctime()response_body = f_data.replace('{%content%}', date_now)# 返回信息# 返回的是元组return status, response_header, response_bodydef not_found():# 状态信息status = '404 Not Found'# 响应头信息# 这里使用列表套元组的方法存放信息,每个元组为一个信息response_header = [('Server', 'PWS/1.1')]# web框架成立后的数据date_now = 'Not Found'# 返回信息# 返回的是元组return status, response_header, date_nowdef handle_request(env):# 获取动态资源请求路径request_path = env['request_path']print('动态资源请求路径:', request_path)# 判断请求的动态资源路径,选中指定的函数处理对应的动态资源请求for path, func in route_list:if request_path == path:# 找到了对应的函数,调用与请求路径对应的函数# 同时返回结果return func()else:# 没有动态资源信息,返回404return not_found()

6. 显示股票信息页面的开发

6.1 数据准备

-- 创建数据库
create database stock_db charset=utf8;
-- 切换数据库
use stock_db;
-- 执行sql文件
source stock_db.sql;

stock_db.sql:

-- MySQL dump 10.13  Distrib 5.7.17, for Linux (x86_64)
--
-- Host: localhost    Database: stock_db
-- ------------------------------------------------------
-- Server version   5.7.13-0ubuntu0.16.04.2/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;--
-- Table structure for table `focus`
--DROP TABLE IF EXISTS `focus`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `focus` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT,`note_info` varchar(200) DEFAULT '',`info_id` int(10) unsigned DEFAULT NULL,PRIMARY KEY (`id`),KEY `info_id` (`info_id`),CONSTRAINT `focus_ibfk_1` FOREIGN KEY (`info_id`) REFERENCES `info` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;--
-- Dumping data for table `focus`
--LOCK TABLES `focus` WRITE;
/*!40000 ALTER TABLE `focus` DISABLE KEYS */;
INSERT INTO `focus` VALUES (2,'你确定要买这个?',36),(3,'利好',37),(9,'',88),(10,'',89),(13,'',1);
/*!40000 ALTER TABLE `focus` ENABLE KEYS */;
UNLOCK TABLES;--
-- Table structure for table `info`
--DROP TABLE IF EXISTS `info`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `info` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT,`code` varchar(6) NOT NULL COMMENT '股票代码',`short` varchar(10) NOT NULL COMMENT '股票简称',`chg` varchar(10) NOT NULL COMMENT '涨跌幅',`turnover` varchar(255) NOT NULL COMMENT '换手率',`price` decimal(10,2) NOT NULL COMMENT '最新价',`highs` decimal(10,2) NOT NULL COMMENT '前期高点',`time` date DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=95 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;--
-- Dumping data for table `info`
--LOCK TABLES `info` WRITE;
/*!40000 ALTER TABLE `info` DISABLE KEYS */;
INSERT INTO `info` VALUES (1,'000007','全新好','10.01%','4.40%',16.05,14.60,'2017-07-18'),(2,'000036','华联控股','10.04%','10.80%',11.29,10.26,'2017-07-20'),(3,'000039','中集集团','1.35%','1.78%',18.07,18.06,'2017-06-28'),(4,'000050','深天马A','4.38%','4.65%',22.86,22.02,'2017-07-19'),(5,'000056','皇庭国际','0.39%','0.65%',12.96,12.91,'2017-07-20'),(6,'000059','华锦股份','3.37%','7.16%',12.26,12.24,'2017-04-11'),(7,'000060','中金岭南','1.34%','3.39%',12.08,11.92,'2017-07-20'),(8,'000426','兴业矿业','0.41%','2.17%',9.71,9.67,'2017-07-20'),(9,'000488','晨鸣纸业','6.30%','5.50%',16.37,15.59,'2017-07-10'),(10,'000528','柳工','1.84%','3.03%',9.42,9.33,'2017-07-19'),(11,'000540','中天金融','0.37%','5.46%',8.11,8.08,'2017-07-20'),(12,'000581','威孚高科','3.49%','3.72%',27.00,26.86,'2017-06-26'),(13,'000627','天茂集团','5.81%','12.51%',10.93,10.33,'2017-07-20'),(14,'000683','远兴能源','6.42%','21.27%',3.48,3.29,'2017-07-19'),(15,'000703','恒逸石化','0.24%','1.65%',16.92,16.88,'2017-07-20'),(16,'000822','山东海化','6.60%','8.54%',9.05,8.75,'2017-07-06'),(17,'000830','鲁西化工','1.38%','4.80%',7.36,7.26,'2017-07-20'),(18,'000878','云南铜业','1.26%','3.23%',14.50,14.47,'2017-07-19'),(19,'000905','厦门港务','5.44%','10.85%',15.90,15.60,'2017-04-20'),(20,'000990','诚志股份','0.53%','1.00%',16.99,16.90,'2017-07-20'),(21,'002019','亿帆医药','1.19%','2.81%',17.05,16.85,'2017-07-20'),(22,'002078','太阳纸业','2.05%','1.90%',8.45,8.29,'2017-07-19'),(23,'002092','中泰化学','7.25%','6.20%',15.53,14.48,'2017-07-20'),(24,'002145','中核钛白','2.43%','7.68%',6.75,6.61,'2017-07-19'),(25,'002285','世联行','8.59%','5.66%',9.23,8.50,'2017-07-20'),(26,'002311','海大集团','1.13%','0.24%',18.81,18.63,'2017-07-19'),(27,'002460','赣锋锂业','9.41%','9.00%',63.70,58.22,'2017-07-20'),(28,'002466','天齐锂业','3.62%','3.66%',68.44,66.05,'2017-07-20'),(29,'002470','金正大','2.30%','0.99%',8.00,7.82,'2017-07-20'),(30,'002496','辉丰股份','3.15%','4.29%',5.24,5.08,'2017-04-10'),(31,'002497','雅化集团','0.38%','12.36%',13.10,13.05,'2017-07-20'),(32,'002500','山西证券','0.44%','3.70%',11.49,11.44,'2017-07-20'),(33,'002636','金安国纪','2.70%','11.59%',19.80,19.42,'2017-07-19'),(34,'300032','金龙机电','0.66%','0.72%',15.28,15.18,'2017-07-20'),(35,'300115','长盈精密','0.60%','0.59%',33.50,33.41,'2017-07-19'),(36,'300268','万福生科','-10.00%','0.27%',31.77,13.57,'2017-04-10'),(37,'300280','南通锻压','3.31%','0.66%',32.20,32.00,'2017-04-11'),(38,'300320','海达股份','0.28%','0.82%',18.26,18.21,'2017-07-20'),(39,'300408','三环集团','1.69%','0.81%',23.42,23.17,'2017-07-19'),(40,'300477','合纵科技','2.84%','5.12%',22.10,22.00,'2017-07-12'),(41,'600020','中原高速','5.46%','4.48%',5.60,5.31,'2017-07-20'),(42,'600033','福建高速','1.01%','1.77%',4.00,3.99,'2017-06-26'),(43,'600066','宇通客车','4.15%','1.49%',23.08,23.05,'2017-06-13'),(44,'600067','冠城大通','0.40%','2.97%',7.56,7.53,'2017-07-20'),(45,'600110','诺德股份','2.08%','4.26%',16.16,15.83,'2017-07-20'),(46,'600133','东湖高新','9.65%','21.74%',13.64,12.44,'2017-07-20'),(47,'600153','建发股份','3.65%','2.03%',13.35,13.21,'2017-07-10'),(48,'600180','瑞茂通','2.20%','1.07%',14.86,14.54,'2017-07-20'),(49,'600183','生益科技','6.94%','4.06%',14.94,14.12,'2017-07-19'),(50,'600188','兖州煤业','1.53%','0.99%',14.56,14.43,'2017-07-19'),(51,'600191','华资实业','10.03%','11.72%',15.80,14.36,'2017-07-20'),(52,'600210','紫江企业','6.03%','10.90%',6.68,6.30,'2017-07-20'),(53,'600212','江泉实业','1.39%','1.78%',10.20,10.15,'2017-07-19'),(54,'600225','*ST松江','4.96%','2.47%',5.71,5.61,'2017-04-13'),(55,'600230','沧州大化','5.74%','13.54%',43.26,40.91,'2017-07-20'),(56,'600231','凌钢股份','2.79%','3.77%',3.68,3.60,'2017-07-19'),(57,'600291','西水股份','10.02%','9.23%',34.71,31.55,'2017-07-20'),(58,'600295','鄂尔多斯','4.96%','12.62%',16.51,15.73,'2017-07-20'),(59,'600303','曙光股份','8.37%','14.53%',11.53,10.64,'2017-07-20'),(60,'600308','华泰股份','1.12%','2.66%',6.30,6.26,'2017-07-19'),(61,'600309','万华化学','0.03%','1.78%',31.81,31.80,'2017-07-20'),(62,'600352','浙江龙盛','0.39%','1.85%',10.32,10.28,'2017-07-20'),(63,'600354','敦煌种业','7.89%','18.74%',9.44,8.75,'2017-07-20'),(64,'600408','安泰集团','1.98%','3.38%',4.13,4.12,'2017-04-13'),(65,'600409','三友化工','0.62%','3.78%',11.36,11.29,'2017-07-20'),(66,'600499','科达洁能','0.46%','3.94%',8.84,8.80,'2017-07-20'),(67,'600508','上海能源','3.26%','2.99%',13.32,13.01,'2017-07-19'),(68,'600563','法拉电子','0.32%','1.36%',53.67,53.50,'2017-07-20'),(69,'600567','山鹰纸业','0.76%','2.85%',3.98,3.96,'2017-07-19'),(70,'600585','海螺水泥','0.45%','0.61%',24.51,24.44,'2017-07-19'),(71,'600668','尖峰集团','4.35%','6.43%',18.70,18.36,'2017-04-13'),(72,'600688','上海石化','2.72%','0.91%',6.80,6.74,'2017-06-01'),(73,'600729','重庆百货','5.70%','3.34%',27.45,27.13,'2017-06-29'),(74,'600739','辽宁成大','3.30%','3.50%',19.74,19.11,'2017-07-20'),(75,'600779','水井坊','3.85%','2.77%',29.39,28.30,'2017-07-20'),(76,'600781','辅仁药业','8.61%','4.16%',23.46,21.89,'2017-05-02'),(77,'600801','华新水泥','4.00%','10.15%',12.99,12.49,'2017-07-20'),(78,'600846','同济科技','2.06%','17.41%',9.39,9.26,'2017-04-13'),(79,'600884','杉杉股份','1.08%','3.53%',20.67,20.45,'2017-07-20'),(80,'600966','博汇纸业','2.89%','5.54%',6.41,6.28,'2017-07-19'),(81,'600971','恒源煤电','2.36%','8.81%',12.16,11.88,'2017-07-20'),(82,'601012','隆基股份','0.76%','1.30%',19.93,19.78,'2017-07-20'),(83,'601100','恒立液压','4.78%','0.92%',19.31,18.97,'2017-07-13'),(84,'601101','昊华能源','4.03%','6.06%',11.10,10.80,'2017-07-19'),(85,'601216','君正集团','2.16%','2.26%',5.20,5.10,'2017-04-17'),(86,'601666','平煤股份','2.81%','6.14%',6.96,6.77,'2017-07-20'),(87,'601668','中国建筑','2.39%','1.42%',10.70,10.45,'2017-07-20'),(88,'601678','滨化股份','0.13%','2.47%',7.92,7.91,'2017-07-20'),(89,'601918','新集能源','1.23%','3.11%',4.93,4.92,'2017-07-19'),(90,'603167','渤海轮渡','2.77%','3.34%',11.87,11.61,'2017-04-13'),(91,'603369','今世缘','3.34%','2.13%',14.24,13.78,'2017-07-20'),(92,'603589','口子窖','3.99%','1.84%',39.37,39.04,'2017-06-26'),(93,'603799','华友钴业','2.38%','7.19%',67.46,65.89,'2017-07-20'),(94,'603993','洛阳钼业','2.94%','2.50%',7.36,7.16,'2017-07-19');
/*!40000 ALTER TABLE `info` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;-- Dump completed on 2017-08-18 20:53:58

6.2 根据sql语句查询股票信息 & 使用查询数据替换模板变量

# 装饰函数
@route('/index.html')
def index():# 状态信息status = '200 OK'# 响应头信息# 这里使用列表套元组的方法存放信息,每个元组为一个信息response_header = [('Server', 'PWS/1.1')]# 1. 打开指定模板文件,读取模板文件中的数据with open('template/index.html', 'r', encoding='utf-8') as f:f_data = f.read()# 2. 查询数据库,模板里面的模板变量({%content%})替换成从数据库中查询出来的数据# 创建与数据库的连接对象conn = pymysql.connect(host='localhost',port=3306,user='root',password='285013',database='stock_db',charset='utf8')# 获取执行sql的游标对象cur = conn.cursor()# sqlsql = 'select * from info;'# 执行sqlcur.execute(sql)# 获取全部结果result = cur.fetchall()# 关闭对象cur.close()conn.close()# print(result)# web框架处理后的数据data = ""for row in result:data += """<tr><td>%s<td><td>%s<td><td>%s<td><td>%s<td><td>%s<td><td>%s<td><td>%s<td><td>%s<td></tr>""" % rowresponse_body = f_data.replace('{%content%}', data)# 返回信息# 返回的是元组return status, response_header, response_body

7. 个人中心数据接口的开发

个人中心数据接口的开发,需要根据sql语句查询个人中心数据,然后将个人中心数据转成json字符串并返回。

python 数据类型与 json 类型的转化表:

来源:python中的元组与json类型转化问题

可以json.dumps函数把字典转成json字符串。

  • json.dumps用于将 Python 对象 编码成 JSON 字符串。
  • 需要导入包import json
  • 函数的第一个参数 obj 表示要把指定对象转成json字符串
  • 参数的第二个参数ensure_ascii=False表示不使用ascii编码,可以在控制台显示中文。
  • indent=True参数根据数据格式缩进显示,读起来更加清晰。

响应头添加Content-Type表示指定数据的编码格式,防止数据到浏览器乱码。

 # 响应头信息# 这里使用列表套元组的方法存放信息,每个元组为一个信息response_header = [('Server', 'PWS/1.1'), # 设置数据的编码格式为 utf-8('Content-Type', 'text/html;charset=utf-8')]
# 个人中心数据接口
# 绑定请求资源路径
@route('/center_data.html')
def center_data():# 从数据库中查询数据# 创建与数据库的连接对象conn = pymysql.connect(host='localhost',port=3306,user='root',password='285013',database='stock_db',charset='utf8')# 获取执行sql的游标对象cur = conn.cursor()# sqlsql = '''select i.code, i.short, i.chg, i.turnover, i.price, i.highs, f.note_info from info as i inner join focus as f on i.id = f.info_id;'''# 执行sqlcur.execute(sql)# 获取全部结果result = cur.fetchall()# print(result)# 将结果由元组转成列表(元组转成json字符串会报错),元组内的每个小元组转成字典# 遍历元组中的每个元素,每个元素(每个小元组)取出值放到字典中# 最后字典组成列表center_data_list = [{'code': row[0],'short': row[1],'chg': row[2],'turnover': row[3],# Decimal不能转json,会报错'price': str(row[4]),'highs': str(row[5]),'note_info': row[6],} for row in result]# print(center_data_list)# 列表转成json字符串# ensure_ascii=False表示可以在控制台显示中文。# indent:参数根据数据格式缩进显示,读起来更加清晰。json_str = json.dumps(center_data_list, ensure_ascii=False, indent=True)# print(json_str)# 状态信息status = '200 OK'# 响应头信息# 这里使用列表套元组的方法存放信息,每个元组为一个信息response_header = [('Server', 'PWS/1.1'), ('Content-Type', 'text/html;charset=utf-8')]# 关闭对象cur.close()conn.close()# 向浏览器返回数据return status, response_header, json_str

8. logging日志

8.1 logging日志的介绍

在现实生活中,记录日志非常重要,比如:银行转账时会有转账记录;飞机飞行过程中,会有个黑盒子(飞行数据记录器)记录着飞机的飞行过程,那在python程序中想要记录程序在运行时所产生的日志信息,可以使用 logging 这个包来完成。

8.2 记录程序日志信息的目的是

  1. 可以很方便的了解程序的运行情况
  2. 可以分析用户的操作行为、喜好等信息
  3. 方便开发人员检查bug

8.3 logging日志级别介绍

日志等级可以分为5个,从低到高分别是:

  • DEBUG:程序调试bug时使用
  • INFO:程序正常运行时使用
  • WARNING:程序未按预期运行时使用,但并不是错误,如:用户登录密码错误
  • ERROR:程序出错误时使用,如:IO操作失败
  • CRITICAL:特别严重的问题,导致程序不能再继续运行时使用,如:磁盘空间为空,一般很少使用

默认的是WARNING等级,当在WARNING或WARNING之上等级的才记录日志信息。
日志等级从低到高的顺序是: DEBUG < INFO < WARNING < ERROR < CRITICAL

8.4 logging日志的使用

在 logging 包中记录日志的方式有两种:

  1. 输出到控制台
  2. 保存到日志文件

8.4.1 日志信息输出到控制台的示例代码

import logginglogging.debug('这是一个debug级别的日志信息')
logging.info('这是一个info级别的日志信息')
logging.warning('这是一个warning级别的日志信息')
logging.error('这是一个error级别的日志信息')
logging.critical('这是一个critical级别的日志信息')

由于默认的是WARNING等级,在WARNING或WARNING之上等级的才记录日志信息,所以WARNING以下的两个等级DEBUG、INFO都不显示。

8.4.2 logging日志等级和输出格式的设置

设置logging的配置信息,使用:

logging.basicConfig()
  • level 表示设置的日志等级
  • format 表示日志的输出格式, 参数说明:
    • %(levelname)s: 打印日志级别名称
    • %(filename)s: 打印当前执行程序名
    • %(lineno)d: 打印日志的当前行号,程序运行的行号
    • %(asctime)s: 打印日志的时间,获取当前时间
    • %(message)s: 打印日志信息

改变logging日志等级:

# 导入包
import logging# 设置logging日志等级为DEBUG
logging.basicConfig(level=logging.DEBUG)logging.debug('这是一个debug级别的日志信息')
logging.info('这是一个info级别的日志信息')
logging.warning('这是一个warning级别的日志信息')
logging.error('这是一个error级别的日志信息')
logging.critical('这是一个critical级别的日志信息')

设置logging的输出格式:

# 导入包
import logging# level 表示设置的日志等级
# format 表示日志的输出格式
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s')logging.debug('这是一个debug级别的日志信息')
logging.info('这是一个info级别的日志信息')
logging.warning('这是一个warning级别的日志信息')
logging.error('这是一个error级别的日志信息')
logging.critical('这是一个critical级别的日志信息')

8.4.3 日志信息保存到日志文件

日志信息保存到日志文件,使用:

logging.basicConfig()
  • filename=" ":日志信息保存的文件名
  • filemode=" ":文件的打开方式
  • encoding=‘utf-8’:设置编码格式
# 导入包
import logging# level 表示设置的日志等级
# format 表示日志的输出格式
logging.basicConfig(level=logging.DEBUG,format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s',filename='log.txt',filemode='a',encoding='utf-8'
)logging.debug('这是一个debug级别的日志信息')
logging.info('这是一个info级别的日志信息')
logging.warning('这是一个warning级别的日志信息')
logging.error('这是一个error级别的日志信息')
logging.critical('这是一个critical级别的日志信息')

8.4.4 logging日志在mini-web项目中应用

logging日志配置信息在程序入口模块设置一次,整个程序都可以生效。

程序入口模块设置logging日志的设置

 import socketimport threadingimport sysimport frameworkimport logging# logging日志的配置
logging.basicConfig(level=logging.DEBUG,format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s',filename="log.txt",filemode="w",encoding='utf-8'
)

INFO级别的日志输出,示例代码

        if request_path.endswith('.html'):logging.info('动态资源请求:'+ request_path)...else:# 静态资源请求logging.info('静态资源请求:' + request_path)...

[Python]mini-Web框架相关推荐

  1. python bottle web框架简介

    Bottle 是一个快速,简单,轻量级的 Python WSGI Web 框架.单一文件,只依赖 Python 标准库 .bottle很适合会一点python基础的人使用,因为这框架用起来很简单,只要 ...

  2. python搭建django框架,Python之Web框架Django项目搭建全过程

    Python之Web框架Django项目搭建全过程 IDE说明: Win7系统 Python:3.5 Django:1.10 Pymysql:0.7.10 Mysql:5.5 注:可通过pip fre ...

  3. 比我的脸还干的gan货——Python Flask Web 框架入门

    Flask是一个轻量级的基于Python的web框架. 本文适合有一定HTML.Python.网络基础的同学阅读. 1. 简介 这份文档中的代码使用 Python 3 运行. 是的,所以读者需要自己在 ...

  4. API接口开发其实特简单,Python Flask Web 框架教程来了

    大家好,日常工作中,无论你是数据工程师.数据挖掘工程师,甚至数据分析人员,都不可避免的与他人进行数据交互,API接口提供数据是最常见的形式. 今天我给大家分享 Python Flask Web 框架教 ...

  5. python的Web框架Django运行报错:Invalid HTTP_HOST header: 'xxx.xx.xxx.xxx:8000'. You may need to add 'xxx.xx'

    python的Web框架Django运行报错:Invalid HTTP_HOST header: 'xxx.xx.xxx.xxx:8000'. You may need to add 'xxx.xx' ...

  6. mini web框架-2-显示页面

    dynamic/my_web.py (更新) import time import ostemplate_root = "./templates"def index(file_na ...

  7. Python微型Web框架Bottle源码分析

    Bottle 是一个快速,简单和轻量级的 WSGI 微型 Web 框架的 Python.它作为单个文件模块分发,除了 Python 标准库之外没有依赖关系. 选择源码分析的版本是 Release 于 ...

  8. python微型web框架flask介绍

    Flask是一个基于python的,微型web框架.之所以被称为微型是因为其核心非常简单,同时具有很强的扩展能力.它几乎不给使用者做任何技术决定. 安装flask时应该注意其必须的几个支持包比如Jin ...

  9. python的web框架哪个最好学_2018年要学习的10大Python Web框架

    通过为开发人员提供应用程序开发结构,框架使开发人员的生活更轻松.他们自动执行通用解决方案,缩短开发时间,并允许开发人员更多地关注应用程序逻辑而不是常规元素. 在本文中,我们分享了我们自己的前十大Pyt ...

  10. Python 常用Web框架的比较

    从GitHub中整理出的15个最受欢迎的Python开源框架.这些框架包括事件I/O,OLAP,Web开发,高性能网络通信,测试,爬虫等. Django: Python Web应用开发框架     D ...

最新文章

  1. com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure 数据库报错
  2. [导入]在ASP.NET+ORACLE添加数据记录并让ID自动增量
  3. CentOS 5.3 下快速安装配置 PPTP ××× 服务器
  4. Repository模式与UnitOfWorks模式的运用
  5. CG CTF RE Hello,RE!
  6. QT的QAudioInput类的使用
  7. Struts2的Action编写
  8. asp.net的几种页面间的传值方法
  9. Mongo数据库慢查询功能
  10. 前端商城项目实战-(前端篇)
  11. 报童问题求解最大利润_数据分析案例:用数学建模和数据模拟解决供求矛盾问题...
  12. linux 音频驱动实验
  13. elasticsearch2.2之index映射参数的not_analyzed属性
  14. 共模信号和差模信号的区别和抑制
  15. 农林牧渔行业S2B2C系统网站提升品牌知名度,提升盈利水平
  16. 2021-2025年中国休闲凉鞋行业市场供需与战略研究报告
  17. Vue3配置postcss-pxtorem报错[plugin:vite:css] Failed to load PostCss config
  18. 高一到高三计算机笔记,高一到高三学习计划
  19. 这才是字节跳动(今日头条)面试?
  20. kali linux下w3af的安装

热门文章

  1. 【python】python ^异或操作
  2. root后自启动,免root自启动管理
  3. 关联规则挖掘--Apriori算法
  4. ubuntu各版本修改网卡配置
  5. java文件上传到腾讯云COS
  6. 转)Linux学习路线
  7. java 防止恶意刷短信验证码_用户使用java短信验证码时要做好三个保护
  8. 学校智慧用电用智能空开
  9. “地图易“图层管理工具介绍——业务图层管理轻松搞定
  10. AI给设计带来哪些影响?日常生活会怎样改变?