乐趣区

关于python:使用QWebEngineView打造一款简单浏览器

应用 PyQt5 的 QWebEngineView 组件打造一款简略的浏览器
QWebEngineView 是 PyQt 中的一个能够显示网页的组件,该组件封装了谷歌浏览器内核,功能强大。老手试着实现一下,锤炼本人的编码能力。

成品图片
1 界面图片

2 界面图片

首先重写一下 QWebEngineView 类的 createWindow 函数
这个函数在 QWebEngineView 中点击跳转关上新页面的时候会被调用,如果不重写的话,页面链接跳转到新页面的时候就会没有反馈。

class MyWebView(QWebEngineView):
    
    def __init__(self, my, *args):
        super(MyWebView, self).__init__(*args)
        self.my = my
        # self.view = None

    def createWindow(self, QWebEnginePage_WebWindowType):
        #如果是要在本页面显示的页面则 return self
        return self.my.create_view() #创立一个新的容器显示新的页面
        

写一个用来装页面以及后退和后退刷新的界面

class Webbox(QWidget):
    def __init__(self, my, *args):
        super(Webbox, self).__init__(*args)
        self.my = my
        self.setGUI()

    def setGUI(self):
        self.webview = MyWebView(self.my, self)
        self.buttons = []
        self.url_input = QLineEdit(self)
        self.function_group = QButtonGroup(self)
        self.function_group.setExclusive(True)
        self.url_input.setStyleSheet(MyStyle.getInputStyle())
        self.homepage()
        self.webview.loadFinished.connect(self.update_view)
        icon = ['back.png', 'forward.png', 'reload.png', 'home.png']
        for i in icon:
            button = QPushButton(self)
            button.setIcon(QIcon(QPixmap(self.get_resource_path('static/' + i))))
            button.setStyleSheet(MyStyle.getIconButtonStyle())
            self.buttons.append(button)
        self.buttons[1].clicked.connect(lambda: self.webview.forward())
        self.buttons[0].clicked.connect(lambda: self.webview.back())
        self.buttons[2].clicked.connect(lambda: self.webview.reload())
        self.buttons[3].clicked.connect(self.homepage)
        self.url_input.returnPressed.connect(self.init)

    def homepage(self):
        self.webview.load(QUrl('https://www.baidu.com'))
        self.url_input.setText('https://www.baidu.com')

    def resizeEvent(self, a0: QtGui.QResizeEvent) -> None:
        self.buttons[0].setGeometry(5, 5, 45, 30)
        self.buttons[1].setGeometry(50 * 1 + 5, 5, 45, 30)
        self.buttons[2].setGeometry(50 * 2 + 5, 5, 45, 30)
        self.buttons[3].setGeometry(50 * 3 + 5, 5, 45, 30)
        self.url_input.setGeometry(50 * 4 + 5, 5, self.width() - 4 * 50 + 10 - 3 * 35 - 80, 30)
        self.webview.setGeometry(0, 40, self.width(), self.height() - 35)

    def init(self):
        if 'http' in self.url_input.text():
            self.webview.load(QUrl(self.url_input.text()))
        elif self.url_input.text() == '':
            self.zhuye()
        else:
            self.webview.load(QUrl(r'http://' + self.url_input.text()))
        self.url_input.setText(self.webview.url().toString())

    def update_view(self):
        self.url_input.setText(self.webview.url().toString())
        self.url_input.setCursorPosition(0)
        self.my.update_title(self)

    def get_resource_path(self, relative_path):
        if hasattr(sys, '_MEIPASS'):
            return os.path.join(sys._MEIPASS, relative_path)
        return os.path.join(os.path.abspath("."), relative_path)

创立一个装整个界面的窗口

class WebView(QWidget):
    def __init__(self, *args):
        super(WebView, self).__init__(*args)
        self.windows = []
        self.buttons = []
        self.setUI()

    def setUI(self):
        self.tabbar = QTabWidget(self)
        self.tabbar.setTabsClosable(True)
        self.tabbar.setStyleSheet(MyStyle.getQTabWidgetStyle())
        self.tabbar.tabCloseRequested.connect(self.close_tab)
        self.setStyleSheet(MyStyle.getQwidgetStyle2())
        # self.tabbar.setAttribute(Qt.WA_StyledBackground)
        self.proxies = QCheckBox('启用代理', self)
        self.proxies.clicked.connect(self.IsProxies)
        self.proxies.setStyleSheet(MyStyle.getCheckBoxStyle())
        view = Webbox(self)
        self.windows.append(view)
        self.tabbar.addTab(view, view.webview.title())
        self.buttonsname = ['shouchang1.png', 'shouchang2.png', 'more.png', 'add.png']
        for i in self.buttonsname:
            button = QPushButton(self)
            button.setIcon(QIcon(QPixmap(self.get_resource_path('static/' + i))))
            button.setStyleSheet(MyStyle.getIconButtonStyle())
            self.buttons.append(button)
        self.buttons[3].setStyleSheet(MyStyle.getButtonStyle2())
        self.buttons[3].setGeometry(self.tabbar.count() * 170, 0, 30, 30)
        self.buttons[3].clicked.connect(self.create_view)

    # 创立一个新的 Webobox 容器来装新的页面
    def create_view(self):
        try:
            view = Webbox(self)
            self.windows.append(view)
            self.tabbar.addTab(view, view.webview.title())
            self.tabbar.setCurrentWidget(view)
            if self.tabbar.count() * 150 > self.width():
                self.buttons[3].setGeometry(self.width()-40, 0, 30, 30)
            else:
                self.buttons[3].setGeometry(self.tabbar.count() * 170, 0, 30, 30)
            return view.webview
        except Exception as e:
            print(e)


    def close_tab(self, currentIndex):
        currentQWidget = self.tabbar.widget(currentIndex)
        currentQWidget.deleteLater()
        self.windows.remove(currentQWidget)
        self.tabbar.removeTab(currentIndex)
        if self.tabbar.count() * 150 > self.width():
            self.buttons[3].setGeometry(self.width()-40, 0, 30, 30)
        else:
            self.buttons[3].setGeometry(self.tabbar.count() * 170, 0, 30, 30)

    def resizeEvent(self, a0: QtGui.QResizeEvent) -> None:
        self.proxies.move(self.width() - 160, 41)
        self.buttons[0].setGeometry(self.width() - 40 * 3 -80, 7 + 30, 26, 26)
        self.buttons[1].setGeometry(self.width() - 35 * 2, 5 + 30, 30, 30)
        self.buttons[2].setGeometry(self.width() - 40, 5 + 30, 30, 30)
        self.tabbar.setGeometry(0, 0, self.width(), self.height())

    def update_title(self, view):
        self.tabbar.setTabText(self.tabbar.indexOf(view), view.webview.title())
    #这一块代码用于获取代码运行的门路
    def get_resource_path(self, relative_path):
        if hasattr(sys, '_MEIPASS'):
            return os.path.join(sys._MEIPASS, relative_path)
        return os.path.join(os.path.abspath("."), relative_path)

    # 这一块代码只是用于测试,具体性能没有实现
    def IsProxies(self):
        if self.proxies.isChecked():
            proxy = QtNetwork.QNetworkProxy()
            # Http 拜访代理
            proxy.setType = QtNetwork.QNetworkProxy.HttpProxy
            # 代理 ip 地址 HttpProxy
            proxy.setHostName("127.0.0.1")
            # 端口号
            proxy.setPort(8888)
            proxy.setUser("4")
            proxy.setPassword("1")
            QtNetwork.QNetworkProxy.setApplicationProxy(proxy)

代码中所用到的图片以及其余类
一个用来寄存 QSS 款式的类
因为不想从其余文件夹读取 qss 文件,所以间接写了一个款式类寄存 qss 款式,如果你只写了一个很简略的窗口,qss 款式很少的时候能够应用这种办法,在打包 exe 的时候能够不必额定打包款式文件。

class MyStyle():
    @staticmethod
    def getIconButtonStyle():
        return '''
        QPushButton{background-color:rgba(0,0,0,0);
            border-radius:3px;
            boder:none;
        }
        QPushButton:hover{background-color:rgb(230,230,230);
        }
        QPushButton:pressed{background-color:rgb(210,210,210);
        }
        '''
    @staticmethod
    def getButtonStyle2():
        return '''
        QPushButton{background-color:rgb(236,245,255);
            font-family:"SimSun";
            funt-size:18px;
            
        }
        QPushButton:hover{background-color:rgb(64,158,255);
            color:white;
        }
        QPushButton:pressed{background-color:rgb(58,142,230);
        }
        '''

    @staticmethod
    def getInputStyle():
        return '''
        QLineEdit{
            border-radius:3px;
            border-style:solid;
            border-width:1px;
            font-size: 16px;
            padding-right:40px;
            font-family:"Microsoft YaHei";
            border-color:rgb(200,200,200);
            background-color:white;
        }
        QLineEdit:hover{border-color:rgb(150,150,150);
        }
        
        QLineEdit:focus{border-color:rgb(102,177,255);
        }
        '''

    @staticmethod
    def getQTabWidgetStyle():
        return '''
        QTabWidget{background-color:rgb(240,240,240);
        }
        
        QTabBar::tab {background-color:rgb(236,245,255);
            height:30px;
            padding-left:10px;
            padding-right:10px;
            margin-top:0px;
            min-width:150px;
            max-width:150px;
         }
        QTabBar::tab:hover{color:rgb(64,158,255);
        }
        
        QTabBar::tab:selected{
            color:white;
            background:rgb(64,158,255);
        }
        QTabBar::close-button{image: url(static/close.png);
            background-color:rgba(0,0,0,0);
        }
        QTabBar::close-button:hover {image: url(static/close2.png);
        }
        '''

    @staticmethod
    def getQwidgetStyle2():
        return'''
        QWidget{background-color:rgb(250,250,250);
            border:none;
        }
        '''

    @staticmethod
    def getCheckBoxStyle():
        return '''
        QCheckBox{color:rgb(150,150,150);
            Background-color:rgba(0,0,0,0);
        }
        QCheckBox:hover{Color:rgb(149,216,255);
        }
        QCheckBox:checked{color:rgb(64,158,255);
        }

        '''

代码中用到的按钮图标
下载窗口中用到的按钮图标文件请点击这里

整体代码

##!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Author : Tang Shimeng

import os
import sys

from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5 import QtNetwork, QtGui
from PyQt5.QtCore import QUrl
from PyQt5.QtGui import QPixmap, QIcon
from PyQt5.QtWidgets import QWidget, QTabWidget, QApplication, QButtonGroup, QLineEdit, QPushButton, QCheckBox


class MyStyle():
    @staticmethod
    def getIconButtonStyle():
        return '''
        QPushButton{background-color:rgba(0,0,0,0);
            border-radius:3px;
            boder:none;
        }
        QPushButton:hover{background-color:rgb(230,230,230);
        }
        QPushButton:pressed{background-color:rgb(210,210,210);
        }
        '''
    @staticmethod
    def getButtonStyle2():
        return '''
        QPushButton{background-color:rgb(236,245,255);
            font-family:"SimSun";
            funt-size:18px;
            
        }
        QPushButton:hover{background-color:rgb(64,158,255);
            color:white;
        }
        QPushButton:pressed{background-color:rgb(58,142,230);
        }
        '''

    @staticmethod
    def getInputStyle():
        return '''
        QLineEdit{
            border-radius:3px;
            border-style:solid;
            border-width:1px;
            font-size: 16px;
            padding-right:40px;
            font-family:"Microsoft YaHei";
            border-color:rgb(200,200,200);
            background-color:white;
        }
        QLineEdit:hover{border-color:rgb(150,150,150);
        }
        
        QLineEdit:focus{border-color:rgb(102,177,255);
        }
        '''

    @staticmethod
    def getQTabWidgetStyle():
        return '''
        QTabWidget{background-color:rgb(240,240,240);
        }
        
        QTabBar::tab {background-color:rgb(236,245,255);
            height:30px;
            padding-left:10px;
            padding-right:10px;
            margin-top:0px;
            min-width:150px;
            max-width:150px;
         }
        QTabBar::tab:hover{color:rgb(64,158,255);
        }
        
        QTabBar::tab:selected{
            color:white;
            background:rgb(64,158,255);
        }
        QTabBar::close-button{image: url(static/close.png);
            background-color:rgba(0,0,0,0);
        }
        QTabBar::close-button:hover {image: url(static/close2.png);
        }
        '''

    @staticmethod
    def getQwidgetStyle2():
        return'''
        QWidget{background-color:rgb(250,250,250);
            border:none;
        }
        '''

    @staticmethod
    def getCheckBoxStyle():
        return '''
        QCheckBox{color:rgb(150,150,150);
            Background-color:rgba(0,0,0,0);
        }
        QCheckBox:hover{Color:rgb(149,216,255);
        }
        QCheckBox:checked{color:rgb(64,158,255);
        }

        '''

class MyWebView(QWebEngineView):

    def __init__(self, my, *args):
        super(MyWebView, self).__init__(*args)
        self.my = my
        # self.view = None

    def createWindow(self, QWebEnginePage_WebWindowType):
        return self.my.create_view()


class Webbox(QWidget):
    def __init__(self, my, *args):
        super(Webbox, self).__init__(*args)
        self.my = my
        self.setGUI()

    def setGUI(self):
        self.webview = MyWebView(self.my, self)
        self.buttons = []
        self.url_input = QLineEdit(self)
        self.function_group = QButtonGroup(self)
        self.function_group.setExclusive(True)
        self.url_input.setStyleSheet(MyStyle.getInputStyle())
        self.homepage()
        self.webview.loadFinished.connect(self.update_view)
        icon = ['back.png', 'forward.png', 'reload.png', 'home.png']
        for i in icon:
            button = QPushButton(self)
            button.setIcon(QIcon(QPixmap(self.get_resource_path('static/' + i))))
            button.setStyleSheet(MyStyle.getIconButtonStyle())
            self.buttons.append(button)
        self.buttons[1].clicked.connect(lambda: self.webview.forward())
        self.buttons[0].clicked.connect(lambda: self.webview.back())
        self.buttons[2].clicked.connect(lambda: self.webview.reload())
        self.buttons[3].clicked.connect(self.homepage)
        self.url_input.returnPressed.connect(self.init)

    def homepage(self):
        self.webview.load(QUrl('https://www.baidu.com'))
        self.url_input.setText('https://www.baidu.com')

    def resizeEvent(self, a0: QtGui.QResizeEvent) -> None:
        self.buttons[0].setGeometry(5, 5, 45, 30)
        self.buttons[1].setGeometry(50 * 1 + 5, 5, 45, 30)
        self.buttons[2].setGeometry(50 * 2 + 5, 5, 45, 30)
        self.buttons[3].setGeometry(50 * 3 + 5, 5, 45, 30)
        self.url_input.setGeometry(50 * 4 + 5, 5, self.width() - 4 * 50 + 10 - 3 * 35 - 80, 30)
        self.webview.setGeometry(0, 40, self.width(), self.height() - 35)

    def init(self):
        if 'http' in self.url_input.text():
            self.webview.load(QUrl(self.url_input.text()))
        elif self.url_input.text() == '':
            self.zhuye()
        else:
            self.webview.load(QUrl(r'http://' + self.url_input.text()))
        self.url_input.setText(self.webview.url().toString())

    def update_view(self):
        self.url_input.setText(self.webview.url().toString())
        self.url_input.setCursorPosition(0)
        self.my.update_title(self)

    def get_resource_path(self, relative_path):
        if hasattr(sys, '_MEIPASS'):
            return os.path.join(sys._MEIPASS, relative_path)
        return os.path.join(os.path.abspath("."), relative_path)



class WebView(QWidget):
    def __init__(self, *args):
        super(WebView, self).__init__(*args)
        self.windows = []
        self.buttons = []
        self.setUI()

    def setUI(self):
        self.tabbar = QTabWidget(self)
        self.tabbar.setTabsClosable(True)
        self.tabbar.setStyleSheet(MyStyle.getQTabWidgetStyle())
        self.tabbar.tabCloseRequested.connect(self.close_tab)
        self.setStyleSheet(MyStyle.getQwidgetStyle2())
        # self.tabbar.setAttribute(Qt.WA_StyledBackground)
        self.proxies = QCheckBox('启用代理', self)
        self.proxies.clicked.connect(self.IsProxies)
        self.proxies.setStyleSheet(MyStyle.getCheckBoxStyle())
        view = Webbox(self)
        self.windows.append(view)
        self.tabbar.addTab(view, view.webview.title())
        self.buttonsname = ['shouchang1.png', 'shouchang2.png', 'more.png', 'add.png']
        for i in self.buttonsname:
            button = QPushButton(self)
            button.setIcon(QIcon(QPixmap(self.get_resource_path('static/' + i))))
            button.setStyleSheet(MyStyle.getIconButtonStyle())
            self.buttons.append(button)
        self.buttons[3].setStyleSheet(MyStyle.getButtonStyle2())
        self.buttons[3].setGeometry(self.tabbar.count() * 170, 0, 30, 30)
        self.buttons[3].clicked.connect(self.create_view)

    # 创立一个新的 Webobox 容器来装新的页面
    def create_view(self):
        try:
            view = Webbox(self)
            self.windows.append(view)
            self.tabbar.addTab(view, view.webview.title())
            self.tabbar.setCurrentWidget(view)
            if self.tabbar.count() * 150 > self.width():
                self.buttons[3].setGeometry(self.width()-40, 0, 30, 30)
            else:
                self.buttons[3].setGeometry(self.tabbar.count() * 170, 0, 30, 30)
            return view.webview
        except Exception as e:
            print(e)


    def close_tab(self, currentIndex):
        currentQWidget = self.tabbar.widget(currentIndex)
        currentQWidget.deleteLater()
        self.windows.remove(currentQWidget)
        self.tabbar.removeTab(currentIndex)
        if self.tabbar.count() * 150 > self.width():
            self.buttons[3].setGeometry(self.width()-40, 0, 30, 30)
        else:
            self.buttons[3].setGeometry(self.tabbar.count() * 170, 0, 30, 30)

    def resizeEvent(self, a0: QtGui.QResizeEvent) -> None:
        self.proxies.move(self.width() - 160, 41)
        self.buttons[0].setGeometry(self.width() - 40 * 3 -80, 7 + 30, 26, 26)
        self.buttons[1].setGeometry(self.width() - 35 * 2, 5 + 30, 30, 30)
        self.buttons[2].setGeometry(self.width() - 40, 5 + 30, 30, 30)
        self.tabbar.setGeometry(0, 0, self.width(), self.height())

    def update_title(self, view):
        self.tabbar.setTabText(self.tabbar.indexOf(view), view.webview.title())

    def get_resource_path(self, relative_path):
        if hasattr(sys, '_MEIPASS'):
            return os.path.join(sys._MEIPASS, relative_path)
        return os.path.join(os.path.abspath("."), relative_path)

    def IsProxies(self):
        if self.proxies.isChecked():
            proxy = QtNetwork.QNetworkProxy()
            # Http 拜访代理
            proxy.setType = QtNetwork.QNetworkProxy.HttpProxy
            # 代理 ip 地址 HttpProxy
            proxy.setHostName("127.0.0.1")
            # 端口号
            proxy.setPort(8888)
            proxy.setUser("4")
            proxy.setPassword("1")
            QtNetwork.QNetworkProxy.setApplicationProxy(proxy)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = WebView()
    window.resize(800, 500)
    window.setMinimumWidth(800)
    window.setWindowTitle('Browser')
    window.setWindowIcon(QIcon(window.get_resource_path("static/ico.png")))
    window.show()
    sys.exit(app.exec_())

代码逻辑不难,重在参加。

退出移动版