基于 cefpython 實現嵌入 Chromium (CEF)

CEF Python是一個開源項目,旨在為Chromium Embedded Framework提供Python綁定,許多流行的GUI工具包都提供了嵌入CEF瀏覽器,例如QT。

安裝

pip install cefpython3==66.1

支持的Python版本:
1

實現打開網頁

from cefpython3 import cefpython as cef
import platform
import sysdef main():check_versions()sys.excepthook = cef.ExceptHook  # To shutdown all CEF processes on errorcef.Initialize()cef.CreateBrowserSync(url="https://www.google.com/",window_title="Hello World!")cef.MessageLoop()cef.Shutdown()def check_versions():ver = cef.GetVersion()print("[hello_world.py] CEF Python {ver}".format(ver=ver["version"]))print("[hello_world.py] Chromium {ver}".format(ver=ver["chrome_version"]))print("[hello_world.py] CEF {ver}".format(ver=ver["cef_version"]))print("[hello_world.py] Python {ver} {arch}".format(ver=platform.python_version(),arch=platform.architecture()[0]))assert cef.__version__ >= "57.0", "CEF Python v57.0+ required to run this"if __name__ == '__main__':main()

綁定js

"""
Communicate between Python and Javascript asynchronously using
inter-process messaging with the use of Javascript Bindings.
"""from cefpython3 import cefpython as cefg_htmlcode = """
<!doctype html>
<html>
<head><style>body, html {font-family: Arial;font-size: 11pt;}</style><script>function print(msg) {document.getElementById("console").innerHTML += msg+"<br>";}function js_function(value) {print("Value sent from Python: <b>"+value+"</b>");py_function("I am a Javascript string #1", js_callback);}function js_callback(value, py_callback) {print("Value sent from Python: <b>"+value+"</b>");py_callback("I am a Javascript string #2");}</script>
</head>
<body><h1>Javascript Bindings</h1><div id=console></div>
</body>
</html>
"""def main():cef.Initialize()browser = cef.CreateBrowserSync(url=cef.GetDataUrl(g_htmlcode),window_title="Javascript Bindings")browser.SetClientHandler(LoadHandler())bindings = cef.JavascriptBindings()bindings.SetFunction("py_function", py_function)bindings.SetFunction("py_callback", py_callback)browser.SetJavascriptBindings(bindings)cef.MessageLoop()del browsercef.Shutdown()def py_function(value, js_callback):print("Value sent from Javascript: "+value)js_callback.Call("I am a Python string #2", py_callback)def py_callback(value):print("Value sent from Javascript: "+value)class LoadHandler(object):def OnLoadEnd(self, browser, **_):browser.ExecuteFunction("js_function", "I am a Python string #1")if __name__ == '__main__':main()

鍵盤處理

from cefpython3 import cefpython as cefdef main():cef.Initialize()browser = cef.CreateBrowserSync(url="https://www.google.com/",window_title="Keyboard Handler")browser.SetClientHandler(KeyboardHandler())cef.MessageLoop()del browsercef.Shutdown()class KeyboardHandler(object):def OnKeyEvent(self, browser, event, event_handle,  **_):print("OnKeyEvent: "+str(event))if __name__ == '__main__':main()

鼠標點擊

# Perform mouse clicks and mouse movements programmatically.from cefpython3 import cefpython as cefdef main():cef.Initialize()browser = cef.CreateBrowserSync(url="data:text/html,<h1>Mouse clicks snippet</h1>""This text will be selected after one second.<br>""This text will be selected after two seconds.",window_title="Mouse clicks")browser.SetClientHandler(LifespanHandler())cef.MessageLoop()del browsercef.Shutdown()def click_after_1_second(browser):print("Click after 1 second")# Mouse move to the top-left corner of the textbrowser.SendMouseMoveEvent(0, 70, False, 0)# Left mouse button click in the top-left corner of the textbrowser.SendMouseClickEvent(0, 70, cef.MOUSEBUTTON_LEFT, False, 1)# Mouse move to the bottom-right corner of the text,# while holding left mouse button.browser.SendMouseMoveEvent(400, 80, False, cef.EVENTFLAG_LEFT_MOUSE_BUTTON)# Release left mouse buttonbrowser.SendMouseClickEvent(400, 80, cef.MOUSEBUTTON_LEFT, True, 1)cef.PostDelayedTask(cef.TID_UI, 1000, click_after_2_seconds, browser)def click_after_2_seconds(browser):print("Click after 2 seconds")browser.SendMouseMoveEvent(0, 90, False, 0)browser.SendMouseClickEvent(0, 90, cef.MOUSEBUTTON_LEFT, False, 1)browser.SendMouseMoveEvent(400, 99, False, cef.EVENTFLAG_LEFT_MOUSE_BUTTON)browser.SendMouseClickEvent(400, 99, cef.MOUSEBUTTON_LEFT, True, 1)cef.PostDelayedTask(cef.TID_UI, 1000, click_after_1_second, browser)class LifespanHandler(object):def OnLoadEnd(self, browser, **_):# Execute function with a delay of 1 second after page# has completed loading.print("Page loading is complete")cef.PostDelayedTask(cef.TID_UI, 1000, click_after_1_second, browser)if __name__ == '__main__':main()

網絡Cookie

"""
Implement RequestHandler.CanGetCookies and CanSetCookie
to block or allow cookies over network requests.
"""from cefpython3 import cefpython as cefdef main():cef.Initialize()browser = cef.CreateBrowserSync(url="http://www.html-kit.com/tools/cookietester/",window_title="Network cookies")browser.SetClientHandler(RequestHandler())cef.MessageLoop()del browsercef.Shutdown()class RequestHandler(object):def __init__(self):self.getcount = 0self.setcount = 0def CanGetCookies(self, frame, request, **_):# There are multiple iframes on that website, let's log# cookies only for the main frame.if frame.IsMain():self.getcount += 1print("-- CanGetCookies #"+str(self.getcount))print("url="+request.GetUrl()[0:80])print("")# Return True to allow reading cookies or False to blockreturn Truedef CanSetCookie(self, frame, request, cookie, **_):# There are multiple iframes on that website, let's log# cookies only for the main frame.if frame.IsMain():self.setcount += 1print("-- CanSetCookie @"+str(self.setcount))print("url="+request.GetUrl()[0:80])print("Name="+cookie.GetName())print("Value="+cookie.GetValue())print("")# Return True to allow setting cookie or False to blockreturn Trueif __name__ == '__main__':main()

關閉前

"""
Implement LifespanHandler.OnBeforeClose to execute custom
code before browser window closes.
"""from cefpython3 import cefpython as cefdef main():cef.Initialize()browser = cef.CreateBrowserSync(url="https://www.google.com/",window_title="OnBeforeClose")browser.SetClientHandler(LifespanHandler())cef.MessageLoop()del browsercef.Shutdown()class LifespanHandler(object):def OnBeforeClose(self, browser):print("Browser ID: {}".format(browser.GetIdentifier()))print("Browser will close and app will exit")if __name__ == '__main__':main()

DOM 就緒

"""
Execute custom Python code on a web page as soon as DOM is ready.
Implements a custom "_OnDomReady" event in the LoadHandler object.
"""from cefpython3 import cefpython as cefdef main():cef.Initialize()browser = cef.CreateBrowserSync(url="https://www.google.com/",window_title="_OnDomReady event")load_handler = LoadHandler(browser)browser.SetClientHandler(load_handler)bindings = cef.JavascriptBindings()bindings.SetFunction("LoadHandler_OnDomReady",load_handler["_OnDomReady"])browser.SetJavascriptBindings(bindings)cef.MessageLoop()del load_handlerdel browsercef.Shutdown()class LoadHandler(object):def __init__(self, browser):self.browser = browserdef __getitem__(self, key):return getattr(self, key)def OnLoadStart(self, browser, **_):browser.ExecuteJavascript("""if (document.readyState === "complete") {LoadHandler_OnDomReady();} else {document.addEventListener("DOMContentLoaded", function() {LoadHandler_OnDomReady();});}""")def _OnDomReady(self):print("DOM is ready!")self.browser.ExecuteFunction("alert","Message from Python: DOM is ready!")if __name__ == '__main__':main()

頁面加載完畢

"""
Execute custom Python code on a web page when page loading is complete.
Implements a custom "_OnPageComplete" event in the LoadHandler object.
"""from cefpython3 import cefpython as cefdef main():cef.Initialize()browser = cef.CreateBrowserSync(url="https://www.google.com/",window_title="_OnPageComplete event")browser.SetClientHandler(LoadHandler())cef.MessageLoop()del browsercef.Shutdown()class LoadHandler(object):def OnLoadingStateChange(self, browser, is_loading, **_):"""For detecting if page loading has ended it is recommendedto use OnLoadingStateChange which is most reliable. The OnLoadEndcallback also available in LoadHandler can sometimes fail insome cases e.g. when image loading hangs."""if not is_loading:self._OnPageComplete(browser)def _OnPageComplete(self, browser):print("Page loading is complete!")browser.ExecuteFunction("alert", "Message from Python: Page loading"" is complete!")if __name__ == '__main__':main()

設置Cookie

"""
Shows how to set a cookie.
"""from cefpython3 import cefpython as cef
import datetimedef main():cef.Initialize()cef.CreateBrowserSync(url="http://www.html-kit.com/tools/cookietester/",window_title="Set a cookie")manager = cef.CookieManager.GetGlobalManager()cookie = cef.Cookie()cookie.Set({"name": "my_cookie","value": "my_value",# Make sure domain is a valid value otherwise it crashes# app (Issue #459)"domain": "www.html-kit.com","path": "/","secure": False,"httpOnly": False,"creation": datetime.datetime(2018, 8, 22),"lastAccess": datetime.datetime(2018, 8, 22),"hasExpires": True,"expires": datetime.datetime(2028, 12, 31, 23, 59, 59),})manager.SetCookie("http://www.html-kit.com/", cookie)cef.MessageLoop()cef.Shutdown()if __name__ == '__main__':main()

窗口大小

"""
Set initial window size to 900/640px without use of
any third party GUI framework. On Linux/Mac you can set
window size by calling WindowInfo.SetAsChild. On Windows
you can accomplish this by calling Windows native functions
using the ctypes module.
"""from cefpython3 import cefpython as cef
import ctypes
import platformdef main():cef.Initialize()window_info = cef.WindowInfo()parent_handle = 0# This call has effect only on Mac and Linux.# All rect coordinates are applied including X and Y parameters.window_info.SetAsChild(parent_handle, [0, 0, 900, 640])browser = cef.CreateBrowserSync(url="https://www.google.com/",window_info=window_info,window_title="Window size")if platform.system() == "Windows":window_handle = browser.GetOuterWindowHandle()insert_after_handle = 0# X and Y parameters are ignored by setting the SWP_NOMOVE flagSWP_NOMOVE = 0x0002# noinspection PyUnresolvedReferencesctypes.windll.user32.SetWindowPos(window_handle, insert_after_handle,0, 0, 900, 640, SWP_NOMOVE)cef.MessageLoop()del browsercef.Shutdown()if __name__ == '__main__':main()

嵌入 QT

# Example of embedding CEF browser using PyQt4, PyQt5 and
# PySide libraries. This example has two widgets: a navigation
# bar and a browser.
#
# Tested configurations:
# - PyQt 5.8.2 (qt 5.8.0) on Windows/Linux/Mac
# - PyQt 4.10.4 / 4.11.4 (qt 4.8.6 / 4.8.7) on Windows/Linux
# - PySide 1.2.1 (qt 4.8.6) on Windows/Linux/Mac
# - PySide2 5.6.0, 5.11.2 (qt 5.6.2, 5.11.2) on Windows/Linux/Mac
# - CEF Python v55.4+
#
# Issues with PySide 1.2:
# - Mac: Keyboard focus issues when switching between controls (Issue #284)
# - Mac: Mouse cursor never changes when hovering over links (Issue #311)from cefpython3 import cefpython as cef
import ctypes
import os
import platform
import sys# GLOBALS
PYQT4 = False
PYQT5 = False
PYSIDE = False
PYSIDE2 = Falseif "pyqt4" in sys.argv:PYQT4 = True# noinspection PyUnresolvedReferencesfrom PyQt4.QtGui import *# noinspection PyUnresolvedReferencesfrom PyQt4.QtCore import *
elif "pyqt5" in sys.argv:PYQT5 = True# noinspection PyUnresolvedReferencesfrom PyQt5.QtGui import *# noinspection PyUnresolvedReferencesfrom PyQt5.QtCore import *# noinspection PyUnresolvedReferencesfrom PyQt5.QtWidgets import *
elif "pyside" in sys.argv:PYSIDE = True# noinspection PyUnresolvedReferencesimport PySide# noinspection PyUnresolvedReferencesfrom PySide import QtCore# noinspection PyUnresolvedReferencesfrom PySide.QtGui import *# noinspection PyUnresolvedReferencesfrom PySide.QtCore import *
elif "pyside2" in sys.argv:PYSIDE2 = True# noinspection PyUnresolvedReferencesimport PySide2# noinspection PyUnresolvedReferencesfrom PySide2 import QtCore# noinspection PyUnresolvedReferencesfrom PySide2.QtGui import *# noinspection PyUnresolvedReferencesfrom PySide2.QtCore import *# noinspection PyUnresolvedReferencesfrom PySide2.QtWidgets import *
else:print("USAGE:")print("  qt.py pyqt4")print("  qt.py pyqt5")print("  qt.py pyside")print("  qt.py pyside2")sys.exit(1)# Fix for PyCharm hints warnings when using static methods
WindowUtils = cef.WindowUtils()# Platforms
WINDOWS = (platform.system() == "Windows")
LINUX = (platform.system() == "Linux")
MAC = (platform.system() == "Darwin")# Configuration
WIDTH = 800
HEIGHT = 600# OS differences
CefWidgetParent = QWidget
if LINUX and (PYQT4 or PYSIDE):# noinspection PyUnresolvedReferencesCefWidgetParent = QX11EmbedContainerdef main():check_versions()sys.excepthook = cef.ExceptHook  # To shutdown all CEF processes on errorsettings = {}if MAC:# Issue #442 requires enabling message pump on Mac# in Qt example. Calling cef.DoMessageLoopWork in a timer# doesn't work anymore.settings["external_message_pump"] = Truecef.Initialize(settings)app = CefApplication(sys.argv)main_window = MainWindow()main_window.show()main_window.activateWindow()main_window.raise_()app.exec_()if not cef.GetAppSetting("external_message_pump"):app.stopTimer()del main_window  # Just to be safe, similarly to "del app"del app  # Must destroy app object before calling Shutdowncef.Shutdown()def check_versions():print("[qt.py] CEF Python {ver}".format(ver=cef.__version__))print("[qt.py] Python {ver} {arch}".format(ver=platform.python_version(), arch=platform.architecture()[0]))if PYQT4 or PYQT5:print("[qt.py] PyQt {v1} (qt {v2})".format(v1=PYQT_VERSION_STR, v2=qVersion()))elif PYSIDE:print("[qt.py] PySide {v1} (qt {v2})".format(v1=PySide.__version__, v2=QtCore.__version__))elif PYSIDE2:print("[qt.py] PySide2 {v1} (qt {v2})".format(v1=PySide2.__version__, v2=QtCore.__version__))# CEF Python version requirementassert cef.__version__ >= "55.4", "CEF Python v55.4+ required to run this"class MainWindow(QMainWindow):def __init__(self):# noinspection PyArgumentListsuper(MainWindow, self).__init__(None)# Avoids crash when shutting down CEF (issue #360)if PYSIDE:self.setAttribute(Qt.WA_DeleteOnClose, True)self.cef_widget = Noneself.navigation_bar = Noneif PYQT4:self.setWindowTitle("PyQt4 example")elif PYQT5:self.setWindowTitle("PyQt5 example")elif PYSIDE:self.setWindowTitle("PySide example")elif PYSIDE2:self.setWindowTitle("PySide2 example")self.setFocusPolicy(Qt.StrongFocus)self.setupLayout()def setupLayout(self):self.resize(WIDTH, HEIGHT)self.cef_widget = CefWidget(self)self.navigation_bar = NavigationBar(self.cef_widget)layout = QGridLayout()# noinspection PyArgumentListlayout.addWidget(self.navigation_bar, 0, 0)# noinspection PyArgumentListlayout.addWidget(self.cef_widget, 1, 0)layout.setContentsMargins(0, 0, 0, 0)layout.setSpacing(0)layout.setRowStretch(0, 0)layout.setRowStretch(1, 1)# noinspection PyArgumentListframe = QFrame()frame.setLayout(layout)self.setCentralWidget(frame)if (PYSIDE2 or PYQT5) and WINDOWS:# On Windows with PyQt5 main window must be shown first# before CEF browser is embedded, otherwise window is# not resized and application hangs during resize.self.show()# Browser can be embedded only after layout was set upself.cef_widget.embedBrowser()if (PYSIDE2 or PYQT5) and LINUX:# On Linux with PyQt5 the QX11EmbedContainer widget is# no more available. An equivalent in Qt5 is to create# a hidden window, embed CEF browser in it and then# create a container for that hidden window and replace# cef widget in the layout with the container.# noinspection PyUnresolvedReferences, PyArgumentListself.container = QWidget.createWindowContainer(self.cef_widget.hidden_window, parent=self)# noinspection PyArgumentListlayout.addWidget(self.container, 1, 0)def closeEvent(self, event):# Close browser (force=True) and free CEF referenceif self.cef_widget.browser:self.cef_widget.browser.CloseBrowser(True)self.clear_browser_references()def clear_browser_references(self):# Clear browser references that you keep anywhere in your# code. All references must be cleared for CEF to shutdown cleanly.self.cef_widget.browser = Noneclass CefWidget(CefWidgetParent):def __init__(self, parent=None):# noinspection PyArgumentListsuper(CefWidget, self).__init__(parent)self.parent = parentself.browser = Noneself.hidden_window = None  # Required for PyQt5 on Linuxself.show()def focusInEvent(self, event):# This event seems to never get called on Linux, as CEF is# stealing all focus due to Issue #284.if cef.GetAppSetting("debug"):print("[qt.py] CefWidget.focusInEvent")if self.browser:if WINDOWS:WindowUtils.OnSetFocus(self.getHandle(), 0, 0, 0)self.browser.SetFocus(True)def focusOutEvent(self, event):# This event seems to never get called on Linux, as CEF is# stealing all focus due to Issue #284.if cef.GetAppSetting("debug"):print("[qt.py] CefWidget.focusOutEvent")if self.browser:self.browser.SetFocus(False)def embedBrowser(self):if (PYSIDE2 or PYQT5) and LINUX:# noinspection PyUnresolvedReferencesself.hidden_window = QWindow()window_info = cef.WindowInfo()rect = [0, 0, self.width(), self.height()]window_info.SetAsChild(self.getHandle(), rect)self.browser = cef.CreateBrowserSync(window_info,url="https://www.google.com/")self.browser.SetClientHandler(LoadHandler(self.parent.navigation_bar))self.browser.SetClientHandler(FocusHandler(self))def getHandle(self):if self.hidden_window:# PyQt5 on Linuxreturn int(self.hidden_window.winId())try:# PyQt4 and PyQt5return int(self.winId())except:# PySide:# | QWidget.winId() returns <PyCObject object at 0x02FD8788># | Converting it to int using ctypes.if sys.version_info[0] == 2:# Python 2ctypes.pythonapi.PyCObject_AsVoidPtr.restype = (ctypes.c_void_p)ctypes.pythonapi.PyCObject_AsVoidPtr.argtypes = ([ctypes.py_object])return ctypes.pythonapi.PyCObject_AsVoidPtr(self.winId())else:# Python 3ctypes.pythonapi.PyCapsule_GetPointer.restype = (ctypes.c_void_p)ctypes.pythonapi.PyCapsule_GetPointer.argtypes = ([ctypes.py_object])return ctypes.pythonapi.PyCapsule_GetPointer(self.winId(), None)def moveEvent(self, _):self.x = 0self.y = 0if self.browser:if WINDOWS:WindowUtils.OnSize(self.getHandle(), 0, 0, 0)elif LINUX:self.browser.SetBounds(self.x, self.y,self.width(), self.height())self.browser.NotifyMoveOrResizeStarted()def resizeEvent(self, event):size = event.size()if self.browser:if WINDOWS:WindowUtils.OnSize(self.getHandle(), 0, 0, 0)elif LINUX:self.browser.SetBounds(self.x, self.y,size.width(), size.height())self.browser.NotifyMoveOrResizeStarted()class CefApplication(QApplication):def __init__(self, args):super(CefApplication, self).__init__(args)if not cef.GetAppSetting("external_message_pump"):self.timer = self.createTimer()self.setupIcon()def createTimer(self):timer = QTimer()# noinspection PyUnresolvedReferencestimer.timeout.connect(self.onTimer)timer.start(10)return timerdef onTimer(self):cef.MessageLoopWork()def stopTimer(self):# Stop the timer after Qt's message loop has endedself.timer.stop()def setupIcon(self):icon_file = os.path.join(os.path.abspath(os.path.dirname(__file__)),"resources", "{0}.png".format(sys.argv[1]))if os.path.exists(icon_file):self.setWindowIcon(QIcon(icon_file))class LoadHandler(object):def __init__(self, navigation_bar):self.initial_app_loading = Trueself.navigation_bar = navigation_bardef OnLoadingStateChange(self, **_):self.navigation_bar.updateState()def OnLoadStart(self, browser, **_):self.navigation_bar.url.setText(browser.GetUrl())if self.initial_app_loading:self.navigation_bar.cef_widget.setFocus()# Temporary fix no. 2 for focus issue on Linux (Issue #284)if LINUX:print("[qt.py] LoadHandler.OnLoadStart:"" keyboard focus fix no. 2 (Issue #284)")browser.SetFocus(True)self.initial_app_loading = Falseclass FocusHandler(object):def __init__(self, cef_widget):self.cef_widget = cef_widgetdef OnTakeFocus(self, **_):if cef.GetAppSetting("debug"):print("[qt.py] FocusHandler.OnTakeFocus")def OnSetFocus(self, **_):if cef.GetAppSetting("debug"):print("[qt.py] FocusHandler.OnSetFocus")def OnGotFocus(self, browser, **_):if cef.GetAppSetting("debug"):print("[qt.py] FocusHandler.OnGotFocus")self.cef_widget.setFocus()# Temporary fix no. 1 for focus issues on Linux (Issue #284)if LINUX:browser.SetFocus(True)class NavigationBar(QFrame):def __init__(self, cef_widget):# noinspection PyArgumentListsuper(NavigationBar, self).__init__()self.cef_widget = cef_widget# Init layoutlayout = QGridLayout()layout.setContentsMargins(0, 0, 0, 0)layout.setSpacing(0)# Back buttonself.back = self.createButton("back")# noinspection PyUnresolvedReferencesself.back.clicked.connect(self.onBack)# noinspection PyArgumentListlayout.addWidget(self.back, 0, 0)# Forward buttonself.forward = self.createButton("forward")# noinspection PyUnresolvedReferencesself.forward.clicked.connect(self.onForward)# noinspection PyArgumentListlayout.addWidget(self.forward, 0, 1)# Reload buttonself.reload = self.createButton("reload")# noinspection PyUnresolvedReferencesself.reload.clicked.connect(self.onReload)# noinspection PyArgumentListlayout.addWidget(self.reload, 0, 2)# Url inputself.url = QLineEdit("")# noinspection PyUnresolvedReferencesself.url.returnPressed.connect(self.onGoUrl)# noinspection PyArgumentListlayout.addWidget(self.url, 0, 3)# Layoutself.setLayout(layout)self.updateState()def onBack(self):if self.cef_widget.browser:self.cef_widget.browser.GoBack()def onForward(self):if self.cef_widget.browser:self.cef_widget.browser.GoForward()def onReload(self):if self.cef_widget.browser:self.cef_widget.browser.Reload()def onGoUrl(self):if self.cef_widget.browser:self.cef_widget.browser.LoadUrl(self.url.text())def updateState(self):browser = self.cef_widget.browserif not browser:self.back.setEnabled(False)self.forward.setEnabled(False)self.reload.setEnabled(False)self.url.setEnabled(False)returnself.back.setEnabled(browser.CanGoBack())self.forward.setEnabled(browser.CanGoForward())self.reload.setEnabled(True)self.url.setEnabled(True)self.url.setText(browser.GetUrl())def createButton(self, name):resources = os.path.join(os.path.abspath(os.path.dirname(__file__)),"resources")pixmap = QPixmap(os.path.join(resources, "{0}.png".format(name)))icon = QIcon(pixmap)button = QPushButton()button.setIcon(icon)button.setIconSize(pixmap.rect().size())return buttonif __name__ == '__main__':main()

截屏

"""
Example of using CEF browser in off-screen rendering mode
(windowless) to create a screenshot of a web page. This
example doesn't depend on any third party GUI framework.
This example is discussed in Tutorial in the Off-screen
rendering section.Before running this script you have to install Pillow image
library (PIL module):pip install PillowWith optionl arguments to this script you can resize viewport
so that screenshot includes whole page with height like 5000px
which would be an equivalent of scrolling down multiple pages.
By default when no arguments are provided will load cefpython
project page on Github with 5000px height.Usage:python screenshot.pypython screenshot.py https://github.com/cztomczak/cefpython 1024 5000python screenshot.py https://www.google.com/ncr 1024 768Tested configurations:
- CEF Python v57.0+
- Pillow 2.3.0 / 4.1.0NOTE: There are limits in Chromium on viewport size. For somewebsites with huge viewport size it won't work. In suchcase it is required to reduce viewport size to an usualsize of a window and perform scrolling programmaticallyusing javascript while making a screenshot for each ofthe scrolled region. Then at the end combine all thescreenshots into one. To force a paint event in OSRmode call cef.Invalidate().
"""from cefpython3 import cefpython as cef
import os
import platform
import subprocess
import systry:from PIL import Image, __version__ as PILLOW_VERSION
except ImportError:print("[screenshot.py] Error: PIL module not available. To install"" type: pip install Pillow")sys.exit(1)# Config
URL = "https://github.com/cztomczak/cefpython"
VIEWPORT_SIZE = (1024, 5000)
SCREENSHOT_PATH = os.path.join(os.path.abspath(os.path.dirname(__file__)),"screenshot.png")def main():check_versions()sys.excepthook = cef.ExceptHook  # To shutdown all CEF processes on errorif os.path.exists(SCREENSHOT_PATH):print("[screenshot.py] Remove old screenshot")os.remove(SCREENSHOT_PATH)command_line_arguments()# Off-screen-rendering requires setting "windowless_rendering_enabled"# option.settings = {"windowless_rendering_enabled": True,}switches = {# GPU acceleration is not supported in OSR mode, so must disable# it using these Chromium switches (Issue #240 and #463)"disable-gpu": "","disable-gpu-compositing": "",# Tweaking OSR performance by setting the same Chromium flags# as in upstream cefclient (Issue #240)."enable-begin-frame-scheduling": "","disable-surfaces": "",  # This is required for PDF ext to work}browser_settings = {# Tweaking OSR performance (Issue #240)"windowless_frame_rate": 30,  # Default frame rate in CEF is 30}cef.Initialize(settings=settings, switches=switches)create_browser(browser_settings)cef.MessageLoop()cef.Shutdown()print("[screenshot.py] Opening screenshot with default application")open_with_default_application(SCREENSHOT_PATH)def check_versions():ver = cef.GetVersion()print("[screenshot.py] CEF Python {ver}".format(ver=ver["version"]))print("[screenshot.py] Chromium {ver}".format(ver=ver["chrome_version"]))print("[screenshot.py] CEF {ver}".format(ver=ver["cef_version"]))print("[screenshot.py] Python {ver} {arch}".format(ver=platform.python_version(),arch=platform.architecture()[0]))print("[screenshot.py] Pillow {ver}".format(ver=PILLOW_VERSION))assert cef.__version__ >= "57.0", "CEF Python v57.0+ required to run this"def command_line_arguments():if len(sys.argv) == 4:url = sys.argv[1]width = int(sys.argv[2])height = int(sys.argv[3])if url.startswith("http://") or url.startswith("https://"):global URLURL = urlelse:print("[screenshot.py] Error: Invalid url argument")sys.exit(1)if width > 0 and height > 0:global VIEWPORT_SIZEVIEWPORT_SIZE = (width, height)else:print("[screenshot.py] Error: Invalid width and height")sys.exit(1)elif len(sys.argv) > 1:print("[screenshot.py] Error: Expected arguments: url width height")sys.exit(1)def create_browser(settings):# Create browser in off-screen-rendering mode (windowless mode)# by calling SetAsOffscreen method. In such mode parent window# handle can be NULL (0).parent_window_handle = 0window_info = cef.WindowInfo()window_info.SetAsOffscreen(parent_window_handle)print("[screenshot.py] Viewport size: {size}".format(size=str(VIEWPORT_SIZE)))print("[screenshot.py] Loading url: {url}".format(url=URL))browser = cef.CreateBrowserSync(window_info=window_info,settings=settings,url=URL)browser.SetClientHandler(LoadHandler())browser.SetClientHandler(RenderHandler())browser.SendFocusEvent(True)# You must call WasResized at least once to let know CEF that# viewport size is available and that OnPaint may be called.browser.WasResized()def save_screenshot(browser):# Browser object provides GetUserData/SetUserData methods# for storing custom data associated with browser. The# "OnPaint.buffer_string" data is set in RenderHandler.OnPaint.buffer_string = browser.GetUserData("OnPaint.buffer_string")if not buffer_string:raise Exception("buffer_string is empty, OnPaint never called?")image = Image.frombytes("RGBA", VIEWPORT_SIZE, buffer_string,"raw", "RGBA", 0, 1)image.save(SCREENSHOT_PATH, "PNG")print("[screenshot.py] Saved image: {path}".format(path=SCREENSHOT_PATH))# See comments in exit_app() why PostTask must be usedcef.PostTask(cef.TID_UI, exit_app, browser)def open_with_default_application(path):if sys.platform.startswith("darwin"):subprocess.call(("open", path))elif os.name == "nt":# noinspection PyUnresolvedReferencesos.startfile(path)elif os.name == "posix":subprocess.call(("xdg-open", path))def exit_app(browser):# Important note:#   Do not close browser nor exit app from OnLoadingStateChange#   OnLoadError or OnPaint events. Closing browser during these#   events may result in unexpected behavior. Use cef.PostTask#   function to call exit_app from these events.print("[screenshot.py] Close browser and exit app")browser.CloseBrowser()cef.QuitMessageLoop()class LoadHandler(object):def OnLoadingStateChange(self, browser, is_loading, **_):"""Called when the loading state has changed."""if not is_loading:# Loading is completesys.stdout.write(os.linesep)print("[screenshot.py] Web page loading is complete")print("[screenshot.py] Will save screenshot in 2 seconds")# Give up to 2 seconds for the OnPaint call. Most of the time# it is already called, but sometimes it may be called later.cef.PostDelayedTask(cef.TID_UI, 2000, save_screenshot, browser)def OnLoadError(self, browser, frame, error_code, failed_url, **_):"""Called when the resource load for a navigation failsor is canceled."""if not frame.IsMain():# We are interested only in loading main url.# Ignore any errors during loading of other frames.returnprint("[screenshot.py] ERROR: Failed to load url: {url}".format(url=failed_url))print("[screenshot.py] Error code: {code}".format(code=error_code))# See comments in exit_app() why PostTask must be usedcef.PostTask(cef.TID_UI, exit_app, browser)class RenderHandler(object):def __init__(self):self.OnPaint_called = Falsedef GetViewRect(self, rect_out, **_):"""Called to retrieve the view rectangle which is relativeto screen coordinates. Return True if the rectangle wasprovided."""# rect_out --> [x, y, width, height]rect_out.extend([0, 0, VIEWPORT_SIZE[0], VIEWPORT_SIZE[1]])return Truedef OnPaint(self, browser, element_type, paint_buffer, **_):"""Called when an element should be painted."""if self.OnPaint_called:sys.stdout.write(".")sys.stdout.flush()else:sys.stdout.write("[screenshot.py] OnPaint")self.OnPaint_called = Trueif element_type == cef.PET_VIEW:# Buffer string is a huge string, so for performance# reasons it would be better not to copy this string.# I think that Python makes a copy of that string when# passing it to SetUserData.buffer_string = paint_buffer.GetBytes(mode="rgba",origin="top-left")# Browser object provides GetUserData/SetUserData methods# for storing custom data associated with browser.browser.SetUserData("OnPaint.buffer_string", buffer_string)else:raise Exception("Unsupported element_type in OnPaint")if __name__ == '__main__':main()

cookie 操作

"""Shows how to fetch all cookies, all cookies for
a given url and how to delete a specific cookie. For
an example on how to set a cookie see the 'setcookie.py'
snippet."""from cefpython3 import cefpython as cefdef main():cef.Initialize()browser = cef.CreateBrowserSync(url="http://www.html-kit.com/tools/cookietester/",window_title="Cookies")browser.SetClientHandler(LoadHandler())cef.MessageLoop()del browsercef.Shutdown()class LoadHandler(object):def OnLoadingStateChange(self, browser, is_loading, **_):if is_loading:print("Page loading complete - start visiting cookies")manager = cef.CookieManager.GetGlobalManager()# Must keep a strong reference to the CookieVisitor object# while cookies are being visited.self.cookie_visitor = CookieVisitor()# Visit all cookiesresult = manager.VisitAllCookies(self.cookie_visitor)if not result:print("Error: could not access cookies")# To visit cookies only for a given url uncomment the# code below."""url = "http://www.html-kit.com/tools/cookietester/"http_only_cookies = Falseresult = manager.VisitUrlCookies(url, http_only_cookies,self.cookie_visitor)if not result:print("Error: could not access cookies")"""class CookieVisitor(object):def Visit(self, cookie, count, total, delete_cookie_out):"""This callback is called on the IO thread."""print("Cookie {count}/{total}: '{name}', '{value}'".format(count=count+1, total=total, name=cookie.GetName(),value=cookie.GetValue()))# Set a cookie named "delete_me" and it will be deleted.# You have to refresh page to see whether it succeeded.if cookie.GetName() == "delete_me":# 'delete_cookie_out' arg is a list passed by reference.# Set its '0' index to True to delete the cookie.delete_cookie_out[0] = Trueprint("Deleted cookie: {name}".format(name=cookie.GetName()))# Return True to continue visiting more cookiesreturn Trueif __name__ == '__main__':main()

相關鏈接

https://pypi.org/project/cefpython3/
https://github.com/cztomczak/cefpython

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/79097.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/79097.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/79097.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

MySQL-存儲引擎和索引

1.MySQL的基礎架構是什么&#xff1f; MySQL由連接器、分析器、優化器、執行器和存儲引擎這五部分構成。 一條SQL的執行流程&#xff1a; 通過連接器連接數據庫&#xff0c;檢查用戶名和密碼&#xff0c;以及權限校驗&#xff0c;是否有增刪改查的權限。在MySQL8.0之前&#…

安卓性能調優之-掉幀測試

掉幀指的是某一幀沒有在規定時間內完成渲染&#xff0c;導致 UI 畫面不流暢&#xff0c;產生視覺上的卡頓、跳幀現象。 Android目標幀率&#xff1a; 一般情況下&#xff0c;Android設備的屏幕刷新率是60Hz&#xff0c;即每秒需要渲染60幀&#xff08;Frame Per Second, FPS&a…

【運維自動化-標準運維】職能化功能如何使用?

職能化功能主要用于一些固化的標準流程可以通過權限開放的方式給到那些負責固定職能的非運維人員&#xff0c;比如外包操作員來執行操作&#xff0c;如此可以釋放一些運維的人力&#xff0c;讓其可以專注流程的建設和優化。實操演示 新建職能化流程&#xff08;運維角色操作&a…

游戲引擎學習第224天

回顧游戲運行并指出一個明顯的圖像問題。 回顧一下之前那個算法 我們今天要做一點預加載的處理。上周剛完成了游戲序章部分的所有剪輯內容。在運行這一部分時&#xff0c;如果觀察得足夠仔細&#xff0c;就會注意到一個問題。雖然因為視頻流壓縮質量較低&#xff0c;很難清楚…

【小沐學GIS】基于C++繪制三維數字地球Earth(QT5、OpenGL、GIS、衛星)第五期

&#x1f37a;三維數字地球系列相關文章如下&#x1f37a;&#xff1a;1【小沐學GIS】基于C繪制三維數字地球Earth&#xff08;OpenGL、glfw、glut&#xff09;第一期2【小沐學GIS】基于C繪制三維數字地球Earth&#xff08;OpenGL、glfw、glut&#xff09;第二期3【小沐學GIS】…

OpenAI 最新發布的 GPT-4.1 系列在 API 中正式上線

每周跟蹤AI熱點新聞動向和震撼發展 想要探索生成式人工智能的前沿進展嗎&#xff1f;訂閱我們的簡報&#xff0c;深入解析最新的技術突破、實際應用案例和未來的趨勢。與全球數同行一同&#xff0c;從行業內部的深度分析和實用指南中受益。不要錯過這個機會&#xff0c;成為AI領…

【力扣】day1

文章目錄 27.移除元素26. 刪除有序數組的重復項 27.移除元素 26. 刪除有序數組的重復項 我們仔細看一下這兩道題的最后的返回值,為什么第一題返回slow 而第二題返回slow1 最后的返回值該如何返回絕對不是憑感覺,我們自己分析一下第一個slow,從0位置開始, 遇到val值就開始和fas…

完全無網絡環境的 openEuler 系統離線安裝 ClamAV 的詳細步驟

準備工作&#xff08;在外網機器操作&#xff09; 1. 下載 ClamAV RPM 包及依賴 mkdir -p ~/clamav-offline/packages cd ~/clamav-offline/packages# 使用 yumdownloader 下載所有依賴包&#xff08;需提前安裝 yum-utils&#xff09; sudo dnf install yum-utils -y sudo y…

3.2.2.2 Spring Boot配置視圖控制器

在Spring Boot中配置視圖控制器可以簡化頁面跳轉跳邏輯。通過實現WebMvcConfigurer接口的addViewControllers方法&#xff0c;可以直接將URL映射到特定的視圖&#xff0c;而無需編寫控制器類。例如&#xff0c;將根路徑"/"映射到welcome.html視圖&#xff0c;當訪問應…

數據庫—函數筆記

一&#xff0c;數據庫函數的分類 內置函數&#xff08;Built-in Functions&#xff09; 數據庫系統自帶的函數&#xff0c;無需額外定義即可直接調用。 聚合函數&#xff1a;對數據集進行計算&#xff08;如 SUM, AVG, COUNT&#xff09;。 字符串函數&#xff1a;處理文本數據…

YOLOv2訓練詳細實踐指南

1. YOLOv2架構與原理詳解 1.1 核心改進點 YOLOv2相比YOLOv1的主要改進&#xff1a; 采用Darknet-19作為backbone&#xff08;相比VGG更高效&#xff09;引入Batch Normalization提高穩定性與收斂速度使用anchor boxes機制代替直接預測邊界框引入維度聚類確定anchor boxes尺寸…

詳解如何復現DeepSeek R1:從零開始利用Python構建

DeepSeek R1 的整個訓練過程&#xff0c;說白了就是在其基礎模型&#xff08;也就是 deepseek V3&#xff09;之上&#xff0c;用各種不同的強化學習方法來“雕琢”它。 咱們從一個小小的本地運行的基礎模型開始&#xff0c;一邊跟著 DeepSeek R1 技術報告 的步驟&#xff0c;…

MCP Server 開發實戰 | 大模型無縫對接 Grafana

前言 隨著大模型的飛速發展&#xff0c;越來越多的 AI 創新顛覆了過往很多產品的使用體驗。但你是否曾想過&#xff0c;在向大型語言模型提問時&#xff0c;它能否根據你的需求精準返回系統中的對應數據&#xff1f;例如&#xff0c;當用戶查詢 Grafana 服務時&#xff0c;模型…

塊存儲、文件存儲和對象存儲的特點、應用場景及區別

塊存儲、文件存儲和對象存儲的特點、應用場景及區別 塊存儲 特點&#xff1a;塊存儲將數據分割成固定大小的塊&#xff0c;每個塊都有唯一的標識符。數據以塊為單位進行讀寫操作&#xff0c;適合需要高性能和低延遲的場景。 應用場景&#xff1a;數據庫存儲、虛擬機磁盤、高性能…

OpenCv--換臉

引言 在當今數字化時代&#xff0c;圖像處理技術的發展日新月異。換臉技術作為其中一項極具趣味性和挑戰性的應用&#xff0c;吸引了眾多開發者和愛好者的目光。OpenCV 作為一款強大的開源計算機視覺庫&#xff0c;為我們實現換臉提供了豐富的工具和方法。本文將深入探討如何使…

安卓基礎(SQLite)

基礎 import sqlite3# 連接到數據庫 conn sqlite3.connect(mydatabase.db) cursor conn.cursor()# 執行查詢 cursor.execute("SELECT * FROM users") rows cursor.fetchall()for row in rows:print(row)# 關閉連接 conn.close() 創建一個繼承自 SQLiteOpenHelpe…

QuickAPI 核心能力解析:構建數據服務化的三位一體生態

在企業數據資產化運營的進程中&#xff0c;如何打破數據開發與共享的效率瓶頸&#xff0c;實現從 “數據可用” 到 “數據好用” 的跨越&#xff1f;麥聰軟件的 QuickAPI 給出了系統性答案。作為 SQL2API 理念的標桿產品&#xff0c;QuickAPI 通過SQL 編輯器、數據 API、數據市…

《計算機視覺度量:從特征描述到深度學習》—生成式人工智能在工業檢測的應用

2022 年 11 月 30 日一個很重要的標志事件就是chatgpt的出現&#xff0c;打開了生成式人工智能的開端。這也許會是一個歷史性的時刻&#xff0c;今天是2025年4月&#xff0c;過去兩年多&#xff0c;那個時刻目前回想還是對本人造成了沖擊&#xff0c;一個完全有自主分析能力的生…

【軟件測試】自動化測試框架Pytest + Selenium的使用

Pytest Selenium 是一種常見的自動化測試框架組合&#xff0c;用于編寫和執行 Web 應用程序的自動化測試。Pytest 是一個強大的 Python 測試框架&#xff0c;而 Selenium 是一個用于瀏覽器自動化的工具&#xff0c;二者結合使用可以高效地進行 Web 應用的功能測試、UI 測試等。…

煤礦濕噴砂漿攪拌機組創新設計與關鍵技術研究

引言&#xff1a;濕噴工藝在煤礦支護中的革命性意義 在深部煤礦巷道支護領域&#xff0c;濕噴混凝土技術以其回彈率低&#xff08;<15%&#xff09;、粉塵濃度小&#xff08;<10mg/m&#xff09;的顯著優勢&#xff0c;逐步取代傳統干噴工藝。作為濕噴工藝的核心設備&am…