简体   繁体   English

Selenium webdriver:firefox无头注入javascript来修改浏览器属性

[英]Selenium webdriver: firefox headless inject javascript to modify browser property

I'm trying to figure out how is possible to use selenium webdriver with python or java to inject javascript in order to modify browser property/attribute. 我试图弄清楚如何使用pylen或java的selenium webdriver来注入javascript以修改浏览器属性/属性。 My final object is to get something similar to this with selenium and firefox since it is a more open and flexible choice. 我的最终目的是要得到类似的东西与硒和Firefox,因为它是一个更开放,更灵活的选择。

Puppeter and chromium file test.js : 木偶和铬文件test.js

const puppeteer = require("puppeteer");

(async () => {
  const browser = await puppeteer.launch({
    args: ["--no-sandbox"],
    headless: true,
  });
  const page = await browser.newPage();
  const fs = require("fs");

  // In your puppeteer script, assuming the javascriptChromium.js file is in same folder of our script
  const preloadFile = fs.readFileSync("./javascriptChromium.js", "utf8");
  await page.evaluateOnNewDocument(preloadFile);

  const testUrl="https://intoli.com/blog/not-possible-to-block-chrome-headless/chrome-headless-test.html";

  await page.goto(testUrl);

  // save screenshot
  await page.screenshot({path: "puppeteer-chromium-async-script-test.png"});
  await browser.close()
})();

Javascript file javascriptChromium.js Javascript文件javascriptChromium.js

// overwrite the `languages` property to use a custom getter
Object.defineProperty(navigator, "languages", {
  get: function() {
    return ["en-US", "en", "es"];
  }
});

// Overwrite the `plugins` property to use a custom getter.
Object.defineProperty(navigator, 'plugins', {
  get: () => [1, 2, 3, 4, 5],
});

// Pass the Webdriver test
Object.defineProperty(navigator, 'webdriver', {
  get: () => false,
});

This code works well and I checked that the property are changed via this test Web site . 此代码运行良好,我检查通过此测试网站更改属性。

Now, selenium and firefox: 现在,selenium和firefox:

import os
from selenium import webdriver

def readJSFile(scriptFile):
    with open(scriptFile, 'r') as fileHandle:  
        script=fileHandle.read()
    return script
injectedJavascript=readJSFile("./javascriptFirefox.js")

options=webdriver.FirefoxOptions()
options.set_headless(True)
driver=webdriver.Firefox(options=options)
driver.set_script_timeout(3)

# inject JavaScript
try:
    driver.execute_async_script(injectedJavascript)
except:
    print("Timeout")

# solution found here https://stackoverflow.com/questions/17385779/how-do-i-load-a-javascript-file-into-the-dom-using-selenium
driver.execute_script("var s=window.document.createElement('script'); s.src='javascriptFirefox.js';window.document.head.appendChild(s);")
testUrl="https://intoli.com/blog/not-possible-to-block-chrome-headless/chrome-headless-test.html";
driver.get(testUrl)

# example sync script
time=driver.execute_script("return performance.timing.loadEventEnd - performance.timing.navigationStart;")
print(time)
# example async script
time=driver.execute_async_script("var callback = arguments[arguments.length-1]; const time = () => { total=performance.timing.loadEventEnd - performance.timing.navigationStart; callback(total); }; time();")
print(time)

file="selenium-firefox-async-script-test.png"
driver.save_screenshot(file)

driver.quit()

Javascript file javascriptFirefox.js Javascript文件javascriptFirefox.js

// overwrite the `languages` property to use a custom getter
const setProperty = () => {
    Object.defineProperty(navigator, "languages", {
        get: function() {
            return ["en-US", "en", "es"];
        }
    });

    // Overwrite the `plugins` property to use a custom getter.
    Object.defineProperty(navigator, 'plugins', {
        get: () => [1, 2, 3, 4, 5],
    });

    // Pass the Webdriver test
    Object.defineProperty(navigator, 'webdriver', {
      get: () => false,
    });
    callback();
};
setProperty();

I'm new of javascript, but what seems different between the two approaches (puppeteer and selenium) is about how they manage the current tab/page. 我是javascript的新手,但两种方法(puppeteer和selenium)之间的不同之处在于它们如何管理当前的标签/页面。 The former via page class and method page.evaluateOnNewDocument while for the latter I did not find and equivalent way. 前者通过页面类和方法page.evaluateOnNewDocument而后者我没有找到和等效的方式。 I tried also the use greasemonkey or violentlmonkey to inject javascript without success. 我也尝试使用greasemonkey或violentlmonkey来注入javascript但没有成功。

Do you have any suggestions? 你有什么建议吗?

Thank you 谢谢

I found the solution to the problem by following this post . 按照这篇文章我找到了问题的解决方案。 In few words, by using an extensions it is possible to inject javascript code into the Web page also with firefox. 简而言之,通过使用扩展,可以使用firefox将javascript代码注入到Web页面中。 In order to avoid a waste of time for the other users, the main files are: 为了避免浪费其他用户的时间,主要文件是:

Python file: selenium+firefox Python文件:selenium + firefox

import json
import os
import sys

from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.firefox.firefox_profile import AddonFormatError

# Patch in support for WebExtensions in Firefox.
# See: https://intoli.com/blog/firefox-extensions-with-selenium/
class FirefoxProfileWithWebExtensionSupport(webdriver.FirefoxProfile):
    def _addon_details(self, addon_path):
        try:
            return super()._addon_details(addon_path)
        except AddonFormatError:
            try:
                with open(os.path.join(addon_path, "manifest.json"), "r") as f:
                    manifest = json.load(f)
                    return {
                        "id": manifest["applications"]["gecko"]["id"],
                        "version": manifest["version"],
                        "name": manifest["name"],
                        "unpack": False,
                    }
            except (IOError, KeyError) as e:
                raise AddonFormatError(str(e), sys.exc_info()[2])

profile_folder="profile_path"
profile=FirefoxProfileWithWebExtensionSupport(profile_folder)
extension_directory="extension"
profile.add_extension(extension_directory)
# firefox dev it is necessary for custom profile, not for standard one
firefox_binary="/usr/bin/firefox-dev"
options=webdriver.FirefoxOptions()
# firefox 56+ headless mode https://developer.mozilla.org/en-US/Firefox/Headless_mode
options.set_headless(True)
driver=webdriver.Firefox(options=options, firefox_profile=profile, firefox_binary=firefox_binary)

test_url="https://intoli.com/blog/not-possible-to-block-chrome-headless/chrome-headless-test.html";
driver.get(test_url)

file="selenium-firefox-extension-profile-script-second-test.png"
driver.save_screenshot(file)

test_url="https://intoli.com/blog/making-chrome-headless-undetectable/chrome-headless-test.html";
driver.get(test_url)

file="selenium-firefox-extension-profile-script-first-test.png"
driver.save_screenshot(file)

driver.quit()

Extensions files: manifest.js and content.js 扩展文件:manifest.js和content.js

{
  "manifest_version": 2,
  "name": "Smart Extension",
  "version": "1.0.0",
  "applications": {
    "gecko": {
      "id": "user@protonmail.com"
    }
  },
  "content_scripts": [
    {
      "matches": ["*://*/*"],
      "js": ["content.js"],
      "run_at": "document_start"
    }
  ]
}

var script=document.createElement("script");
script.src=browser.extension.getURL("myscript.js");
script.async=false;
document.documentElement.appendChild(script);

Javascript file: myscript.js Javascript文件:myscript.js

// overwrite the `languages` property to use a custom getter
Object.defineProperty(navigator, "languages", {
  get: function() {
    return ["en", "es"];
  }
});

// Overwrite the `plugins` property to use a custom getter.
Object.defineProperty(navigator, "plugins", {
  get: () => new Array(Math.floor(Math.random() * 6) + 1),
});

// Pass the Webdriver test
Object.defineProperty(navigator, "webdriver", {
  get: () => false,
});

// hairline: store the existing descriptor
const elementDescriptor=Object.getOwnPropertyDescriptor(HTMLElement.prototype, "offsetHeight");

// redefine the property with a patched descriptor
Object.defineProperty(HTMLDivElement.prototype, "offsetHeight", {
    ...elementDescriptor,
  get: function() {
    if (this.id === "modernizr") {
      return 1;
    }
    return elementDescriptor.get.apply(this);
  },
});

["height", "width"].forEach(property => {
  // store the existing descriptor
  const imageDescriptor=Object.getOwnPropertyDescriptor(HTMLImageElement.prototype, property);

  // redefine the property with a patched descriptor
  Object.defineProperty(HTMLImageElement.prototype, property, {
    ...imageDescriptor,
    get: function() {
      // return an arbitrary non-zero dimension if the image failed to load
      if (this.complete && this.naturalHeight == 0) {
        return 24;
      }
      // otherwise, return the actual dimension
      return imageDescriptor.get.apply(this);
    },
  });
});

const getParameter=WebGLRenderingContext.getParameter;
WebGLRenderingContext.prototype.getParameter=function(parameter) {
  // UNMASKED_VENDOR_WEBGL WebGLRenderingContext.prototype.VENDOR
  if (parameter === 37445) {
    return "Intel Open Source Technology Center";
  }
  // UNMASKED_RENDERER_WEBGL WebGLRenderingContext.prototype.RENDERER
  if (parameter === 37446) { 
    return "Mesa DRI Intel(R) Ivybridge Mobile";
  }
  return getParameter(parameter);
};

This works well for all tests in graphical mode while in headless mode all tests except WebGL test which seems affect to a bug . 这适用于图形模式下的所有测试,而在无头模式下除了WebGL测试之外的所有测试都会影响bug

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Selenium-WebDriver 如何使用 javascript 和 firefox 浏览器突出显示元素 - Selenium-WebDriver how to highlight element using javascript and firefox browser Selenium WebDriver Javascript:修改元素CSS - Selenium WebDriver Javascript : Modify element CSS Javascript:无法使用Selenium中的Firefox浏览器 - Javascript: Unable to Firefox browser in Selenium Selenium WebDriver(Firefox):动态禁用Javascript - Selenium WebDriver (Firefox): dynamically disable Javascript 硒无头JavaScript下载 - Headless javascript download with selenium 如何注入javascript和修改原生android浏览器google搜索结果 - how to inject javascript and modify native android browser google search results 带有Edge TypeError的Javascript Selenium Webdriver:无法读取null的属性“开始” - Javascript Selenium Webdriver with Edge TypeError: Cannot read property 'start' of null 谁能帮助您以编程方式使用Selenium Webdriver将修改标头用户代理添加到Chrome浏览器 - Can anyone help to how to add modify header user-agent to chrome browser using selenium webdriver programmatically Java Selenium,如何直接定义/修改javascript函数并在浏览器中运行它? - Java Selenium, how to directly define/modify javascript function and run it in browser? FireFox的无头浏览器(类似于适用于Chrome的PhantomJS) - Headless browser for FireFox (similar to PhantomJS for Chrome)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM