1 import re 2 from pymysql import connect 3 import urllib.parse 4 import logging 5 6 7 URL_FUNC_DICT = dict() 8 9 def open_mysql(): 10 # 创建connect连接 11 conn = connect(host='localhost',port=3306,user='root',password='m',database='stock',charset='utf8') 12 # 获得cursor对象 13 cs = conn.cursor() 14 return conn, cs 15 16 def close_mysql(conn, cs): 17 # 关闭连接、对象 18 cs.close() 19 conn.close() 20 21 def route(path_info): 22 '''装饰器:添加方法-路径到字典''' 23 def set_func(func): 24 URL_FUNC_DICT[path_info] = func 25 def call_func(*args, **kwargs): 26 return func(*args, **kwargs) 27 return call_func 28 return set_func 29 30 @route(r"/index.html") 31 def index(ret): 32 # 打开、读取网页 33 with open("./templates/index.html", encoding="utf-8") as f: 34 content = f.read() 35 # 打开数据库 36 conn, cs = open_mysql() 37 # 执行sql语句 38 cs.execute("select * from info;") 39 # 读取数据库数据 40 stock_infos = cs.fetchall() 41 # 关闭数据库 42 close_mysql(conn, cs) 43 # 数据库数据替换模板数据 44 tr_template = """<tr> 45 <td>%s</td> 46 <td>%s</td> 47 <td>%s</td> 48 <td>%s</td> 49 <td>%s</td> 50 <td>%s</td> 51 <td>%s</td> 52 <td>%s</td> 53 <td> 54 <input type="button" value="添加" id="toAdd" name="toAdd" systemidvaule="%s"> 55 </td> 56 </tr> 57 """ 58 html = "" 59 for line_info in stock_infos: 60 html += tr_template % (line_info[0],line_info[1],line_info[2],line_info[3],line_info[4],line_info[5],line_info[6],line_info[7], line_info[1]) 61 return re.sub(r"\{%content%\}", html, content) 62 63 @route(r"/center.html") 64 def center(ret): 65 # 打开读取网页 66 with open("./templates/center.html", encoding="utf-8") as f: 67 content = f.read() 68 # 打开数据库 69 conn, cs = open_mysql() 70 # 执行sql语句 71 cs.execute("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;") 72 # 读取sql语句结果 73 stock_infos = cs.fetchall() 74 # 关闭数据库 75 close_mysql(conn, cs) 76 tr_template = """ 77 <tr> 78 <td>%s</td> 79 <td>%s</td> 80 <td>%s</td> 81 <td>%s</td> 82 <td>%s</td> 83 <td>%s</td> 84 <td>%s</td> 85 <td> 86 <a type="button" class="btn btn-default btn-xs" href="/update/%s.html"> <span class="glyphicon glyphicon-star" aria-hidden="true"></span> 修改 </a> 87 </td> 88 <td> 89 <input type="button" value="删除" id="toDel" name="toDel" systemidvaule="%s"> 90 </td> 91 </tr> 92 """ 93 # 用数据库内容替换模板数据 94 html = "" 95 for stock_info in stock_infos: 96 html += tr_template % (stock_info[0], stock_info[1], stock_info[2], stock_info[3],stock_info[4], stock_info[5], stock_info[6], stock_info[0], stock_info[0]) 97 return re.sub(r"\{%content%\}", html, content) 98 99 @route(r"^/add/(\d+)\.html$") 100 def add_focus(ret): 101 '''添加股票''' 102 # 获取股票代码 103 stock_code = ret.group(1) 104 # 打开数据库,查询股票代码 105 conn, cs = open_mysql() 106 sql = "select * from info where code = %s;" 107 cs.execute(sql, (stock_code,)) 108 # 股票代码不在数据库中 109 if not cs.fetchall(): 110 # 返回提示 111 close_mysql(conn, cs) 112 return "没有这只股票代码,请收下留情。。" 113 # 判断股票代码是否已存在于focus表数据库中 114 sql = "select * from info as i inner join focus as f on i.id = f.info_id where i.code = %s" 115 cs.execute(sql, (stock_code,)) 116 # 已存在于focus表 117 if cs.fetchall(): 118 close_mysql(conn, cs) 119 return "已成功关注,请勿重复关注。。" 120 # 不存在于focu表 121 # 执行sql语句添加股票代码到focus表 122 sql = "insert into focus(info_id) select id from info where code = %s;" 123 cs.execute(sql, (stock_code)) 124 conn.commit() 125 # 关闭数据库 126 close_mysql(conn, cs) 127 return "关注成功。。" 128 129 @route(r"^/del/(\d+)\.html$") 130 def del_focus(ret): 131 '''取消关注股票''' 132 stock_code = ret.group(1) 133 print(stock_code) 134 conn, cs = open_mysql() 135 sql = "select * from focus as f inner join info as i on i.id = f.info_id where i.code = %s;" 136 cs.execute(sql, (stock_code,)) 137 # 股票代码不存在于focus表 138 if not cs.fetchall(): 139 close_mysql(conn, cs) 140 return "未曾关注,谈何取消。。" 141 sql = "delete from focus where info_id = (select id from info where code = %s);" 142 cs.execute(sql, (stock_code,)) 143 conn.commit() 144 close_mysql(conn, cs) 145 return "已成功取关注。。" 146 147 @route(r"/update/(\d+)\.html") 148 def update_info(ret): 149 '''更新数据''' 150 # 获取股票代码 151 stock_code = ret.group(1) 152 # 打开数据库,查询股票代码 153 conn, cs = open_mysql() 154 sql = "select * from info where code = %s;" 155 cs.execute(sql, (stock_code,)) 156 # 股票代码不在数据库中 157 if not cs.fetchall(): 158 # 返回提示 159 close_mysql(conn, cs) 160 return "没有这只股票代码,请收下留情。。" 161 # 判断股票代码是否已存在于focus表数据库中 162 sql = "select * from info as i inner join focus as f on i.id = f.info_id where i.code = %s" 163 cs.execute(sql, (stock_code,)) 164 # 已存在于focus表 165 if not cs.fetchall(): 166 close_mysql(conn, cs) 167 return "没有关注,请勿输入备注。。" 168 # 打开网页 169 with open("./templates/update.html", encoding="utf-8") as f: 170 content = f.read() 171 # 替换模板,回传数据 172 content = re.sub(r"\{%note_info%\}","请输入修改内容", content) 173 return re.sub(r"\{%code%\}", stock_code, content) 174 # return "更新数据成功。。" 175 176 @route(r"/update/(\d+)/(.*)\.html") 177 def save_update(ret): 178 stock_code = ret.group(1) 179 new_info = ret.group(2) 180 new_info = urllib.parse.unquote(new_info) 181 # 打开数据库,查询股票代码 182 conn, cs = open_mysql() 183 sql = "select * from info where code = %s;" 184 cs.execute(sql, (stock_code,)) 185 # 股票代码不在数据库中 186 if not cs.fetchall(): 187 # 返回提示 188 close_mysql(conn, cs) 189 return "没有这只股票代码,请收下留情。。" 190 # 判断股票代码是否已存在于focus表数据库中 191 sql = "select * from info as i inner join focus as f on i.id = f.info_id where i.code = %s" 192 cs.execute(sql, (stock_code,)) 193 # 不存在于focu表 194 if not cs.fetchall(): 195 close_mysql(conn, cs) 196 return "未曾关注,请勿修改。。" 197 # 已存在于focus表 198 # 执行sql语句添加股票代码到focus表 199 sql = "update focus set note_info=%s where info_id = (select id from info where code=%s);" 200 cs.execute(sql, (new_info, stock_code)) 201 conn.commit() 202 # 关闭数据库 203 close_mysql(conn, cs) 204 return "修改成功。。" 205 206 def application(env, start_header): 207 start_header("200 OK", [("Content-type", "text/html;charset=utf-8")]) 208 # 获取请求文件信息 209 file_name = env["PATH_INFO"] 210 file_name = urllib.parse.unquote(file_name) 211 # 日志设定 212 # 创建logger 213 logger = logging.getLogger() 214 logger.setLevel(logging.DEBUG) 215 # 创建一个handler,用于写入文件 216 logfile = "./log.txt" 217 fh = logging.FileHandler(logfile,mode='a') 218 fh.setLevel(logging.INFO) 219 # 创建一个handler,用于输出控制台 220 ch = logging.StreamHandler() 221 ch.setLevel(logging.WARNING) 222 # 定义日志输出格式 223 formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s") 224 fh.setFormatter(formatter) 225 ch.setFormatter(formatter) 226 # 将logger添加到handler中 227 logger.addHandler(fh) 228 logger.addHandler(ch) 229 logger.info("客户访问:%s" % file_name) 230 try: 231 for url, func in URL_FUNC_DICT.items(): 232 ret = re.match(url, file_name) 233 if ret: 234 return func(ret) 235 else: 236 logger.warning("请求错误。file(%s) not found" % file_name) 237 return "请求错误。file(%s) not found" % file_name 238 except Exception as e: 239 logger.warning("程序异常。错误信息:%s" % e) 240 return "请求错误。logger错误信息:%s" % e
1 import sys 2 import re 3 import socket 4 import multiprocessing 5 6 class WSGIServer(object): 7 '''服务器运行对象''' 8 def __init__(self, port, app, static_path): 9 '''对象初始化''' 10 # 创建套接字 11 self.tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 12 self.tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 13 # 绑定端口 IP 14 self.tcp_server_socket.bind(("", port)) 15 # 设置监听套接字 16 self.tcp_server_socket.listen(128) 17 # web框架调用方法 18 self.application = app 19 # 静态网页存放地址 20 self.static_path = static_path 21 22 def client_serve(self, client_socket): 23 '''为浏览器实现具体服务''' 24 # 获取浏览器请求 25 request = client_socket.recv(1024).decode("utf-8") 26 request_lines = request.splitlines() 27 # 解析浏览器请求 28 ret = re.match(r"[^/]+(/[^ ]*)", request_lines[0]) 29 file_name = "" 30 if ret: 31 file_name = ret.group(1) 32 if file_name == "/": 33 file_name = "/index.html" 34 # print("file_nema:", file_name) 35 # 如果为静态页面请求(非html请求) 36 if not file_name.endswith(".html"): 37 # 打开请求页面 38 try: 39 with open(self.static_path + file_name, "rb") as f: 40 response_body = f.read() 41 # 打开页面失败 42 except: 43 response_body = "file not found" 44 response_header = "HTTP/1.1 404 FILE NOT FOUND\r\n" 45 response_header += "\r\n" 46 response = response_header + response_body 47 client_socket.send(response.encode("utf-8")) 48 # 打开页面成功 49 else: 50 response_header = "HTTP/1.1 200 OK\r\n" 51 response_header += "\r\n" 52 response = response_header.encode("utf-8") + response_body 53 client_socket.send(response) 54 # 如果为动态页面请求 55 else: 56 env = dict() 57 env["PATH_INFO"] = file_name 58 # print(file_name) 59 # 调用web框架方法,处理页面 60 response_body = self.application(env, self.set_headers) 61 62 response_header = "HTTP/1.1 %s \r\n" % self.status 63 for header in self.header_list: 64 response_header += "%s:%s\r\n" %(header[0],header[1]) 65 response_header += "\r\n" 66 67 response = response_header + response_body 68 client_socket.send(response.encode("utf-8")) 69 # 关闭套接字 70 client_socket.close() 71 72 def set_headers(self, status, header_list): 73 '''存放web框架请求头信息''' 74 self.status = status 75 self.header_list = header_list 76 77 def fun_forever(self): 78 '''服务器对象流程控制''' 79 while True: 80 # print("等待浏览器连接") 81 client_socket, client_addr = self.tcp_server_socket.accept() 82 # 利用多进程实现多任务操作 83 # print("创建子线程") 84 p = multiprocessing.Process(target=self.client_serve, args=(client_socket,)) 85 p.start() 86 client_socket.close() 87 88 def error_msg(): 89 print("服务器开启失败,请按以下方式输入") 90 print("python xxx.py 8080 mini_frame:application") 91 92 def main(): 93 '''实现主体流程控制''' 94 # # 获取服务器端口、web_frame框架地址、方法名 95 # # 如果程序调用参数为3,输入正确 96 # if len(sys.argv) == 3: 97 # # 参数输入方式正确 98 # try: 99 # port = int(sys.argv[1]) 100 # frame_app_name = sys.argv[2] 101 # # 参数输入方式错误 102 # except: 103 # error_msg() 104 # # 如果不为3,调用方法错误,输出提示 105 # else: 106 # error_msg() 107 port = 8080 108 frame_app_name = "mini_frame:application" 109 # 打开配置文件,获取静态、动态文件夹地址 110 with open("web_server.conf") as f: 111 conf_info = eval(f.read()) 112 dynamic_path = conf_info["dynamic_path"] 113 sys.path.append(dynamic_path) 114 # 获取框架名、方法名 115 ret = re.match(r"([^:]+):(.*)", frame_app_name) 116 if ret: 117 frame_name = ret.group(1) 118 app_name = ret.group(2) 119 # print("app",app_name) 120 else: 121 error_msg() 122 # 导入web_frame框架 123 frame = __import__(frame_name) 124 # 导入app方法 125 app = getattr(frame, app_name) 126 # print("创建WSGI对象") 127 # 创建WSGI对象 128 wsgi_server = WSGIServer(port, app, conf_info["static_path"]) 129 # 调用其run_forever方法,使流程不断运行 130 wsgi_server.fun_forever() 131 132 if __name__ == "__main__": 133 main()