基于 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.mzph.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…