org.openqa.selenium.NoSuchElementException:尝试通过 CssSelector 定位 card-fields-iframe 时返回的节点(null)不是 DOM 元素
org.openqa.selenium.NoSuchElementException: Returned node (null) was not a DOM element when trying to locate card-fields-iframe by CssSelector
我正在尝试通过部分 ID 定位 iframe。对于这种方法,我使用了:
driver.switchTo().frame(driver.findElement(By.cssSelector("iframe[id*='card-fields-number']")));
我也尝试过 xpath。
driver.switchTo().frame(driver.findElement(By.xpath("//iframe[contains(@id,'card-fields-number')]")));
但是,我仍然收到此异常:
org.openqa.selenium.NoSuchElementException: Returned node (null) was not a DOM element
我发现当我为 HtmlUnit 启用 javascript 时,它能够定位框架并切换到它。我宁愿不启用 javascript 因为它对我来说运行很慢,并且增加了不必要的延迟。
iFrame HTML代码:
<iframe class="card-fields-iframe" frameborder="0" id="card-fields-number-7pbvqg7azsf00000" name="card-fields-number-7pbvqg7azsf00000" scrolling="no" src="https://checkout.shopifycs.com/number?identifier=438599641d0ed8fe61c161d72e62b5f8&location=https%3A%2F%2Fshopnicekicks.com%2F2192362%2Fcheckouts%2F438599641d0ed8fe61c161d72e62b5f8&dir=ltr&fonts[]=Lato" title="Field container for: Card number" style="height: 43px;"></iframe>
iFrame ID 是动态的,这就是我使用部分 ID 的原因。
网站link:https://shopnicekicks.com/checkout
您必须填写所有内容,直到到达最后一页,即信用卡信息页。
更新
iFrame 位于父框架内。
父框架:
<iframe srcdoc="<script>!function(){var e=function(e){var t={exports:{}};return e.call(t.exports,t,t.exports),t.exports},t=function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}(),n=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},i=function(e){return e&&e.__esModule?e:{"default":e}},o=e(function(e,i){"use strict";Object.defineProperty(i,"__esModule",{value:!0});var o=function(){function e(){var t=this;n(this,e),this.calls=[],window.ga=function(){for(var e=arguments.length,n=Array(e),i=0;i<e;i++)n[i]=arguments[i];return t.gaCall(n)}}return t(e,[{key:"gaCall",value:function(e){var t=this;this.calls.push(e),clearTimeout(this.timeout),this.timeout=setTimeout(function(){t.calls.length>0&&t.sendMessage()},0)}},{key:"listen",value:function(){var e=this;window.addEventListener("message",function(t){return e.receiveMessage(t)},!1)}},{key:"sendMessage",value:function(){window.parent.postMessage({type:"analytics",calls:this.calls},this.origin),this.calls=[]}},{key:"receiveMessage",value:function(e){if(e.source===window.parent&&"checkout_context"===e.data.type){this.origin=e.origin,window.Shopify=e.data.Shopify,window.__st=e.data.__st;try{window.additionalScripts()}catch(e){console.error("User script error: ",e)}}}}]),e}();i["default"]=o});e(function(){"use strict";var e=i(o);!function(){(new e["default"]).listen()}()})}("undefined"!=typeof global?global:"undefined"!=typeof window&&window); window.additionalScripts = function () {};</script>" src="https://checkout.shopify.com/2192362/sandbox/google_analytics_iframe" onload="this.setAttribute('data-loaded', true)" sandbox="allow-scripts" id="google-analytics-sandbox" tabindex="-1" class="visually-hidden" style="display:none" aria-hidden="true" data-loaded="true"></iframe>
只需尝试使用框架索引“//iframe[index]”,其中索引整数。
例如xpath : //iframe[1]
框架 ID 可能会动态变化,但在少数应用程序中结构保持不变,因此索引可以解决问题。
如果问题解决了请告诉我。
由于 iframe 有标签 iframe
,您可以使用如下标签名切换到 iframe:
driver.switchTo().frame(driver.findElement(By.tagName("iframe")));
如果你想再次切换到默认内容,那么你可以使用 driver.switchTo().defaultContent();
这个错误信息...
org.openqa.selenium.NoSuchElementException: Returned node (null) was not a DOM element
...意味着 没有找到这样的元素 ,因为返回的节点是 null 或者不是 DOM元素。
这仍然是 issue 与 htmlunit-driver 团队的开放。
但是,您需要注意以下事项:
- 首先,所有现代浏览器都内置了对 JavaScript 的支持。
- HtmlUnitDriver is a WebDriver compatible driver for HtmlUnit 无头浏览器。它有相当好的 JavaScript 支持(正在不断改进)并且即使使用非常复杂的 AJAX 库也能工作,模拟 Chrome、Firefox 或 Internet Explorer 取决于所使用的配置。因此,理想情况下,在使用 HtmlUnitDriver 时,必须启用 JavaScript,否则 HtmlUnitDriver 可能不会ne 能够检测基于 JavaScript 的元素。
- 您可以在 HtmlUnitDriver does not load javascript when navigating a page from an url
中找到详细的讨论
- 该元素似乎是一个 信用卡字段 并且历史上 信用卡号,等等位于
<iframes>
中。
- 您可以在
中找到详细的讨论
- 每当
<iframe>
发挥作用时,<iframe>
标签的 src
属性就起着至关重要的作用。
- 您可以在
中找到详细的讨论
- 根据切换
<iframe>
时的最佳做法,您需要引入 WebDriverWait 以使所需的框架可用并切换到它。
- 我们在您之前的问题中讨论了这方面的问题
因此您可以使用以下任一解决方案:
cssSelector:
new WebDriverWait(driver, 10).until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.cssSelector("iframe.card-fields-iframe[id^='card-fields-number-'][src*='shopifycs']")));
xpath:
new WebDriverWait(driver, 10).until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.xpath("//iframe[@class='card-fields-iframe' and starts-with(@id,'card-fields-number-')][contains(@src, 'shopifycs')]")));
更新
查看 CssSelector
的快照,它根据您提供的 HTML 识别元素 perfecto:
我正在尝试通过部分 ID 定位 iframe。对于这种方法,我使用了:
driver.switchTo().frame(driver.findElement(By.cssSelector("iframe[id*='card-fields-number']")));
我也尝试过 xpath。
driver.switchTo().frame(driver.findElement(By.xpath("//iframe[contains(@id,'card-fields-number')]")));
但是,我仍然收到此异常:
org.openqa.selenium.NoSuchElementException: Returned node (null) was not a DOM element
我发现当我为 HtmlUnit 启用 javascript 时,它能够定位框架并切换到它。我宁愿不启用 javascript 因为它对我来说运行很慢,并且增加了不必要的延迟。
iFrame HTML代码:
<iframe class="card-fields-iframe" frameborder="0" id="card-fields-number-7pbvqg7azsf00000" name="card-fields-number-7pbvqg7azsf00000" scrolling="no" src="https://checkout.shopifycs.com/number?identifier=438599641d0ed8fe61c161d72e62b5f8&location=https%3A%2F%2Fshopnicekicks.com%2F2192362%2Fcheckouts%2F438599641d0ed8fe61c161d72e62b5f8&dir=ltr&fonts[]=Lato" title="Field container for: Card number" style="height: 43px;"></iframe>
iFrame ID 是动态的,这就是我使用部分 ID 的原因。
网站link:https://shopnicekicks.com/checkout 您必须填写所有内容,直到到达最后一页,即信用卡信息页。
更新 iFrame 位于父框架内。 父框架:
<iframe srcdoc="<script>!function(){var e=function(e){var t={exports:{}};return e.call(t.exports,t,t.exports),t.exports},t=function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}(),n=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},i=function(e){return e&&e.__esModule?e:{"default":e}},o=e(function(e,i){"use strict";Object.defineProperty(i,"__esModule",{value:!0});var o=function(){function e(){var t=this;n(this,e),this.calls=[],window.ga=function(){for(var e=arguments.length,n=Array(e),i=0;i<e;i++)n[i]=arguments[i];return t.gaCall(n)}}return t(e,[{key:"gaCall",value:function(e){var t=this;this.calls.push(e),clearTimeout(this.timeout),this.timeout=setTimeout(function(){t.calls.length>0&&t.sendMessage()},0)}},{key:"listen",value:function(){var e=this;window.addEventListener("message",function(t){return e.receiveMessage(t)},!1)}},{key:"sendMessage",value:function(){window.parent.postMessage({type:"analytics",calls:this.calls},this.origin),this.calls=[]}},{key:"receiveMessage",value:function(e){if(e.source===window.parent&&"checkout_context"===e.data.type){this.origin=e.origin,window.Shopify=e.data.Shopify,window.__st=e.data.__st;try{window.additionalScripts()}catch(e){console.error("User script error: ",e)}}}}]),e}();i["default"]=o});e(function(){"use strict";var e=i(o);!function(){(new e["default"]).listen()}()})}("undefined"!=typeof global?global:"undefined"!=typeof window&&window); window.additionalScripts = function () {};</script>" src="https://checkout.shopify.com/2192362/sandbox/google_analytics_iframe" onload="this.setAttribute('data-loaded', true)" sandbox="allow-scripts" id="google-analytics-sandbox" tabindex="-1" class="visually-hidden" style="display:none" aria-hidden="true" data-loaded="true"></iframe>
只需尝试使用框架索引“//iframe[index]”,其中索引整数。
例如xpath : //iframe[1]
框架 ID 可能会动态变化,但在少数应用程序中结构保持不变,因此索引可以解决问题。
如果问题解决了请告诉我。
由于 iframe 有标签 iframe
,您可以使用如下标签名切换到 iframe:
driver.switchTo().frame(driver.findElement(By.tagName("iframe")));
如果你想再次切换到默认内容,那么你可以使用 driver.switchTo().defaultContent();
这个错误信息...
org.openqa.selenium.NoSuchElementException: Returned node (null) was not a DOM element
...意味着 没有找到这样的元素 ,因为返回的节点是 null 或者不是 DOM元素。
这仍然是 issue 与 htmlunit-driver 团队的开放。
但是,您需要注意以下事项:
- 首先,所有现代浏览器都内置了对 JavaScript 的支持。
- HtmlUnitDriver is a WebDriver compatible driver for HtmlUnit 无头浏览器。它有相当好的 JavaScript 支持(正在不断改进)并且即使使用非常复杂的 AJAX 库也能工作,模拟 Chrome、Firefox 或 Internet Explorer 取决于所使用的配置。因此,理想情况下,在使用 HtmlUnitDriver 时,必须启用 JavaScript,否则 HtmlUnitDriver 可能不会ne 能够检测基于 JavaScript 的元素。
- 您可以在 HtmlUnitDriver does not load javascript when navigating a page from an url 中找到详细的讨论
- 该元素似乎是一个 信用卡字段 并且历史上 信用卡号,等等位于
<iframes>
中。- 您可以在
- 您可以在
- 每当
<iframe>
发挥作用时,<iframe>
标签的src
属性就起着至关重要的作用。- 您可以在
- 您可以在
- 根据切换
<iframe>
时的最佳做法,您需要引入 WebDriverWait 以使所需的框架可用并切换到它。- 我们在您之前的问题中讨论了这方面的问题
- 我们在您之前的问题中讨论了这方面的问题
因此您可以使用以下任一解决方案:
cssSelector:
new WebDriverWait(driver, 10).until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.cssSelector("iframe.card-fields-iframe[id^='card-fields-number-'][src*='shopifycs']")));
xpath:
new WebDriverWait(driver, 10).until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.xpath("//iframe[@class='card-fields-iframe' and starts-with(@id,'card-fields-number-')][contains(@src, 'shopifycs')]")));
更新
查看 CssSelector
的快照,它根据您提供的 HTML 识别元素 perfecto: