Selenium WebDriver 线程安全吗?

问题描述 投票:0回答:2

更具体地说,同时在单个 WebDriver/WebElement 上执行多个操作是否安全?即像这样

WebDriver driver; //driver initialized somehow
final WebElement elem = driver.findElement(By.cssSelector("#elementID"));

//simplified for example, but in real code I'd be storing the results of these calls
new Thread() {
    @Override
    public void run() {
        elem.isDisplayed();
    }
}.run();
new Thread() {
    @Override
    public void run() {
        elem.isEnabled();
    }
}.run();

我自己尝试过在本地交互时没有出现任何问题,但在对远程硒网格执行相同的操作时遇到间歇性问题。

我不确定我遇到的问题是否来自 Selenium 本身,或者 Selenium 是否良好并且这是我正在使用的托管网格提供商的限制。 使用Python进行抓取时,selenium线程安全吗?提到selenium可能不是线程安全的,但我找不到任何确认。

java multithreading selenium
2个回答
13
投票

这个问题有答案这里

“WebDriver 不是线程安全的。话虽如此,如果您可以序列化对底层驱动程序实例的访问,则可以在多个线程中共享引用。这是不可取的。另一方面,您/可以/实例化一个每个线程的 WebDriver 实例。”


0
投票

您可以使用选项卡管理使其线程安全。每个线程都有自己的选项卡,当您使用完毕后,请关闭该选项卡。所有涉及导航的区域都应该同步。

 /**
 *
 * @author michaelassraf
 */
@Component
public class ChromePDFExporter {

    protected Logger logger = Utils.getInstance().getLogger(ChromePDFExporter.class);

    @Autowired
    RestfulClient restfulClient;

    @Value(PropertiesFieldNames.ChromePDFExporterLocalPortNumber)
    Integer chromePDFExporterLocalPortNumber;

    @Value(PropertiesFieldNames.TempDir)
    File tempDir;

    private ChromeDriver chromeDriver;

    String chromeDriverOriginalWindowHandle = null;

    public synchronized ChromeDriver buildChromeClient() {
        try {
            logger.info("<< ChromePDFExporter is starting >>");
            ChromeOptions options = getChromeOptions(chromePDFExporterLocalPortNumber);
            ChromeDriverService service = new ChromeDriverService.Builder()
                    .withAppendLog(true)
                    .withVerbose(true)
                    .withLogLevel(ChromiumDriverLogLevel.ALL)
                    .withLogFile(
                            new File(tempDir.getAbsolutePath() + File.separator + ChromeDriver.class.getSimpleName() + "LogFile.log"))
                    .withLogOutput(new FileOutputStream(
                            new File(tempDir.getAbsolutePath() + File.separator + ChromeDriver.class.getSimpleName() + "LogOutput.log")))
                    .withAllowedListIps(Utils.getInstance().getMachinePrivateIP(restfulClient))
                    .usingPort(chromePDFExporterLocalPortNumber)
                    .build();
            logger.info("<< ChromePDFExporter local ip is " + Utils.getInstance().getMachinePrivateIP(restfulClient) + " >>");
            chromeDriver = new ChromeDriver(service, options);
            chromeDriverOriginalWindowHandle = chromeDriver.getWindowHandle();
            logger.info("<< ChromePDFExporter Launched " + chromeDriver.getSessionId() + " >>");
        } catch (Throwable th) {
            logger.error("ChromePDFExporter - Can't launch Chrome Driver.", th);
        }

        return chromeDriver;
    }

    private ChromeOptions getChromeOptions(Integer port) {
        ChromeOptions options = new ChromeOptions();
        options.addArguments("--no-sandbox"); // Bypass OS security model.
        options.setExperimentalOption("useAutomationExtension", false);
        options.addArguments("--headless");
        options.addArguments("--disable-popup-blocking");
        options.addArguments("--disable-setuid-sandbox");
        options.addArguments("--enable-automation");
        options.addArguments("--disable-browser-side-navigation");
        options.addArguments("--disable-blink-features=AutomationControlled");
        options.addArguments("--disable-web-security");
        options.addArguments("--remote-allow-origins=*");
        options.addArguments("--wait-for-all-loading");
        options.addArguments("--remote-debugging-pipe");
        options.addArguments("--incognito");
        options.addArguments("--guest");
        options.addArguments("--run-all-compositor-stages-before-draw");
        options.addArguments("disable-infobars"); // disabling infobars
        options.addArguments("--disable-extensions"); // disabling extensions
        options.addArguments("--disable-gpu"); // applicable to windows os only
        options.addArguments("--disable-dev-shm-usage"); // overcome limited resource problems
        options.addArguments("--remote-debugging-port=" + port);
        options.addArguments("--no-first-run");
        options.addArguments("--no-default-browser-check");
        options.addArguments("--disable-infobars");
        options.addArguments("--user-data-dir=" + tempDir.getAbsolutePath() + File.separator + ChromeOptions.class.getSimpleName() + "Data");
        options.addArguments("--profile-directory=" + tempDir.getAbsolutePath() + File.separator + ChromeOptions.class.getSimpleName() + "Profile");
        Map<String, Object> prefs = new HashMap<String, Object>();
        prefs.put("profile.default_content_settings.popups", false);
        prefs.put("distribution.skip_first_run_ui", true);
        prefs.put("signin.allowed_on_next_startup", false);
        prefs.put("safebrowsing.enabled", false);
        options.setExperimentalOption("prefs", prefs);
        return options;
    }

    ChromeDriver getChromeDriver(String navigateTo) {
        boolean shouldReconnect = chromeDriver == null;
        checkIfAlive:
        {
            if (shouldReconnect) {
                break checkIfAlive;
            }
            try {
                chromeDriver.switchTo().window(navigateTo == null ? chromeDriverOriginalWindowHandle : navigateTo);
                chromeDriver.getCurrentUrl();
            } catch (Throwable th) {
                shouldReconnect = true;
            }
        }
        if (shouldReconnect) {
            buildChromeClient();
        }
        return chromeDriver;
    }

    @Autowired
    ReportComponentHTMLBlocks reportComponentHTMLBlocks;

    @Autowired
    Base64Encryption base64Encryption;

    HashSet<String> processedComponents = new HashSet<>();

    Object synchronizer = new Object();

    boolean checkIfAtLeastOneComponentWasNotProcessed(HashSet<String> components) {
        for (String component : components) {
            if (!processedComponents.contains(component)) {
                processedComponents.addAll(components);
                return true;
            }
        }
        return false;
    }

    public File exportFromPDFUsingChrome(File htmlFile,
            String targeFile,
            boolean addGenericFooterAndHeader,
            String injectCustomFooter,
            String organizationName,
            String reportTemplateName,
            HashSet<String> components) {

        String url = "file://" + htmlFile.getAbsolutePath();
        String tabName = null;

        File pdfFile = new File(targeFile);

        synchronized (synchronizer) {
            ((JavascriptExecutor) getChromeDriver(null)).executeScript("window.open()");
            ArrayList<String> tabs = new ArrayList<>(getChromeDriver(null).getWindowHandles());
            tabName = tabs.get(tabs.size() - 1);
            getChromeDriver(tabName).get(url);
        }

        Map<String, Object> params = new HashMap();

        params.put("headerLeft", 0);
        params.put("headerRight", 0);

        Double spaceForFooter = addGenericFooterAndHeader ? 1.0 : 0;
        spaceForFooter = injectCustomFooter != null ? 5.0 : spaceForFooter;

        Double spaceForHeader = addGenericFooterAndHeader ? 1.0 : 0;

        params.put("headerBottom", spaceForFooter);
        params.put("headerTop", spaceForHeader);

        params.put("marginLeft", 0);
        params.put("marginRight", 0);
        params.put("marginBottom", spaceForFooter);
        params.put("marginTop", spaceForHeader);

        params.put("printBackground", true);
        params.put("transferMode", "ReturnAsBase64");
        params.put("displayHeaderFooter", addGenericFooterAndHeader || injectCustomFooter != null);

        if (addGenericFooterAndHeader) {
            params.put("headerTemplate", reportComponentHTMLBlocks
                    .getChromePDFExporterHeader(organizationName, reportTemplateName));
            params.put("footerTemplate", reportComponentHTMLBlocks
                    .getChromePDFExporterFooter(20));
        }

        if (injectCustomFooter != null) {
            params.put("footerTemplate", injectCustomFooter);
        }

        String command = "Page.printToPDF";
        Map<String, Object> output = null;
        boolean keepRunning = true;
        while (keepRunning) {
            workaroundForChromeExportBug:
            {
                synchronized (synchronizer) {
                    output = getChromeDriver(tabName).executeCdpCommand(command, params);
                }

                boolean containsOneUnprocessedCompenent = checkIfAtLeastOneComponentWasNotProcessed(components);
                keepRunning = containsOneUnprocessedCompenent;
                if (!containsOneUnprocessedCompenent) {
                    break workaroundForChromeExportBug;
                }
                logger.info("First run of Chrome, running export retry.");
                synchronized (synchronizer) {
                    getChromeDriver(tabName).navigate().refresh();
                }
                try {
                    Thread.sleep(100l);
                } catch (Throwable th) {
                }
            }
        }

        Utils.getInstance().deleteDirectory(pdfFile.getAbsolutePath());

        FileOutputStream fileOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream(pdfFile.getAbsolutePath());
        } catch (Throwable th) {
            logger.error("Can't create file output stream.", th);
        }
        byte[] byteArray = base64Encryption.decodeToByteArray((String) output.get("data"));
        try {
            fileOutputStream.write(byteArray);
        } catch (Throwable th) {
            logger.error("Can't write file input stream.", th);
        }
        try {
            fileOutputStream.close();
        } catch (Throwable th) {
            logger.error("Can't close file outpute stream.", th);
        }

        synchronized (synchronizer) {
            ((JavascriptExecutor) getChromeDriver(tabName)).executeScript("window.close();");
        }

        return pdfFile;
    }

    @PreDestroy
    public void destroyChromeDriverThreadLocal() {
        if (chromeDriver == null) {
            return;
        }

        chromeDriver.close();
        chromeDriver.quit();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.