Selenium: Как вставлять/выполнять Javascript на странице перед загрузкой/выполнением каких-либо других скриптов на странице?
Я использую selenium python webdriver для просмотра некоторых страниц. Я хочу ввести код javascript на страницы, прежде чем загружать и выполнять любые другие коды Javascript. С другой стороны, мне нужен мой JS-код, который будет выполнен как первый JS-код этой страницы. Есть ли способ сделать это с помощью Selenium?
Я отправил его в течение нескольких часов, но я не нашел подходящего ответа!
Ответы
Ответ 1
Если вы не можете изменить содержимое страницы, вы можете использовать прокси или использовать контент script в расширении, установленном в вашем браузере. Сделав это в селене, вы напишете код, который вводит script как один из дочерних элементов существующего элемента, но вы не сможете запустить его до загрузки страницы (когда ваш драйвер get()
возвращает вызов.)
String name = (String) ((JavascriptExecutor) driver).executeScript(
"(function () { ... })();" ...
Документация оставляет неуказанным момент начала выполнения кода. Вы хотите, чтобы это было до того, как DOM начнет загрузку, так что гарантия может быть выполнена только с прокси-сервером или контентом script.
Если вы можете измерить свою страницу с минимальной привязкой, вы можете обнаружить наличие специального параметра запроса url и загрузить дополнительный контент, но вам нужно сделать это с помощью встроенного script. Псевдокод:
<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>
...
Ответ 2
Если вы хотите внедрить что-либо в html-страницу, прежде чем она будет проанализирована и выполнена браузером, я бы посоветовала вам использовать прокси-сервер, такой как Mitmproxy.
Ответ 3
Начиная с версии 1.0.9, selenium-wire получила функциональность для изменения ответов на запросы. Ниже приведен пример этой функции для вставки скрипта в страницу, прежде чем он достигнет веб-браузера.
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
injected.append((req, req_body, res, res_body, parsed_html))
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
Ответ 4
я знаю, что прошло несколько лет, но я нашел способ сделать это без изменения содержимого веб-страницы и без использования прокси! Я использую версию nodejs, но, вероятно, API совместим и с другими языками. То, что вы хотите сделать, заключается в следующем
const {Builder, By, Key, until, Capabilities} = require('selenium-webdriver');
const capabilities = new Capabilities();
cap.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'
\')
Этот вариант "рвение" работает для меня. Возможно, вам придется использовать опцию "none". Документация: https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/capabilities_exports_PageLoadStrategy.html
РЕДАКТИРОВАТЬ: Обратите внимание, что опция 'нетерпеливый' еще не был реализован в Chrome...
Ответ 5
Теперь есть https://pypi.org/project/selenium-wire/, который позволяет относительно легко получить доступ/изменить все запросы.