簡體   English   中英

Selenium:如何在加載/執行頁面的任何其他腳本之前將 Javascript 注入/執行到頁面中?

[英]Selenium: How to Inject/execute a Javascript in to a Page before loading/executing any other scripts of the page?

我正在使用 selenium python webdriver 來瀏覽一些頁面。 我想在加載和執行任何其他 Javascript 代碼之前將 javascript 代碼注入頁面。 另一方面,我需要將我的 JS 代碼作為該頁面的第一個 JS 代碼執行。 Selenium 有沒有辦法做到這一點?

我用谷歌搜索了幾個小時,但我找不到任何正確的答案!

從 1.0.9 版本開始, selenium-wire獲得了修改請求響應的功能。 下面是此功能的示例,用於在頁面到達 Web 瀏覽器之前將腳本注入頁面。

import os
from seleniumwire import webdriver
from gzip import compress, decompress
from urllib.parse import urlparse

from lxml import html
from lxml.etree import ParserError
from lxml.html import builder

script_elem_to_inject = builder.SCRIPT('alert("injected")')

def inject(req, req_body, res, res_body):
    # various checks to make sure we're only injecting the script on appropriate responses
    # we check that the content type is HTML, that the status code is 200, and that the encoding is gzip
    if res.headers.get_content_subtype() != 'html' or res.status != 200 or res.getheader('Content-Encoding') != 'gzip':
        return None
    try:
        parsed_html = html.fromstring(decompress(res_body))
    except ParserError:
        return None
    try:
        parsed_html.head.insert(0, script_elem_to_inject)
    except IndexError: # no head element
        return None
    return compress(html.tostring(parsed_html))

drv = webdriver.Firefox(seleniumwire_options={'custom_response_handler': inject})
drv.header_overrides = {'Accept-Encoding': 'gzip'} # ensure we only get gzip encoded responses

通常遠程控制瀏覽器並能夠在頁面內容加載之前注入腳本的另一種方法是使用完全基於單獨協議的庫,例如:DevTools 協議。 此處提供了 Python 實現: https : //github.com/pyppeteer/pyppeteer2 (免責聲明:我是主要作者之一)

如果你想在頁面的 html 被瀏覽器解析和執行之前注入一些東西,我建議你使用像Mitmproxy這樣的代理。

如果您無法修改頁面內容,您可以使用代理,或在瀏覽器中安裝的擴展程序中使用內容腳本。 在 selenium 中執行此操作,您將編寫一些代碼將腳本作為現有元素的子元素之一注入,但在頁面加載之前(當您的驅動程序的get()調用返回時),您將無法運行它。

String name = (String) ((JavascriptExecutor) driver).executeScript(
    "(function () { ... })();" ...

文檔未指定代碼開始執行的時刻。 您希望它在 DOM 開始加載之前完成,以便保證可能只能滿足代理或擴展內容腳本路由。

如果您可以使用最少的工具來檢測您的頁面,您可能會檢測到特殊 url 查詢參數的存在並加載其他內容,但您需要使用內聯腳本來執行此操作。 偽代碼:

 <html>
    <head>
       <script type="text/javascript">
       (function () {
       if (location && location.href && location.href.indexOf("SELENIUM_TEST") >= 0) {
          var injectScript = document.createElement("script");
          injectScript.setAttribute("type", "text/javascript");

          //another option is to perform a synchronous XHR and inject via innerText.
          injectScript.setAttribute("src", URL_OF_EXTRA_SCRIPT);
          document.documentElement.appendChild(injectScript);

          //optional. cleaner to remove. it has already been loaded at this point.
          document.documentElement.removeChild(injectScript);
       }
       })();
       </script>
    ...

所以我知道已經有幾年了,但是我找到了一種無需修改網頁內容且無需使用代理即可完成此操作的方法! 我使用的是 nodejs 版本,但大概其他語言的 API 也是一致的。 你想要做的如下

const {Builder, By, Key, until, Capabilities} = require('selenium-webdriver');
const capabilities = new Capabilities();
capabilities.setPageLoadStrategy('eager'); // Options are 'eager', 'none', 'normal'
let driver = await new Builder().forBrowser('firefox').setFirefoxOptions(capabilities).build();
await driver.get('http://example.com');
driver.executeScript(\`
  console.log('hello'
\`)

那個“熱切”的選項對我有用。 您可能需要使用“無”選項。 文檔: https : //seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/capabilities_exports_PageLoadStrategy.html

編輯:請注意,“熱切”選項尚未在 Chrome 中實現...

Selenium 現在已經支持 Chrome Devtools Protocol (CDP) API,因此,在每個頁面加載時執行腳本真的很容易。 這是一個示例代碼:

driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {'source': 'alert("Hooray! I did it!")'})

它將為每個頁面加載執行該腳本。 可以在以下位置找到有關此的更多信息:

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM