2016-03-28 8 views
0

Ich möchte mit HtmlUnitDriver einen Screenshot einer Seite erstellen Ich bin auf diesen Link gestoßen, wo dieser Typ einen benutzerdefinierten HTML-Einheitentreiber erstellt hat, um den Screenshot zu erstellen. Aber leider, während der Umsetzung, bekomme ich eine Ausnahme.Screenshot kann nicht mit HtmlUnitDriver [Selenium WebDriver java]

"Exception in thread "main" java.lang.ClassCastException: [B nicht java.io.File bei Test.main (Test.java:39) gegossen werden kann" My Code

ist als folgt-

import java.io.File; 
import java.io.IOException; 
import org.openqa.selenium.OutputType; 
import org.openqa.selenium.WebDriver; 
import com.gargoylesoftware.htmlunit.BrowserVersion; 

public class Test extends ScreenCaptureHtmlUnitDriver { 

    public static void main(String[] args) throws InterruptedException, IOException { 

     WebDriver driver = new ScreenCaptureHtmlUnitDriver(BrowserVersion.FIREFOX_38); 
     driver.get("https://www.google.com/?gws_rd=ssl"); 
     try{ 
     File scrFile = ((ScreenCaptureHtmlUnitDriver) driver).getScreenshotAs(OutputType.FILE); 
     FileUtils.copyFile(scrFile, new File("D:\\TEMP.PNG")); 
     }catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Htmlunit Treiber, den I (die eine, die in der Verbindung ist) verwende ist this-

import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
import java.net.URL; 
import java.util.Collections; 
import java.util.HashMap; 
import java.util.Iterator; 
import java.util.LinkedList; 
import java.util.List; 
import java.util.Map; 
import java.util.regex.Matcher; 
import java.util.regex.Pattern; 
import java.util.zip.ZipEntry; 
import java.util.zip.ZipOutputStream; 
import org.apache.commons.io.FilenameUtils; 
import org.apache.commons.io.IOUtils; 
import org.openqa.selenium.Capabilities; 
import org.openqa.selenium.OutputType; 
import org.openqa.selenium.TakesScreenshot; 
import org.openqa.selenium.WebDriverException; 
import org.openqa.selenium.htmlunit.HtmlUnitDriver; 
import org.openqa.selenium.internal.Base64Encoder; 
import org.openqa.selenium.remote.CapabilityType; 
import org.openqa.selenium.remote.DesiredCapabilities; 
import com.gargoylesoftware.htmlunit.BrowserVersion; 
import com.gargoylesoftware.htmlunit.WebClient; 
import com.gargoylesoftware.htmlunit.WebRequest; 
import com.gargoylesoftware.htmlunit.WebWindow; 
import com.gargoylesoftware.htmlunit.html.HtmlElement; 
import com.gargoylesoftware.htmlunit.html.HtmlPage; 

public class ScreenCaptureHtmlUnitDriver extends HtmlUnitDriver implements TakesScreenshot { 

private static Map<String, byte[]> imagesCache = Collections.synchronizedMap(new HashMap<String, byte[]>()); 

private static Map<String, String> cssjsCache = Collections.synchronizedMap(new HashMap<String, String>()); 

// http://stackoverflow.com/questions/4652777/java-regex-to-get-the-urls-from-css 
private final static Pattern cssUrlPattern = Pattern.compile("background(-image)?[\\s]*:[^url]*url[\\s]*\\([\\s]*([^\\)]*)[\\s]*\\)[\\s]*");// ?<url> 

public ScreenCaptureHtmlUnitDriver() { 
    super(); 
} 

public ScreenCaptureHtmlUnitDriver(boolean enableJavascript) { 
    super(enableJavascript); 
} 

public ScreenCaptureHtmlUnitDriver(Capabilities capabilities) { 
    super(capabilities); 
} 

public ScreenCaptureHtmlUnitDriver(BrowserVersion version) { 
    super(version); 
    DesiredCapabilities var = ((DesiredCapabilities) getCapabilities()); 
    var.setCapability(CapabilityType.TAKES_SCREENSHOT, true); 
} 

//@Override 
@SuppressWarnings("unchecked") 
public <X> X getScreenshotAs(OutputType<X> target) throws WebDriverException { 
    byte[] archive = new byte[0]; 
    try { 
     archive = downloadCssAndImages(getWebClient(), (HtmlPage) getCurrentWindow().getEnclosedPage()); 
    } catch (Exception e) { 
    } 
    if(target.equals(OutputType.BASE64)){ 
     return target.convertFromBase64Png(new Base64Encoder().encode(archive)); 
    } 
    if(target.equals(OutputType.BYTES)){ 
     return (X) archive; 
    } 
    return (X) archive; 
} 

// http://stackoverflow.com/questions/2244272/how-can-i-tell-htmlunits-webclient-to-download-images-and-css 
protected byte[] downloadCssAndImages(WebClient webClient, HtmlPage page) throws Exception { 
    WebWindow currentWindow = webClient.getCurrentWindow(); 
    Map<String, String> urlMapping = new HashMap<String, String>(); 
    Map<String, byte[]> files = new HashMap<String, byte[]>(); 
    WebWindow window = null; 
    try { 
     window = webClient.getWebWindowByName(page.getUrl().toString()+"_screenshot"); 
     webClient.getPage(window, new WebRequest(page.getUrl())); 
    } catch (Exception e) { 
     window = webClient.openWindow(page.getUrl(), page.getUrl().toString()+"_screenshot"); 
    } 

    String xPathExpression = "//*[name() = 'img' or name() = 'link' and (@type = 'text/css' or @type = 'image/x-icon') or @type = 'text/javascript']"; 
    List<?> resultList = page.getByXPath(xPathExpression); 

    Iterator<?> i = resultList.iterator(); 
    while (i.hasNext()) { 
     try { 
      HtmlElement el = (HtmlElement) i.next(); 
      String resourceSourcePath = el.getAttribute("src").equals("") ? el.getAttribute("href") : el 
        .getAttribute("src"); 
      if (resourceSourcePath == null || resourceSourcePath.equals("")) 
       continue; 
      URL resourceRemoteLink = page.getFullyQualifiedUrl(resourceSourcePath); 
      String resourceLocalPath = mapLocalUrl(page, resourceRemoteLink, resourceSourcePath, urlMapping); 
      urlMapping.put(resourceSourcePath, resourceLocalPath); 
      if (!resourceRemoteLink.toString().endsWith(".css")) { 
       byte[] image = downloadImage(webClient, window, resourceRemoteLink); 
       files.put(resourceLocalPath, image); 
      } else { 
       String css = downloadCss(webClient, window, resourceRemoteLink); 
       for (String cssImagePath : getLinksFromCss(css)) { 
        URL cssImagelink = page.getFullyQualifiedUrl(cssImagePath.replace("\"", "").replace("\'", "") 
          .replace(" ", "")); 
        String cssImageLocalPath = mapLocalUrl(page, cssImagelink, cssImagePath, urlMapping); 
        files.put(cssImageLocalPath, downloadImage(webClient, window, cssImagelink)); 
       } 
       files.put(resourceLocalPath, replaceRemoteUrlsWithLocal(css, urlMapping) 
         .replace("resources/", "./").getBytes()); 
      } 
     } catch (Exception e) { 
     } 
    } 
    String pagesrc = replaceRemoteUrlsWithLocal(page.getWebResponse().getContentAsString(), urlMapping); 
    files.put("page.html", pagesrc.getBytes()); 
    webClient.setCurrentWindow(currentWindow); 
    return createZip(files); 
} 

String downloadCss(WebClient webClient, WebWindow window, URL resourceUrl) throws Exception { 
    if (cssjsCache.get(resourceUrl.toString()) == null) { 
     cssjsCache.put(resourceUrl.toString(), webClient.getPage(window, new WebRequest(resourceUrl)) 
       .getWebResponse().getContentAsString()); 

    } 
    return cssjsCache.get(resourceUrl.toString()); 
} 

byte[] downloadImage(WebClient webClient, WebWindow window, URL resourceUrl) throws Exception { 
    if (imagesCache.get(resourceUrl.toString()) == null) { 
     imagesCache.put(
       resourceUrl.toString(), 
       IOUtils.toByteArray(webClient.getPage(window, new WebRequest(resourceUrl)).getWebResponse() 
         .getContentAsStream())); 
    } 
    return imagesCache.get(resourceUrl.toString()); 
} 

public static byte[] createZip(Map<String, byte[]> files) throws IOException  { 
    ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
    ZipOutputStream zipfile = new ZipOutputStream(bos); 
    Iterator<String> i = files.keySet().iterator(); 
    String fileName = null; 
    ZipEntry zipentry = null; 
    while (i.hasNext()) { 
     fileName = i.next(); 
     zipentry = new ZipEntry(fileName); 
     zipfile.putNextEntry(zipentry); 
     zipfile.write(files.get(fileName)); 
    } 
    zipfile.close(); 
    return bos.toByteArray(); 
} 

    List<String> getLinksFromCss(String css) { 
    List<String> result = new LinkedList<String>(); 
    Matcher m = cssUrlPattern.matcher(css); 
    while (m.find()) { // find next match 
     result.add(m.group(2)); 
    } 
    return result; 
} 

String replaceRemoteUrlsWithLocal(String source, Map<String, String> replacement) { 
    for (String object : replacement.keySet()) { 
     // background:url(http://org.com/images/image.gif) 
     source = source.replace(object, replacement.get(object)); 
    } 
    return source; 
} 

String mapLocalUrl(HtmlPage page, URL link, String path, Map<String, String> replacementToAdd) throws Exception { 
    String resultingFileName = "resources/" + FilenameUtils.getName(link.getFile()); 
    replacementToAdd.put(path, resultingFileName); 
    return resultingFileName; 
} 

} 

UPDATE

Code von Andrew zur Verfügung gestellt- aber ich wollte wissen, ob es einen Weg gibt, mit dem wir nur ausgewählte Ressourcen herunterladen können. Für zB this Website möchte ich nur Captcha Bild diese ID ist "// * [@ id = 'cimage']" herunterladen, da das Herunterladen aller Ressourcen eine lange Zeit dauern wird. Gibt es einen Weg, wie wir nur die spezifische Ressource herunterladen können? Weil mit dem vorhandenen Code unten alle Ressourcen heruntergeladen werden.

byte[] zipFileBytes = ((ScreenCaptureHtmlUnitDriver) driver).getScreenshotAs(OutputType.BYTES); 
FileUtils.writeByteArrayToFile(new File("D:\\TEMP.PNG"), zipFileBytes); 
+0

Können Sie die vollständige Ausnahme-Stack hinzufügen und die Art von "B" sagen? –

+0

Hallo Florent Ich habe den Code bearbeitet und try Catch mit printstacktrace hinzugefügt, aber ich bekomme immer noch "java.lang.ClassCastException: [B kann nicht in java.io.File \t bei Test.main umgewandelt werden (Test.java:19)" as stacktrace – Ajay

+0

Hi ist es notwendig, HtmlUnitDriver zu verwenden, wenn nicht plz gehen für Phantom js ist es besser in Bezug auf das Sprechen Screenshot –

Antwort

1

Der Fehler besagt, dass der Code eine byte[] zu einem File umwandeln will. Es ist leicht einzusehen, warum, wenn Sie nur die nicht verwendeten Pfade von getScreenshotAs Streifen aus:

public <X> X getScreenshotAs(OutputType<X> target) throws WebDriverException { 
    byte[] archive = new byte[0]; 
    try { 
     archive = downloadCssAndImages(getWebClient(), (HtmlPage) getCurrentWindow().getEnclosedPage()); 
    } catch (Exception e) { 
    } 
    return (X) archive; 
} 

Es gibt keine Möglichkeit, einen File aus, dass zu bekommen. OutputType.FILE wird nicht unterstützt, so dass Sie die Dateiausgabe selbst behandeln müssen. Zum Glück ist das einfach.

byte[] zipFileBytes = ((ScreenCaptureHtmlUnitDriver) driver).getScreenshotAs(OutputType.BYTES); 
FileUtils.writeByteArrayToFile(new File("D:\\TEMP.PNG"), zipFileBytes); 

Siehe FileUtils.writeByteArrayToFile() für mehr: Sie können Ihren Code ändern.

+1

Vielen Dank, Andrew, das funktioniert super :) Ich habe meine Frage etwas ausführlicher aufgenommen. Kannst du bitte einen Blick darauf werfen? Vielen Dank. – Ajay

-3

Check this out dies hilfreich sein für Sie

File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE); 
FileUtils.copyFile(scrFile, new File("C:/Users/home/Desktop/screenshot.png"));// copy it somewhere 
+2

Dies erklärt nicht die tatsächliche Fehlermeldung, missversteht die Frage und was OP versucht zu erreichen, und wird einen Fehler durch einen anderen ersetzen. –

+0

Dies ist die einfachste Möglichkeit, Screenshot von CURRENT Webseite – monil

+0

zu nehmen Das war nicht die Frage. OP möchte wissen, wie man vorbeikommt. * "ClassCastException: [B kann nicht in java.io.File" umgewandelt werden * in einer angepassten Version von HtmlUnitDriver, die normalerweise keine Screenshots erstellen kann. –