MachinePublishers / jBrowserDriver

A programmable, embeddable web browser driver compatible with the Selenium WebDriver spec -- headless, WebKit-based, pure Java
Other
809 stars 143 forks source link

Could not launch browser #198

Closed weiwill closed 7 years ago

weiwill commented 7 years ago

I use JBrowserDriver for screenshot run in tomcat background. The program runs for half a day or a day or so, Will throw the following exception

Caused by: org.openqa.selenium.WebDriverException: Could not launch browser. Build info: version: '2.53.0', revision: '35ae25b1534ae328c771e0856c93e187490ca824', time: '2016-03-15 10:43:46' System info: host: 'iZ233dwnlq8Z', ip: '_._.60.173', os.name: 'Windows Server 2012 R2', os.arch: 'amd64', os.version: '6.3', java.version: '1.8.0_91' Driver info: driver.version: JBrowserDriver at com.machinepublishers.jbrowserdriver.Util.handleException(Util.java:140) at com.machinepublishers.jbrowserdriver.JBrowserDriver.(JBrowserDriver.java:282) at com.jgwei.vin.utils.ConnUtil.screenshot2(ConnUtil.java:323) ... 14 more Caused by: java.lang.IllegalStateException: Could not launch browser. ... 17 more

here screenshot code

   public static BufferedImage screenshot2(String html,
                                      String scrollWidthScript, String scrollHeightScript, String script){
        if(html == null || "".equals(html)){
            return  null;
        }
        Settings.Builder builder = Settings.builder();

        JBrowserDriver driver = new JBrowserDriver(builder
                .logTrace(false)
                .logWarnings(false)
                .connectTimeout(1)
                .build());

        driver.setErrorHandler(null);
        BufferedImage bufferedImage = null;
        try {
            File tempFile = File.createTempFile("temp_html_" + System.currentTimeMillis(),".html");
            System.out.println(tempFile.toURI());
            OutputStream out = new FileOutputStream(tempFile);
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"));
            writer.write(html);
            writer.close();
            out.close();
            driver.get(tempFile.toURI().toString());
            int scrollWidth = Integer.valueOf(driver.executeScript(scrollWidthScript).toString());
            int scrollHeight = Integer.valueOf(driver.executeScript(scrollHeightScript).toString());
            driver.reset(builder.screen(new Dimension(scrollWidth,scrollHeight)).build());
            driver.get(tempFile.toURI().toString());
            if(!"".equals(script)){
                driver.executeScript(script);
            }
            File scrFile = driver.getScreenshotAs(OutputType.FILE);
            tempFile.deleteOnExit();
            bufferedImage = ImageUtiil.toBufferedImage(scrFile);
            scrFile.deleteOnExit();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            driver.kill();
        }
        return bufferedImage;
    }
weiwill commented 7 years ago

I use ThreadPool to call screenshot2 method

ExecutorService executorService = Executors.newFixedThreadPool(4);
Future  future = executorService.submit((Callable) () -> {
        Document tempDoc = Jsoup.parse(html);
        BufferedImage bufferedImage = ConnUtil.screenshot2(tempDoc.html());
        return  bufferedImage;
    });

The current situation seems to be running a screenshot2 this method, the time used, it will be a little more than the last time, the final will appear above the error.

Time seems to have spent on creating JBrowserDriver

JBrowserDriver driver = new JBrowserDriver(builder
            .logTrace(false)
            .logWarnings(false)
            .connectTimeout(1)
            .build());
weiwill commented 7 years ago

This is my test code, it will slow down after a few minutes.

public static void main(String[] args) {
        final int[] seconds = {0};
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            public void run() {
                seconds[0]++;
                System.out.println("-------"+ seconds[0] +"--------");
            }
        }, 0,1000);

        ExecutorService executorService = Executors.newFixedThreadPool(4);
        String html ="<html>\n" +
                " <head> \n" +
                "  <meta http-equiv=\"Content-Type\" content=\"text/html;charset=UTF-8\">   \n" +
                " </head> \n" +
                " <body> \n" +
                " </body>\n" +
                "</html>";
        for (int i = 0; i < 2000; i++) {
            executorService.submit((Callable) () -> {
                long beginTime = System.currentTimeMillis();
                String scrollWidthScript = "return document.body.scrollWidth;";
                String scrollHeightScript = "return document.body.scrollHeight";
                System.out.println(Thread.currentThread().getName()+" create build");
                Settings.Builder builder = Settings.builder();
                JBrowserDriver driver = new JBrowserDriver(builder
                        .logTrace(false)
                        .logWarnings(false)
                        .connectTimeout(1)
                        .build());
                System.out.println(Thread.currentThread().getName()+" create driver");
                BufferedImage bufferedImage = null;
                try {
                    File tempFile = File.createTempFile("temp_html_" + System.currentTimeMillis(),".html");
                    System.out.println(Thread.currentThread().getName()+" create tempFile");
                    OutputStream out = new FileOutputStream(tempFile);
                    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"));
                    writer.write(html);
                    writer.close();
                    out.close();
                    System.out.println(Thread.currentThread().getName()+" write tempFile");
                    driver.get(tempFile.toURI().toString());
                    int scrollWidth = Integer.valueOf(driver.executeScript(scrollWidthScript).toString());
                    int scrollHeight = Integer.valueOf(driver.executeScript(scrollHeightScript).toString());
                    driver.reset(builder.screen(new Dimension(scrollWidth,scrollHeight)).build());
                    driver.get(tempFile.toURI().toString());

                    File scrFile = driver.getScreenshotAs(OutputType.FILE);
                    tempFile.deleteOnExit();
                    bufferedImage = toBufferedImage(scrFile);
                    scrFile.deleteOnExit();
                    ImageIO.write(bufferedImage.getSubimage(0,0,scrollWidth,scrollHeight),"jpg",new File("F:\\tmp\\"+System.currentTimeMillis()+".jpg"));
                    System.out.println(Thread.currentThread().getName()+" create image");
                    System.out.println(Thread.currentThread().getName()+" use time: "+(System.currentTimeMillis() - beginTime) +" Millisecond");
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    driver.kill();
                }
                return null;
            });
        }

    }

    public static BufferedImage toBufferedImage(File img) throws IOException {
        Image image = Toolkit.getDefaultToolkit().getImage(img.getPath());
        BufferedImage bimage = null;
        if (image instanceof BufferedImage) {
            return (BufferedImage) image;
        }
        image = new ImageIcon(image).getImage();
        int width = image.getWidth(null);
        int height = image.getHeight(null);
        if (width < 0 || height < 0) {
            return null;
        }
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        try {
            int transparency = Transparency.OPAQUE;
            GraphicsDevice gs = ge.getDefaultScreenDevice();
            GraphicsConfiguration gc = gs.getDefaultConfiguration();
            bimage = gc.createCompatibleImage(width, height, transparency);
        } catch (HeadlessException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (bimage == null) {
            int type = BufferedImage.TYPE_INT_RGB;
            bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
        }
        Graphics g = bimage.createGraphics();
        g.drawImage(image, 0, 0, null);
        g.dispose();
        return bimage;
    }
weiwill commented 7 years ago

I'm remove code synchronized (Object.class) {} in SocketFactory.createSocket() method,it's looks like OK.

hollingsworthd commented 7 years ago

@weiwill Good find. Thank you! That line synchronized (Object.class) { does look problematic. I think that area of code doesn't need synchronization at all because bind will throw an exception if two threads try the same port, and there's already error handling for that. I'll try removing it too and see if I find any problems without it.

weiwill commented 7 years ago

The new version has been able to work, thanks