You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Python、Javascript连接WebKit2.UserContentManager的script-message-received信号

解决WebKit2.UserContentManager的"script-message-received"信号连接问题(Python + JavaScript)

我完全理解你被这个问题卡了好几天的烦躁感——WebKit2的脚本消息传递确实有几个容易踩的坑,这就一步步帮你实现「获取整个文档+点击元素」的需求。

核心思路拆解

要实现Python和JavaScript的通信,关键是做好两步:

  1. Python端注册脚本消息通道,监听script-message-received信号
  2. JavaScript端通过指定通道,把需要的数据序列化后发送给Python

完整可运行代码

我把你的代码补全并优化,直接就能运行测试:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys
import json

try:
    import gi
    gi.require_version('Gtk', '3.0')
    gi.require_version('WebKit2', '4.0')
    from gi.repository import Gtk, WebKit2
except ImportError as e:
    print(f"依赖导入失败: {e}")
    sys.exit(1)

class WebKitMessageDemo(Gtk.Window):
    def __init__(self):
        super().__init__(title="WebKit2 点击数据获取Demo")
        self.set_default_size(800, 600)

        # 初始化UserContentManager(脚本消息的核心处理对象)
        self.content_manager = WebKit2.UserContentManager.new()
        
        # 注册消息通道:名字要和JavaScript端完全对应
        self.content_manager.register_script_message_handler("clickData", None)
        
        # 绑定信号处理函数:收到JS消息时触发
        self.content_manager.connect("script-message-received", self.handle_js_message)

        # 创建关联了ContentManager的WebView
        self.web_view = WebKit2.WebView.new_with_user_content_manager(self.content_manager)
        self.add(self.web_view)

        # 加载测试页面(内嵌HTML,也可以替换成外部URL)
        test_page = """
        <!DOCTYPE html>
        <html>
        <head>
            <script>
                // 监听页面任意点击事件
                document.addEventListener('click', (e) => {
                    // 提取点击元素的关键信息(DOM对象不能直接传递,要转成可序列化的数据)
                    const clickedEl = {
                        tag: e.target.tagName,
                        outerHTML: e.target.outerHTML,
                        id: e.target.id,
                        class: e.target.className
                    };
                    
                    // 打包文档和点击元素数据
                    const sendData = {
                        fullDocument: document.documentElement.outerHTML,
                        clickedElement: clickedEl
                    };

                    // 发送消息到Python端(通道名必须和Python注册的一致)
                    if (window.webkit?.messageHandlers?.clickData) {
                        window.webkit.messageHandlers.clickData.postMessage(sendData);
                    }
                });
            </script>
        </head>
        <body>
            <h1>点击页面任意位置测试!</h1>
            <p>这是一段测试文本</p>
            <button id="testBtn" class="demo-btn">测试按钮</button>
        </body>
        </html>
        """
        self.web_view.load_html(test_page, "file:///")

    def handle_js_message(self, _, message):
        # 解析JS传来的JSON数据
        try:
            data = json.loads(message.get_js_value().to_json())
            print("\n=== 收到JavaScript消息 ===")
            # 文档内容太长,只打印前500字符预览
            print(f"文档预览: {data['fullDocument'][:500]}...")
            print(f"点击元素标签: {data['clickedElement']['tag']}")
            print(f"点击元素HTML: {data['clickedElement']['outerHTML']}")
        except Exception as e:
            print(f"解析消息失败: {e}")

if __name__ == "__main__":
    window = WebKitMessageDemo()
    window.connect("destroy", Gtk.main_quit)
    window.show_all()
    Gtk.main()

关键细节说明

  1. Python端注意点:

    • 必须先调用register_script_message_handler注册通道名,否则JS发送的消息会被忽略
    • script-message-received信号的处理函数中,要通过message.get_js_value().to_json()把JS值转成JSON字符串,再解析成Python字典
    • WebView必须通过new_with_user_content_manager关联我们创建的ContentManager,否则消息通道不会生效
  2. JavaScript端注意点:

    • 不能直接传递DOM对象,必须提取成字符串、数字这类可JSON序列化的格式
    • 发送消息前最好做一下兼容性判断(window.webkit?.messageHandlers?.clickData),避免报错
    • 通道名要和Python端注册的完全一致,大小写敏感

测试方法

运行代码后,点击页面上的任意元素,控制台就会打印出文档的预览内容和点击元素的详细信息,完全符合你的需求。

内容的提问来源于stack exchange,提问作者taupist

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:55:10