Selenium:在加载/执行页面的任何其他脚本之前,如何在页面中注入/执行Javascript?

Ale*_*lex 23 javascript python selenium javascript-injection

我正在使用selenium python webdriver来浏览一些页面.我想在加载和执行任何其他Javascript代码之前将javascript代码注入页面.另一方面,我需要将我的JS代码作为该页面的第一个JS代码来执行.有没有办法通过Selenium做到这一点?

我用谷歌搜索了几个小时,但我找不到任何正确的答案!

小智 21

Selenium 现在支持 Chrome Devtools Protocol (CDP) API,因此,在每次页面加载时执行脚本确实很容易。这是一个示例代码:

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

它将为每个页面加载执行该脚本。有关此内容的更多信息可以在以下位置找到:


Mat*_* M. 7

从 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
Run Code Online (Sandbox Code Playgroud)

通常远程控制浏览器并能够在页面内容加载之前注入脚本的另一种方法是使用完全基于单独协议的库,例如:DevTools 协议。此处提供了 Python 实现:https : //github.com/pyppeteer/pyppeteer2(免责声明:我是主要作者之一)


Jon*_*han 6

如果您想在网页的html中插入某些内容,然后再由浏览器对其进行解析和执行,则建议您使用Mitmproxy之类的代理。


ini*_*_js 4

如果您无法修改页面内容,您可以使用代理,或使用浏览器中安装的扩展程序中的内容脚本。get()在 selenium 中执行此操作,您将编写一些代码,将脚本作为现有元素的子元素之一注入,但在加载页面之前(当驱动程序的调用返回时),您将无法让它运行。

String name = (String) ((JavascriptExecutor) driver).executeScript(
    "(function () { ... })();" ...
Run Code Online (Sandbox Code Playgroud)

该文档未指定代码开始执行的时间。您可能希望在 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>
    ...
Run Code Online (Sandbox Code Playgroud)