YOGYUI

PyQt5 - QtWebEngine::웹브라우저 만들기 (3) 본문

Software/Python

PyQt5 - QtWebEngine::웹브라우저 만들기 (3)

요겨 2021. 9. 6. 18:00
반응형

4. 네비게이션 툴바 만들기

북마크바를 만들려고 하다보니, 탭 안의 위젯이 url 에디트 등의 컨트롤들을 각각 모두 가지고 있는 것이 불합리해보여서 별도로 네비게이션 툴바를 만들었다 (QToolBar 상속)

[NavigationWidget.py]

from PyQt5.QtCore import pyqtSignal, QSize
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QToolBar, QToolButton, QLineEdit

class NavigationToolBar(QToolBar):
    _is_loading: bool = False

    sig_navigate_url = pyqtSignal(str)
    sig_go_backward = pyqtSignal()
    sig_go_forward = pyqtSignal()
    sig_reload = pyqtSignal()
    sig_stop = pyqtSignal()
    sig_go_home = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__('Navigation', parent=parent)
        self.editUrl = QLineEdit()
        self.btnBackward = QToolButton()
        self.btnForward = QToolButton()
        self.btnReload = QToolButton()
        self.btnHome = QToolButton()
        self._iconRefresh = QIcon('./Resource/reload.png')
        self._iconStop = QIcon('./Resource/cancel.png')
        self.initControl()
        self.initLayout()
        stylesheet = "QToolBar {border: 0x;}"
        self.setStyleSheet(stylesheet)

    def initLayout(self):
        self.setIconSize(QSize(22, 22))
        self.addWidget(self.btnBackward)
        self.addWidget(self.btnForward)
        self.addWidget(self.btnReload)
        self.addWidget(self.btnHome)
        self.addWidget(self.editUrl)
        self.editUrl.setFixedHeight(24)
        font = self.editUrl.font()
        font.setPointSize(11)
        self.editUrl.setFont(font)

    def initControl(self):
        self.editUrl.returnPressed.connect(self.onEditUrlReturnPressed)
        self.btnBackward.setEnabled(False)
        self.btnBackward.clicked.connect(self.sig_go_backward.emit)
        self.btnBackward.setIcon(QIcon('./Resource/previous.png'))
        self.btnBackward.setToolTip('Previous')
        self.btnForward.setEnabled(False)
        self.btnForward.clicked.connect(self.sig_go_forward.emit)
        self.btnForward.setIcon(QIcon('./Resource/forward.png'))
        self.btnForward.setToolTip('Forward')
        self.btnReload.clicked.connect(self.onClickBtnStopRefresh)
        self.btnReload.setIcon(self._iconRefresh)
        self.btnReload.setToolTip('Reload')
        self.btnHome.clicked.connect(self.sig_go_home.emit)
        self.btnHome.setIcon(QIcon('./Resource/home.png'))
        self.btnHome.setToolTip('Home')

    def onEditUrlReturnPressed(self):
        self.sig_navigate_url.emit(self.editUrl.text())

    def onClickBtnStopRefresh(self):
        if self._is_loading:
            self.sig_stop.emit()
        else:
            self.sig_reload.emit()

    def setEditUrlFocused(self):
        self.editUrl.setFocus()
        self.editUrl.selectAll()

    def setIsLoading(self, loading: bool):
        self._is_loading = loading
        if loading:
            self.btnReload.setIcon(self._iconStop)
        else:
            self.btnReload.setIcon(self._iconRefresh)

기존 위젯 (WebPageWidget)의 네비게이션 관련 컨트롤들은 모두 제거한 후, 윈도우(WebBrowserWindow)에 네비게이션 툴바 관련 객체 추가 및 시그널들을 연결해줬다 (메뉴바도 추가)

[WebBrowserWindow.py]

# ...
from NavigationWidget import NavigationToolBar
from PyQt5.QtWidgets import QMenuBar, QMenu, QAction

class WebBrowserWindow(QMainWindow):
    _mb_show_navbar: QAction
    
    def __init__(self, parent=None, init_url: Union[str, QUrl, None] = 'about:blank'):
        # ...
        self._navBar = NavigationToolBar(self)
        self._menuBar = QMenuBar(self)
        self.initMenuBar()
    
    def initControl(self):
        self.addToolBar(Qt.TopToolBarArea, self._navBar)
        self._navBar.sig_navigate_url.connect(self.onNavBarNavitageUrl)
        self._navBar.sig_go_backward.connect(self.onNavBarGoBackward)
        self._navBar.sig_go_forward.connect(self.onNavBarGoForward)
        self._navBar.sig_reload.connect(self.onNavBarReload)
        self._navBar.sig_stop.connect(self.onNavBarStop)
        self._navBar.sig_go_home.connect(self.onNavBarGoHome)
    
    def initMenuBar(self):
        self.setMenuBar(self._menuBar)
        menuFile = QMenu('File', self._menuBar)
        self._menuBar.addAction(menuFile.menuAction())
        mb_close = makeQAction(parent=self, text='Close', triggered=self.close)
        menuFile.addAction(mb_close)

        menuView = QMenu('View', self._menuBar)
        self._menuBar.addAction(menuView.menuAction())
        self._mb_show_navbar = makeQAction(parent=self, text='Navigation Bar', checkable=True, triggered=self.toggleNavigationBar)
        menuView.addAction(self._mb_show_navbar)
        menuView.aboutToShow.connect(self.onMenuViewAboutToShow)

    def onMenuViewAboutToShow(self):
        self._mb_show_navbar.setChecked(self._navBar.isVisible())
    
        def onNavBarNavitageUrl(self, url: str):
        curwgt = self._tabWidget.currentWidget()
        if isinstance(curwgt, WebPageWidget):
            curwgt.load(url)

    def onNavBarGoBackward(self):
        curwgt = self._tabWidget.currentWidget()
        if isinstance(curwgt, WebPageWidget):
            curwgt.view().back()

    def onNavBarGoForward(self):
        curwgt = self._tabWidget.currentWidget()
        if isinstance(curwgt, WebPageWidget):
            curwgt.view().forward()

    def onNavBarReload(self):
        curwgt = self._tabWidget.currentWidget()
        if isinstance(curwgt, WebPageWidget):
            curwgt.view().reload()

    def onNavBarStop(self):
        curwgt = self._tabWidget.currentWidget()
        if isinstance(curwgt, WebPageWidget):
            curwgt.view().stop()

    def onNavBarGoHome(self):
        curwgt = self._tabWidget.currentWidget()
        if isinstance(curwgt, WebPageWidget):
            curwgt.load(self._config.url_home)

    def refreshNavBarState(self):
        curwgt = self._tabWidget.currentWidget()
        if isinstance(curwgt, WebPageWidget):
            history = curwgt.view().history()
            self._navBar.btnBackward.setEnabled(history.canGoBack())
            self._navBar.btnForward.setEnabled(history.canGoForward())
    
    def onPageLoadStarted(self, view: WebPageWidget):
        curwgt = self._tabWidget.currentWidget()
        if curwgt == view:
            self._navBar.setIsLoading(True)
            self.refreshNavBarState()

    def onPageLoadFinished(self, view: WebPageWidget):
        curwgt = self._tabWidget.currentWidget()
        if curwgt == view:
            self._navBar.setIsLoading(False)
            self.refreshNavBarState()
    
    def toggleNavigationBar(self):
        if self._navBar.isVisible():
            self._navBar.hide()
        else:
            self._navBar.show()

네비게이션 툴바 추가

5. 북마크 툴바 만들기

북마크 바도 네비게이션 바와 똑같이 QToolBar를 상속해서 만들어보자

(테스트를 위해 네이버와 구글 아이템을 수동으로 추가)

[BookMarkWidget.py]

import urllib.request
from functools import partial
from PyQt5.QtCore import Qt, pyqtSignal, QSize
from PyQt5.QtGui import QIcon, QPixmap
from PyQt5.QtWidgets import QToolBar, QToolButton

class BookMarkToolBar(QToolBar):
    sig_navitage = pyqtSignal(str)

    def __init__(self, parent=None):
        super().__init__('Bookmark', parent=parent)
        stylesheet = "QToolBar {border: 0px; spacing: 0px;}"
        self.setStyleSheet(stylesheet)

        self._bookmarks = list()
        self._bookmarks.append({
            'url': 'https://www.naver.com/',
            'title': 'NAVER',
            'icon_url': 'https://www.naver.com/favicon.ico?1',
        })
        self._bookmarks.append({
            'url': 'https://www.google.com/',
            'title': 'Google',
            'icon_url': 'https://www.google.com/favicon.ico',
        })
        self.setIconSize(QSize(18, 18))
        self.drawItems()

    def drawItems(self):
        self.clear()
        for item in self._bookmarks:
            data = urllib.request.urlopen(item.get('icon_url')).read()
            pixmap = QPixmap()
            pixmap.loadFromData(data)
            icon = QIcon(pixmap)

            btn = QToolButton()
            btn.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
            btn.setIcon(icon)
            btn.setText(item.get('title'))
            btn.setToolTip(item.get('title'))
            btn.clicked.connect(partial(self.sig_navitage.emit, item.get('url')))

            self.addWidget(btn)

브라우저 윈도우에 툴바를 추가해주자

from BookMarkWidget import BookMarkToolBar

class WebBrowserWindow(QMainWindow):
    _mb_show_bookmark: QAction
    
    def __init__(self, parent=None, init_url: Union[str, QUrl, None] = 'about:blank'):
        # ...
        self._bookmarkBar = BookMarkToolBar(self)
    
    def initControl(self):
        self.addToolBar(Qt.TopToolBarArea, self._navBar)
        # ...
        self.addToolBarBreak(Qt.TopToolBarArea)
        self.addToolBar(Qt.TopToolBarArea, self._bookmarkBar)
        self._bookmarkBar.sig_navitage.connect(self.onNavBarNavitageUrl)
    
    def initMenuBar(self):
        # ...
        self._mb_show_bookmark = makeQAction(parent=self, text='Bookmark Bar', checkable=True, triggered=self.toggleBookMarkBar)
        menuView.addAction(self._mb_show_bookmark)
    
    def onMenuViewAboutToShow(self):
        self._mb_show_navbar.setChecked(self._navBar.isVisible())
        self._mb_show_bookmark.setChecked(self._bookmarkBar.isVisible())
    
    def toggleBookMarkBar(self):
        if self._bookmarkBar.isVisible():
            self._bookmarkBar.hide()
        else:
            self._bookmarkBar.show()

북마크 테스트

이제 북마크 관리 기능을 만들어보자

5.1. 북마크 매니저 만들기

BookMarkItem, BookMarkManager 클래스 구현

[BookMarkWidget.py]

import urllib.request
from typing import List
from functools import partial
from PyQt5.QtCore import Qt, pyqtSignal, QSize, QObject
from PyQt5.QtGui import QIcon, QPixmap
from PyQt5.QtWidgets import QToolBar, QToolButton

class BookMarkItem:
    def __init__(self, url: str, title: str, icon_url: str):
        self.url = url
        self.title = title
        self.icon_url = icon_url

class BookMarkManager(QObject):
    sig_changed = pyqtSignal()

    def __init__(self):
        super().__init__()
        self.bookmarks: List[BookMarkItem] = list()

    def urlList(self) -> List[str]:
        return [x.url for x in self.bookmarks]

    def isExist(self, url: str):
        return url in self.urlList()

    def add(self, url: str, title: str, icon_url: str):
        self.bookmarks.append(BookMarkItem(url, title, icon_url))
        self.sig_changed.emit()

    def remove(self, url: str):
        find = list(filter(lambda x: x.url == url, self.bookmarks))
        if len(find) >= 1:
            self.bookmarks.remove(find[0])
        self.sig_changed.emit()

class BookMarkToolBar(QToolBar):
    sig_navitage = pyqtSignal(str)

    def __init__(self, manager: BookMarkManager, parent=None):
        super().__init__('Bookmark', parent=parent)
        stylesheet = "QToolBar {border: 0px; spacing: 0px;}"
        self.setStyleSheet(stylesheet)
        self._manager = manager
        self._manager.sig_changed.connect(self.drawItems)

        self.setIconSize(QSize(18, 18))
        self.drawItems()

    def drawItems(self):
        self.clear()
        for item in self._manager.bookmarks:
            try:
                data = urllib.request.urlopen(item.icon_url).read()
                pixmap = QPixmap()
                pixmap.loadFromData(data)
                icon = QIcon(pixmap)

                btn = QToolButton()
                btn.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
                btn.setIcon(icon)
                btn.setText(item.title)
                btn.setToolTip(item.title)
                btn.clicked.connect(partial(self.sig_navitage.emit, item.url))

                self.addWidget(btn)
            except Exception:
                pass

- 툴바 아이템은 버튼에 표시할 타이틀(title), 실제 네비게이션할 주소(url), 표시할 아이콘 주소(icon_url) 멤버변수를 갖도록 구현했다

- 툴바에 아이템(QToolButton)을 추가할 때, 지정된 아이콘 URL을 urllib 패키지의 request를 사용해서 데이터를 읽어온 뒤 QPixmap으로 변환하여 아이콘을 만드는 방법을 사용했다

- 북마크 매니저의 아이템 리스트가 변경될 때마다 콜백 시그널을 호출해 툴바가 바로바로 새로 그리도록 구현했다 (합리적인 UX는 아니다...)

5.2. 브라우저 설정 파일 관리

북마크 아이템을 관리하기 위해 로컬에 xml 파일로 저장/불러오기할 수 있도록 WebBrowserConfig 클래스를 구현하자

[ConfigUtil.py]

import os
import xml.etree.ElementTree as ET
from BookMarkWidget import BookMarkManager
from Common import writeXmlFile


class WebBrowserConfig:
    def __init__(self, bookmarkManager: BookMarkManager):
        curpath = os.path.dirname(os.path.abspath(__file__))
        configpath = os.path.join(os.path.dirname(curpath), 'Config')
        self.xml_path = os.path.join(configpath, 'config.xml')

        self.url_home = 'about:blank'
        self.bookmarkManager = bookmarkManager
        self.load_from_xml()

    def load_from_xml(self):
        if not os.path.isfile(self.xml_path):
            self.save_to_xml()
        xmldata = ET.parse(self.xml_path)
        root = xmldata.getroot()

        node = root.find('home')
        if node is not None:
            self.url_home = node.text

        node = root.find('bookmarks')
        if node is not None:
            for child in list(node):
                title = child.tag
                url = child.attrib.get('url')
                icon_url = child.attrib.get('icon_url')
                self.bookmarkManager.add(url, title, icon_url)

    def save_to_xml(self):
        if os.path.isfile(self.xml_path):
            xmldata = ET.parse(self.xml_path)
        else:
            xmldata = ET.ElementTree(ET.Element('BrowserConfig'))
        root = xmldata.getroot()

        node = root.find('home')
        if node is None:
            node = ET.Element('home')
            root.append(node)
        node.text = self.url_home

        node = root.find('bookmarks')
        if node is None:
            node = ET.Element('bookmarks')
            root.append(node)

            for item in self.bookmarkManager.bookmarks:
                child = node.find(item.title)
                if child is None:
                    child = ET.Element(item.title)
                    node.append(child)
                child.attrib['url'] = item.url
                child.attrib['icon_url'] = item.icon_url

        writeXmlFile(root, self.xml_path, backup=False)

* writeXmlFile 함수 구현 내역은 GitHub 참고

5.3. 네비게이션 바, 브라우저 윈도우 수정

북마크 관련 버튼을 추가해주자

[NavigationWidget.py]

class NavigationToolBar(QToolBar):
    # ...
    sig_toggle_bookmark = pyqtSignal()
    
    def __init__(self, parent=None):
        # ...
        self.btnBookmark = QToolButton()
        self._iconBookmarkOff = QIcon('./Resource/bookmark_off.png')
        self._iconBookmarkOn = QIcon('./Resource/bookmark_on.png')
    
    def initLayout(self):
        # ...
        self.addWidget(self.btnBookmark)
    
    def initControl(self):
        # ...
        self.btnBookmark.clicked.connect(self.sig_toggle_bookmark.emit)
        self.btnBookmark.setIcon(self._iconBookmarkOff)
        self.btnBookmark.setToolTip('BookMark')
    
    def setBookMarkStatus(self, exist: bool):
        if exist:
            self.btnBookmark.setIcon(self._iconBookmarkOn)
        else:
            self.btnBookmark.setIcon(self._iconBookmarkOff)

 

북마크매니저, 북마크바, 네비게이션바의 이벤트를 서로 연결해주자

[WebBrowserWindow.py]

from BookMarkWidget import BookMarkToolBar, BookMarkManager

class WebBrowserWindow(QMainWindow):
    def __init__(self, parent=None, init_url: Union[str, QUrl, None] = 'about:blank'):
        # ...
        self._bookMarkManager = BookMarkManager()
        self._config = WebBrowserConfig(self._bookMarkManager)
        self._bookmarkBar = BookMarkToolBar(self._bookMarkManager, self)
    
    def release(self):
        self.closeWebPageAll()
        self._config.save_to_xml()
    
    def onNavBarToggleBookmark(self):
        curwgt = self._tabWidget.currentWidget()
        if isinstance(curwgt, WebPageWidget):
            url = curwgt.view().url().toString()
            if self._bookMarkManager.isExist(url):
                self._bookMarkManager.remove(url)
            else:
                url_icon = curwgt.view().iconUrl().toString()
                title = curwgt.view().title()
                self._bookMarkManager.add(url, title, url_icon)
            self.refreshNavBarState()
    
    def refreshNavBarState(self):
        curwgt = self._tabWidget.currentWidget()
        if isinstance(curwgt, WebPageWidget):
            history = curwgt.view().history()
            self._navBar.btnBackward.setEnabled(history.canGoBack())
            self._navBar.btnForward.setEnabled(history.canGoForward())

            bookmark_url_list = self._bookMarkManager.urlList()
            self._navBar.setBookMarkStatus(curwgt.view().url().toString() in bookmark_url_list)

- refreshNavBarState 호출 시, 현재 텝 페이지의 URL이 북마크 매니저 아이템 리스트에 존재하는지 여부에 따라 네비게이션 툴바 북마크 아이템의 아이콘을 변경하도록 구현했다

북마크바 사용 데모

/Config/config.xml 파일이 생성되고 북마크 정보가 저장되었으며, 다음 실행부터 해당 북마크가 적용된다

[config.xml]

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<BrowserConfig>
    <home>naver.com</home>
    <bookmarks>
        <NAVER url="https://www.naver.com/" icon_url="https://www.naver.com/favicon.ico?1"/>
        <Google url="https://www.google.com/" icon_url="https://www.google.com/favicon.ico"/>
        <Daum url="https://www.daum.net/" icon_url="https://www.daum.net/favicon.ico"/>
    </bookmarks>
</BrowserConfig>

일반 브라우저처럼 북마크를 사용하기 위해서는 다음 기능들이 추가로 구현되어야 한다

TODO: 북마크 아이템 옮기기, 북마크 폴더 기능, 북마크바 컨텍스트 메뉴

6. 자바스크립트 실행

QWebEnginePage는 자바스크립트 실행을 위한 runJavaScript 메서드를 제공한다

출처: https://doc.qt.io/qt-5/qwebenginepage.html#runJavaScript

콜백함수를 등록하면 실행결과를 QVariant 객체로 리턴받을 수 있다고 한다

가이드를 따라 간단하게 구현해보자

 

개발자도구로 활용할 위젯을 하나 만들었다

[DeveloperWidget.py]

from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QWidget, QTextEdit, QPushButton, QLineEdit
from PyQt5.QtWidgets import QVBoxLayout, QGroupBox, QSizePolicy

class DeveloperWidget(QWidget):
    sig_run_js = pyqtSignal(str)

    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self._editJavaScript = QTextEdit()
        self._btnRunJavaScript = QPushButton('RUN')
        self._editJsResult = QLineEdit()
        self.initControl()
        self.initLayout()

    def initLayout(self):
        vbox = QVBoxLayout(self)
        vbox.setContentsMargins(4, 4, 4, 4)
        vbox.setSpacing(4)

        grbox = QGroupBox('JavaScript')
        grbox.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed)
        vbox_gr = QVBoxLayout(grbox)
        vbox_gr.setContentsMargins(4, 4, 4, 4)
        vbox_gr.setSpacing(4)
        vbox_gr.addWidget(self._editJavaScript)
        vbox_gr.addWidget(self._btnRunJavaScript)
        vbox_gr.addWidget(self._editJsResult)
        vbox.addWidget(grbox)

        vbox.addWidget(QWidget())

    def initControl(self):
        self._editJavaScript.setLineWrapColumnOrWidth(-1)
        self._editJavaScript.setLineWrapMode(QTextEdit.FixedPixelWidth)
        self._btnRunJavaScript.clicked.connect(self.onClickBtnRunJavaScript)
        self._editJsResult.setReadOnly(True)

    def onClickBtnRunJavaScript(self):
        script = self._editJavaScript.toPlainText()
        self.sig_run_js.emit(script)

    def setJsResult(self, obj: object):
        self._editJsResult.setText(str(obj))

WebPageWidget에 자바스크립트 관련 구문을 추가해주자

[WebPageWidget.py]

class WebPageWidget(QWidget):
    sig_js_result = pyqtSignal(object)
    # ...
    def runJavaScript(self, script: str):
        self.view().page().runJavaScript(script, self.jsCallback)

    def jsCallback(self, v: QVariant):
        self.sig_js_result.emit(v)

브라우저 윈도우의 central widget을 QSplitter로 바꾼 뒤, Splitter에 탭 위젯과 개발자 위젯을 배치한 뒤 시그널들을 연결해주자

[WebBrowserWindow.py]

from PyQt5.QtWidgets import QSplitter
from DeveloperWidget import DeveloperWidget

class WebBrowserWindow(QMainWindow):
    _mb_show_devtool: QAction
    
    def __init__(self, parent=None, init_url: Union[str, QUrl, None] = 'about:blank'):
        # ...
        self._splitter = QSplitter(Qt.Horizontal, self)
        self._tabWidget = CustomTabWidget()
        self._devWidget = DeveloperWidget()
    
    def initLayout(self):
        self.setCentralWidget(self._splitter)
        self._splitter.addWidget(self._tabWidget)
        self._splitter.addWidget(self._devWidget)
        self._devWidget.hide()
    
    def initControl(self):
        self._splitter.setStyleSheet("QSplitter:handle:horizontal {background:rgb(204,206,219); margin:1px 1px}")
        # ...
        self._devWidget.sig_run_js.connect(self.runJavaScript)
        
    def initMenuBar(self):
        self._mb_show_devtool = makeQAction(parent=self, text='Dev Tool', checkable=True, triggered=self.toggleDevTool)
        menuView.addAction(self._mb_show_devtool)
    
    def onMenuViewAboutToShow(self):
        self._mb_show_devtool.setChecked(self._devWidget.isVisible())
    
    def toggleDevTool(self):
        if self._devWidget.isVisible():
            self._devWidget.hide()
        else:
            self._devWidget.show()
    
    def runJavaScript(self, script: str):
        curwgt = self._tabWidget.currentWidget()
        if isinstance(curwgt, WebPageWidget):
            curwgt.runJavaScript(script)

    def onJavaScriptResult(self, obj: object):
        self._devWidget.setJsResult(obj)

 

현재 로드된 페이지의 타이틀을 자바스크립트로 가져와보자 (document.title 호출)

 

안타깝게도 QWebEnginePage의 자바스크립트 엔진으로 리턴받을 수 있는 객체 타입은 한정적이다

네이버 메인 페이지에서 특정 element의 영역 정보를 가져와보자

document.getElementsByClassName("nav_item")[0].getBoundingClientRect();

예시 코드는 네이버 메인 페이지 네비게이션 아이템 중 '메일' element의 geometry를 가져오는 코드

크롬 개발자도구에서 실행해보자

DOMRect 객체가 반환된다

하지만 QWebEnginePage의 반환결과는 

class WebPageWidget(QWidget):
    def jsCallback(self, v: QVariant):
        print(v, type(v))
        self.sig_js_result.emit(v)
{} <class 'dict'>

dict형으로 반환되는데, 내용물은 없다

 

결과물을 JSON으로 변환하면 일단 dict형으로 제대로 받아볼 수는 있다

document.getElementsByClassName("nav_item")[0].getBoundingClientRect().toJSON();
{'bottom': 251, 'height': 30, 'left': 30, 'right': 89.40625, 'top': 221, 'width': 59.40625, 'x': 30, 'y': 221} <class 'dict'>

한계가 있는만큼 활용도가 높지는 않다

JS를 효과적으로 구동할 수 있는 다른 방법이 있는지 찾아봐야겠다

 

지금까지의 구현 내용은 다음 깃허브 링크에서 확인할 수 있다

https://github.com/YOGYUI/Projects/tree/rev.3/WebBrowser/python

 

GitHub - YOGYUI/Projects

Contribute to YOGYUI/Projects development by creating an account on GitHub.

github.com

 

일단 코어 기능은 그럭저럭 완성했으니 이제 쉬엄쉬엄 업데이트해나갈 예정이다

(블로그 포스트는 안할지도...)

반응형