zoukankan      html  css  js  c++  java
  • Python 创建本地服务器环境生成二维码

    一. 需求

    公司要做一个H5手机端适配页面,因技术问题所以H5是外包的,每次前端给我们源码,我们把源码传到服务器让其他人访问看是否存在bug,这个不是很麻烦吗?有人说,可以让前端在他们的服务器上先托管,等我们验收了后在给源码不结了嘛,是的呀!所有的人都愿意这样,but……

    要是能在本地搭建环境直接访问是不是更好的。问题是我们这边程序此刻没时间与H5前端对接,既浪费我们时间又浪费他们时间。所以开发一个service服务器让测试人员直接参与,这样就可以把我们完美分工了。

    二.Python搭建web服务器

    Python自带一个http.serrver包可以简单的搭建web服务器

    官网:https://docs.python.org/3/library/http.server.html?highlight=httpserver#http.server.BaseHTTPRequestHandler

    参考:

    http://www.cnblogs.com/xuxn/archive/2011/02/14/build-simple-web-server-with-python.html

    http://blog.csdn.net/kevin_darkelf/article/details/40979545

    http://blog.csdn.net/tianmohust/article/details/7689414

    # return Html page
    class MyHttpBaseHandler(BaseHTTPRequestHandler):
        def do_GET(self):
            print(self.path)
            enc = "UTF-8"
            encoded = ''.join(self.path).encode(enc)
            f = io.BytesIO()
            f.write(encoded)
            f.seek(0)
            self.send_response(200)
            self.send_header("Content-type", "text/html; charset=%s" % enc)
            self.send_header("Content-Length", str(len(encoded)))
            self.end_headers()
            shutil.copyfileobj(f, self.wfile)
    
        # This method serves the 'POST' request type, only allowed for CGI scripts.
        def do_POST(self):
            pass
    
    
    # return  static  -m  eg:python -m http.server 8080
    class MyHttpSimpleHandler(SimpleHTTPRequestHandler):
        pass


    httpd = HTTPServer((self.addressIP, self.port), MyHttpSimpleHandler)
    print("Server started on " + self.addressIP + ",port " + str(self.port) + ".....")
    httpd.serve_forever()
     

    三. 绘制UI,生成二维码

    之前写过

    Pyqt+QRcode 生成 识别 二维码

    直接参考生成二维码

    绘制UI

    class MainWidgetUI(QDialog):
        def __init__(self, parent=None):
            super(MainWidgetUI, self).__init__(parent)
            self.setFixedSize(640, 480)  # PyQT禁止调整窗口大小
            self.setWindowTitle('Python 创建本地服务器环境生成二维码')
            self.setWindowIcon(QtGui.QIcon("favicon.ico"))
            # Main布局
            main_layout = QVBoxLayout()
            self.methodtype = QComboBox()
            self.methodTopLayout = QHBoxLayout()
            self.methodtype.addItem('文件', QVariant(1))  # 使用 QVariant保存Key
            self.methodtype.addItem('地址', QVariant(2))
            self.methodtype.setFixedWidth(90)  # 设置固定不变的宽度为90px
            self.pushButton = QPushButton("选择文件")
            self.Url = QLineEdit()
            self.Url.hide()
            self.methodTopLayout.addWidget(self.methodtype)  # 添加一个挂件
            self.methodTopLayout.addWidget(self.Url)  # 添加一个挂件
            self.methodTopLayout.addSpacing(10)  # 添加一个10px的空间距离 且不带弹性
            self.methodTopLayout.addWidget(self.pushButton)
            self.qrcodeGroup = QVBoxLayout()
            self.groupBox = QGroupBox("二维码")
            self.QrLabel = QLabel(self.groupBox)
    
            self.qrcodeGroup.addWidget(self.groupBox)
            main_layout.addLayout(self.methodTopLayout)  # 添加一个布局
            main_layout.addLayout(self.qrcodeGroup)
            self.setLayout(main_layout)
            self.QrLabel.setGeometry(QRect(30, 30, 540, 380))  # 设置qrLabel 的图形位置
            # self.QrLabel.setScaledContents(True)  # 按比例缩放二维码显示内容
    
            self.pushButton.clicked.connect(self.FileOperator)  # 点击按钮
            self.methodtype.currentIndexChanged.connect(self.comboxchange)  # 下拉框改变时候事件
            self.Url.textChanged.connect(self.comboxchange)  # 当地址文本框内容改变时触发

    生成二维码

        # 获取服务器(地址) 生成二维码
        def ShowQrCode(self, strings):
            if not strings:  # 参数为空,pixmap为空
                self.QrLabel.setPixmap(QtGui.QPixmap(""))
            else:
                qr = qrcode.QRCode(version=None, error_correction=qrcode.constants.ERROR_CORRECT_L, box_size=10, border=2, )
                qr.add_data(strings)
                qr.make(fit=True)
                img = qr.make_image()
                qraddr=tempDir+'qr.png'
                print(qraddr)
                img.save(qraddr)

    很简单,通过选择文件获取路径,将文件copy到当前目录,将当前目录设置为http.server服务目录,二维码则为服务地址+文件名

    四.注意的事项

    1. 获取当前局域网IP

    addressIP = socket.gethostbyname_ex(socket.gethostname())[-1][0]  # 获取局域网IP

    2.获取windows临时目录

    tempDir = tempfile.gettempdir() + '/'  # 获取临时temp目录

    3. copy文件

    copy文件有两种,一种为Python自带,另一种为Pyqt中方法

    shutil.copy(filePath, "./")  # 文件=>目录
    QFile.copy(filePath, sys.path[0]+"\"+file)   #  QFile.copy 必须文件对=>文件

    4. 使用线程开启服务

    直接在UI中开启httpd.serve_forever() 会导致UI堵塞,所以使用QtCore.QThread 线程开启http服务

    5.动态调整UI大小

    参数不同导致生成的二维码大小不同,所以要动态修改UI大小以便将整个二维码显示全

                qrsize = Image.open(qraddr).size
                if qrsize[0] > 400:  # 二维码的像素值大于400的时候动态修改窗体的大小
                    dsize = qrsize[0] // 2  # 取整数部分
                    self.setFixedSize(640 + dsize, 480 + dsize)
                    self.QrLabel.setGeometry(QRect(30, 30, 540 + dsize, 380 + dsize))
                else:
                    self.setFixedSize(640, 480)
                    self.QrLabel.setGeometry(QRect(30, 30, 540, 380))
                self.QrLabel.setPixmap(QtGui.QPixmap(qraddr))

    6. 通过判断文件的md5对比文件是否为最新版文件

        if filePath:
                file = filePath.split('/')[-1]
                isfExist = os.path.exists(file)
                if not isfExist:  # 不存在文件
                    shutil.copy(filePath, "./")  # 文件对=>目录
                else:  # 已经存在文件,对比文件md5 判断是否为最新文件
                    md5FilePath = self.getFileMD5(filePath)
                    md5File = self.getFileMD5(file)
                    if md5File != md5FilePath:
                        shutil.copy(filePath,  "./")
    
    
        # 获取文件的MD5值,适用于小文件
        def getFileMD5(self, filepath):
            f = open(filepath, 'rb')
            md5obj = hashlib.md5()
            md5obj.update(f.read())
            hash = md5obj.hexdigest()
            f.close()
            return str(hash).upper()

    7.生成debug.log 日志

    def delog(string='--'):
        debugFile=open("debog.txt",'a',1,'utf-8')
        debugFile.writelines(string+'
    ')
        debugFile.close()

    五.完整代码

    # -*- coding: UTF8 -*-
    import io, shutil, sys, os
    from http.server import HTTPServer, BaseHTTPRequestHandler, SimpleHTTPRequestHandler
    from PyQt5.QtWidgets import *
    from PyQt5.QtCore import *
    from PyQt5 import QtGui
    import qrcode
    from PIL import Image
    import socket
    import hashlib
    import tempfile
    
    
    port = 8080  # 默认端口
    addressIP = socket.gethostbyname_ex(socket.gethostname())[-1][0]  # 获取局域网IP
    tempDir = tempfile.gettempdir() + '/'  # 获取临时temp目录
    
    
    class MainWidgetUI(QDialog):
        def __init__(self, parent=None):
            super(MainWidgetUI, self).__init__(parent)
            self.setFixedSize(640, 480)  # PyQT禁止调整窗口大小
            self.setWindowTitle('Python 创建本地服务器环境生成二维码')
            self.setWindowIcon(QtGui.QIcon("favicon.ico"))
            # Main布局
            main_layout = QVBoxLayout()
            self.methodtype = QComboBox()
            self.methodTopLayout = QHBoxLayout()
            self.methodtype.addItem('文件', QVariant(1))  # 使用 QVariant保存Key
            self.methodtype.addItem('地址', QVariant(2))
            self.methodtype.setFixedWidth(90)  # 设置固定不变的宽度为90px
            self.pushButton = QPushButton("选择文件")
            self.Url = QLineEdit()
            self.Url.hide()
            self.methodTopLayout.addWidget(self.methodtype)  # 添加一个挂件
            self.methodTopLayout.addWidget(self.Url)  # 添加一个挂件
            self.methodTopLayout.addSpacing(10)  # 添加一个10px的空间距离 且不带弹性
            self.methodTopLayout.addWidget(self.pushButton)
            self.qrcodeGroup = QVBoxLayout()
            self.groupBox = QGroupBox("二维码")
            self.QrLabel = QLabel(self.groupBox)
    
            self.qrcodeGroup.addWidget(self.groupBox)
            main_layout.addLayout(self.methodTopLayout)  # 添加一个布局
            main_layout.addLayout(self.qrcodeGroup)
            self.setLayout(main_layout)
            self.QrLabel.setGeometry(QRect(30, 30, 540, 380))  # 设置qrLabel 的图形位置
            # self.QrLabel.setScaledContents(True)  # 按比例缩放二维码显示内容
    
            self.pushButton.clicked.connect(self.FileOperator)  # 点击按钮
            self.methodtype.currentIndexChanged.connect(self.comboxchange)  # 下拉框改变时候事件
            self.Url.textChanged.connect(self.comboxchange)  # 当地址文本框内容改变时触发
    
        # 文件操作
        def FileOperator(self):
            filePath = self.selectFile()
            if filePath:
                file = filePath.split('/')[-1]
                isfExist = os.path.exists(file)
                if not isfExist:  # 不存在文件
                    shutil.copy(filePath, "./")  # 文件对=>目录
                    # delog(a)  #  打包exe调试日志log
                    # QFile.copy(filePath, sys.path[0]+"\"+file)  QFile.copy 必须文件对=>文件
                else:  # 已经存在文件,对比文件md5 判断是否为最新文件
                    md5FilePath = self.getFileMD5(filePath)
                    md5File = self.getFileMD5(file)
                    if md5File != md5FilePath:
                        shutil.copy(filePath,  "./")
    
                # 拼接二维码参数
                address = "http://" + addressIP + ':' + str(port) + '/' + file
                self.ShowQrCode(address)  # 显示二维码
                print('生成qrcord')
                self.Theading = TheadingPost((addressIP, port))  # 开进程打开服务-直接启动http.service 会导致UI进程无响应
                self.Theading.start()  # 线程开始
    
    
    
        # 获取文件的MD5值,适用于小文件
        def getFileMD5(self, filepath):
            f = open(filepath, 'rb')
            md5obj = hashlib.md5()
            md5obj.update(f.read())
            hash = md5obj.hexdigest()
            f.close()
            return str(hash).upper()
    
        # 选择文件
        def selectFile(self):
            # getOpenFileName  只能选择一个    getOpenFileNames  可多个选择
            files = QFileDialog.getOpenFileName(self, "请选择播放文件", '', "*.*")
            if files[0] == '':
                QMessageBox.warning(self, u'错误提示!', "请选择文件", QMessageBox.Yes)
            else:
                return files[0]
    
        # 下拉框选择
        def comboxchange(self):
            currentIndex = self.methodtype.currentIndex()  # currentIndex  索引是从0开始自增
            key = self.methodtype.itemData(currentIndex)  # QVariant 保存的 key
    
            #  self.methodtype.currentText()  # 文本
            if key == 1:  # 文件
                self.pushButton.show()
                self.Url.hide()
                self.ShowQrCode("")
            elif key == 2:  # 地址
                self.pushButton.hide()
                self.Url.show()
                url = self.Url.text()
                self.ShowQrCode(url)
    
        # 获取服务器(地址) 生成二维码12
        def ShowQrCode(self, strings):
            if not strings:  # 参数为空,pixmap为空
                self.QrLabel.setPixmap(QtGui.QPixmap(""))
            else:
                qr = qrcode.QRCode(version=None, error_correction=qrcode.constants.ERROR_CORRECT_L, box_size=10, border=2, )
                qr.add_data(strings)
                qr.make(fit=True)
                img = qr.make_image()
                qraddr=tempDir+'qr.png'
                print(qraddr)
                img.save(qraddr)
                qrsize = Image.open(qraddr).size
                if qrsize[0] > 400:  # 二维码的像素值大于400的时候动态修改窗体的大小
                    dsize = qrsize[0] // 2  # 取整数部分
                    self.setFixedSize(640 + dsize, 480 + dsize)
                    self.QrLabel.setGeometry(QRect(30, 30, 540 + dsize, 380 + dsize))
                else:
                    self.setFixedSize(640, 480)
                    self.QrLabel.setGeometry(QRect(30, 30, 540, 380))
                self.QrLabel.setPixmap(QtGui.QPixmap(qraddr))
    
    
    # return Html page
    class MyHttpBaseHandler(BaseHTTPRequestHandler):
        def do_GET(self):
            print(self.path)
            enc = "UTF-8"
            encoded = ''.join(self.path).encode(enc)
            f = io.BytesIO()
            f.write(encoded)
            f.seek(0)
            self.send_response(200)
            self.send_header("Content-type", "text/html; charset=%s" % enc)
            self.send_header("Content-Length", str(len(encoded)))
            self.end_headers()
            shutil.copyfileobj(f, self.wfile)
    
        # This method serves the 'POST' request type, only allowed for CGI scripts.
        def do_POST(self):
            pass
    
    
    # return  static  -m  eg:python -m http.server 8080
    class MyHttpSimpleHandler(SimpleHTTPRequestHandler):
        pass
    
    
    # 启动服务
    class TheadingPost(QThread):
        def __init__(self, list):
            super(TheadingPost, self).__init__()
            self.addressIP = list[0]
            self.port = list[1]
    
        def run(self):
            httpd = HTTPServer((self.addressIP, self.port), MyHttpSimpleHandler)
            print("Server started on " + self.addressIP + ",port " + str(self.port) + ".....")
            httpd.serve_forever()
    
    def delog(string='--'):
        debugFile=open("debog.txt",'a',1,'utf-8')
        debugFile.writelines(string+'
    ')
        debugFile.close()
    
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        main_widget = MainWidgetUI()
        main_widget.show()
        sys.exit(app.exec_())

    六.运行效果

  • 相关阅读:
    Linux中profile、bashrc、bash_profile之间的区别和联系
    指针长度长几何
    快速理解网络协议视频总结
    gdb调试关键点记录
    调试经验积累
    定位网页元素
    浮动
    盒子模型
    css3
    css
  • 原文地址:https://www.cnblogs.com/dcb3688/p/4608035.html
Copyright © 2011-2022 走看看