Python 创建本地服务器环境生成二维码

北城以北 提交于 2020-04-19 18:49:29

 

一. 需求

公司要做一个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+'\n')
    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+'\n')
    debugFile.close()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    main_widget = MainWidgetUI()
    main_widget.show()
    sys.exit(app.exec_())

 

六.运行效果

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!