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
<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>
...
6条答案
按热度按时间mzillmmw1#
Selenium现在支持Chrome Devtools协议(CDP)API,因此,在每次页面加载时执行脚本非常容易。下面是一个示例代码:
字符串
它将为每个页面加载执行该脚本。有关此的详细信息可以在以下位置找到:
vbopmzt12#
从1.0.9版开始,selenium-wire获得了修改请求响应的功能。下面是此功能的一个示例,在页面到达Web浏览器之前将脚本注入页面。
字符串
另一种远程控制浏览器并能够在页面内容加载之前注入脚本的方法是使用完全基于单独协议的库,例如:Chrome DevTools Protocol。
hgc7kmma3#
如果你想在页面被浏览器解析和执行之前注入一些东西到页面的html中,我建议你使用一个代理,比如Mitmproxy。
xmjla07d4#
如果你不能修改页面内容,你可以使用代理,或者使用浏览器中安装的扩展中的内容脚本。在selenium中这样做,你会编写一些代码,将脚本作为现有元素的子元素之一注入,但是在页面加载之前(当驱动程序的
get()
调用返回时),你不能让它运行。字符串
文档中没有指定代码开始执行的时间。你可能希望它在DOM开始加载之前就开始执行,这样保证可能只能通过代理或扩展内容脚本路由来满足。
如果你可以用最小的工具来检测你的页面,你可能会检测到一个特殊的url查询参数的存在,并加载额外的内容,但你需要使用内联脚本来实现。伪代码:
型
n7taea2i5#
所以我知道这是几年前的事了,但我已经找到了一种方法来做到这一点,而无需修改网页的内容,也无需使用代理!我使用的是nodejs版本,但想必API对其他语言也是一致的。你想做的是如下所示
字符串
这个“渴望”选项对我来说很有效。你可能需要使用“无”选项。文档:https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/capabilities_exports_PageLoadStrategy.html
编辑:请注意,“渴望”选项尚未在Chrome中实现.
nfeuvbwi6#
更新版本的@Mattwmaster58的答案,适用于最新版本的
selenium-wire
(撰写本文时为5.1.0)。还增加了对内联脚本标记的nonce
attributes支持。字符串
作为使用
lxml
生成输出的替代方案(这可能会改变HTML的结构),您还可以使用正则表达式插入标记并保留现有格式:型