有没有办法在浏览器中获取Pyqt5中页面的XPATH?

我正在使用pyqt5。我希望用户单击嵌入在我的pyqt5应用程序上的浏览器,以获取他/她正在单击的元素的XPATH。

任何想法是如何完成的,或者它是否可行?


繁星coding
浏览 144回答 1
1回答

慕田峪4524236

为了回答这个问题,我使用了以下答案:获取已单击的项目:https://stackoverflow.com/a/9012576获取给定项目的 XPATH:https://stackoverflow.com/a/58677712运行js脚本并将信息发送到python:https://stackoverflow.com/a/55294356连接所有这些部分,您将获得以下解决方案:├── main.py└── xpath_from_element.jsmain.pyimport osfrom PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets, QtWebChannelfrom jinja2 import TemplateCURRENT_DIR = os.path.dirname(os.path.realpath(__file__))class Element(QtCore.QObject):&nbsp; &nbsp; def __init__(self, name, parent=None):&nbsp; &nbsp; &nbsp; &nbsp; super(Element, self).__init__(parent)&nbsp; &nbsp; &nbsp; &nbsp; self._name = name&nbsp; &nbsp; @property&nbsp; &nbsp; def name(self):&nbsp; &nbsp; &nbsp; &nbsp; return self._name&nbsp; &nbsp; def script(self):&nbsp; &nbsp; &nbsp; &nbsp; return ""class WebEnginePage(QtWebEngineWidgets.QWebEnginePage):&nbsp; &nbsp; def __init__(self, parent=None):&nbsp; &nbsp; &nbsp; &nbsp; super(WebEnginePage, self).__init__(parent)&nbsp; &nbsp; &nbsp; &nbsp; self.loadFinished.connect(self.onLoadFinished)&nbsp; &nbsp; &nbsp; &nbsp; self._objects = []&nbsp; &nbsp; &nbsp; &nbsp; self._scripts = []&nbsp; &nbsp; def add_object(self, obj):&nbsp; &nbsp; &nbsp; &nbsp; self._objects.append(obj)&nbsp; &nbsp; @QtCore.pyqtSlot(bool)&nbsp; &nbsp; def onLoadFinished(self, ok):&nbsp; &nbsp; &nbsp; &nbsp; print("Finished loading: ", ok)&nbsp; &nbsp; &nbsp; &nbsp; if ok:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.load_qwebchannel()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.add_objects()&nbsp; &nbsp; def load_qwebchannel(self):&nbsp; &nbsp; &nbsp; &nbsp; file = QtCore.QFile(":/qtwebchannel/qwebchannel.js")&nbsp; &nbsp; &nbsp; &nbsp; if file.open(QtCore.QIODevice.ReadOnly):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; content = file.readAll()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; file.close()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.runJavaScript(content.data().decode())&nbsp; &nbsp; &nbsp; &nbsp; if self.webChannel() is None:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; channel = QtWebChannel.QWebChannel(self)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.setWebChannel(channel)&nbsp; &nbsp; def add_objects(self):&nbsp; &nbsp; &nbsp; &nbsp; if self.webChannel() is not None:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; objects = {obj.name: obj for obj in self._objects}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.webChannel().registerObjects(objects)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _script = """&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {% for obj in objects %}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var {{obj}};&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {% endfor %}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new QWebChannel(qt.webChannelTransport, function (channel) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {% for obj in objects %}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {{obj}} = channel.objects.{{obj}};&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {% endfor %}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; """&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.runJavaScript(Template(_script).render(objects=objects.keys()))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for obj in self._objects:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if isinstance(obj, Element):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.runJavaScript(obj.script())class Helper(Element):&nbsp; &nbsp; xpathClicked = QtCore.pyqtSignal(str)&nbsp; &nbsp; def script(self):&nbsp; &nbsp; &nbsp; &nbsp; js = ""&nbsp; &nbsp; &nbsp; &nbsp; file = QtCore.QFile(os.path.join(CURRENT_DIR, "xpath_from_element.js"))&nbsp; &nbsp; &nbsp; &nbsp; if file.open(QtCore.QIODevice.ReadOnly):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; content = file.readAll()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; file.close()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; js = content.data().decode()&nbsp; &nbsp; &nbsp; &nbsp; js += """&nbsp; &nbsp; &nbsp; &nbsp; document.addEventListener('click', function(e) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e = e || window.event;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var target = e.target || e.srcElement;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var xpath = Elements.DOMPath.xPath(target, false);&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {{name}}.receive_xpath(xpath);&nbsp; &nbsp; &nbsp; &nbsp; }, false);"""&nbsp; &nbsp; &nbsp; &nbsp; return Template(js).render(name=self.name)&nbsp; &nbsp; @QtCore.pyqtSlot(str)&nbsp; &nbsp; def receive_xpath(self, xpath):&nbsp; &nbsp; &nbsp; &nbsp; self.xpathClicked.emit(xpath)if __name__ == "__main__":&nbsp; &nbsp; import sys&nbsp; &nbsp; app = QtWidgets.QApplication(sys.argv)&nbsp; &nbsp; xpath_helper = Helper("xpath_helper")&nbsp; &nbsp; xpath_helper.xpathClicked.connect(lambda xpath: print("clicked", xpath))&nbsp; &nbsp; view = QtWebEngineWidgets.QWebEngineView()&nbsp; &nbsp; page = WebEnginePage()&nbsp; &nbsp; page.add_object(xpath_helper)&nbsp; &nbsp; view.setPage(page)&nbsp; &nbsp; view.load(QtCore.QUrl("https://www.qt.io"))&nbsp; &nbsp; view.show()&nbsp; &nbsp; sys.exit(app.exec_())xpath_from_element.js// Copyright 2018 The Chromium Authors. All rights reserved.// Use of this source code is governed by a BSD-style license that can be// found in the LICENSE file.Elements = {};Elements.DOMPath = {};/**&nbsp;* @param {!Node} node&nbsp;* @param {boolean=} optimized&nbsp;* @return {string}&nbsp;*/Elements.DOMPath.xPath = function (node, optimized) {&nbsp; &nbsp; if (node.nodeType === Node.DOCUMENT_NODE) {&nbsp; &nbsp; &nbsp; &nbsp; return '/';&nbsp; &nbsp; }&nbsp; &nbsp; const steps = [];&nbsp; &nbsp; let contextNode = node;&nbsp; &nbsp; while (contextNode) {&nbsp; &nbsp; &nbsp; &nbsp; const step = Elements.DOMPath._xPathValue(contextNode, optimized);&nbsp; &nbsp; &nbsp; &nbsp; if (!step) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; // Error - bail out early.&nbsp; &nbsp; &nbsp; &nbsp; steps.push(step);&nbsp; &nbsp; &nbsp; &nbsp; if (step.optimized) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; contextNode = contextNode.parentNode;&nbsp; &nbsp; }&nbsp; &nbsp; steps.reverse();&nbsp; &nbsp; return (steps.length && steps[0].optimized ? '' : '/') + steps.join('/');};/**&nbsp;* @param {!Node} node&nbsp;* @param {boolean=} optimized&nbsp;* @return {?Elements.DOMPath.Step}&nbsp;*/Elements.DOMPath._xPathValue = function (node, optimized) {&nbsp; &nbsp; let ownValue;&nbsp; &nbsp; const ownIndex = Elements.DOMPath._xPathIndex(node);&nbsp; &nbsp; if (ownIndex === -1) {&nbsp; &nbsp; &nbsp; &nbsp; return null;&nbsp; &nbsp; }&nbsp; // Error.&nbsp; &nbsp; switch (node.nodeType) {&nbsp; &nbsp; &nbsp; &nbsp; case Node.ELEMENT_NODE:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (optimized && node.getAttribute('id')) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return new Elements.DOMPath.Step('//*[@id="' + node.getAttribute('id') + '"]', true);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ownValue = node.localName;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; case Node.ATTRIBUTE_NODE:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ownValue = '@' + node.nodeName;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; case Node.TEXT_NODE:&nbsp; &nbsp; &nbsp; &nbsp; case Node.CDATA_SECTION_NODE:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ownValue = 'text()';&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; case Node.PROCESSING_INSTRUCTION_NODE:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ownValue = 'processing-instruction()';&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; case Node.COMMENT_NODE:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ownValue = 'comment()';&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; case Node.DOCUMENT_NODE:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ownValue = '';&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; default:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ownValue = '';&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; }&nbsp; &nbsp; if (ownIndex > 0) {&nbsp; &nbsp; &nbsp; &nbsp; ownValue += '[' + ownIndex + ']';&nbsp; &nbsp; }&nbsp; &nbsp; return new Elements.DOMPath.Step(ownValue, node.nodeType === Node.DOCUMENT_NODE);};/**&nbsp;* @param {!Node} node&nbsp;* @return {number}&nbsp;*/Elements.DOMPath._xPathIndex = function (node) {&nbsp; &nbsp; // Returns -1 in case of error, 0 if no siblings matching the same expression,&nbsp; &nbsp; // <XPath index among the same expression-matching sibling nodes> otherwise.&nbsp; &nbsp; function areNodesSimilar(left, right) {&nbsp; &nbsp; &nbsp; &nbsp; if (left === right) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return true;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; if (left.nodeType === Node.ELEMENT_NODE && right.nodeType === Node.ELEMENT_NODE) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return left.localName === right.localName;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; if (left.nodeType === right.nodeType) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return true;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; // XPath treats CDATA as text nodes.&nbsp; &nbsp; &nbsp; &nbsp; const leftType = left.nodeType === Node.CDATA_SECTION_NODE ? Node.TEXT_NODE : left.nodeType;&nbsp; &nbsp; &nbsp; &nbsp; const rightType = right.nodeType === Node.CDATA_SECTION_NODE ? Node.TEXT_NODE : right.nodeType;&nbsp; &nbsp; &nbsp; &nbsp; return leftType === rightType;&nbsp; &nbsp; }&nbsp; &nbsp; const siblings = node.parentNode ? node.parentNode.children : null;&nbsp; &nbsp; if (!siblings) {&nbsp; &nbsp; &nbsp; &nbsp; return 0;&nbsp; &nbsp; }&nbsp; // Root node - no siblings.&nbsp; &nbsp; let hasSameNamedElements;&nbsp; &nbsp; for (let i = 0; i < siblings.length; ++i) {&nbsp; &nbsp; &nbsp; &nbsp; if (areNodesSimilar(node, siblings[i]) && siblings[i] !== node) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; hasSameNamedElements = true;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; if (!hasSameNamedElements) {&nbsp; &nbsp; &nbsp; &nbsp; return 0;&nbsp; &nbsp; }&nbsp; &nbsp; let ownIndex = 1;&nbsp; // XPath indices start with 1.&nbsp; &nbsp; for (let i = 0; i < siblings.length; ++i) {&nbsp; &nbsp; &nbsp; &nbsp; if (areNodesSimilar(node, siblings[i])) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (siblings[i] === node) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return ownIndex;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ++ownIndex;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return -1;&nbsp; // An error occurred: |node| not found in parent's children.};/**&nbsp;* @unrestricted&nbsp;*/Elements.DOMPath.Step = class {&nbsp; &nbsp; /**&nbsp; &nbsp; &nbsp;* @param {string} value&nbsp; &nbsp; &nbsp;* @param {boolean} optimized&nbsp; &nbsp; &nbsp;*/&nbsp; &nbsp; constructor(value, optimized) {&nbsp; &nbsp; &nbsp; &nbsp; this.value = value;&nbsp; &nbsp; &nbsp; &nbsp; this.optimized = optimized || false;&nbsp; &nbsp; }&nbsp; &nbsp; /**&nbsp; &nbsp; &nbsp;* @override&nbsp; &nbsp; &nbsp;* @return {string}&nbsp; &nbsp; &nbsp;*/&nbsp; &nbsp; toString() {&nbsp; &nbsp; &nbsp; &nbsp; return this.value;&nbsp; &nbsp; }};
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python