使用AShot+Selenium ChromeDriver截取长网页不全问题求助
解决AShot截取超长网页截图不完整的内存优化方案
看起来你遇到的超长网页截图截断问题,很大概率确实是内存限制导致的——AShot在拼接数十个视口截图时,会占用大量堆内存,一旦内存不足就会出现截图不完整甚至OOM错误。结合你的代码,我给你几个针对性的优化方案:
1. 先给Java进程加足内存
最简单的第一步,运行你的Java程序时,通过JVM启动参数增加堆内存分配,避免内存瓶颈:
java -Xmx2G -Xms1G ashot_CompletePage
-Xmx2G表示最大堆内存为2GB,-Xms1G表示初始堆内存为1GB,你可以根据页面长度调整这个数值(比如超长页面可以加到-Xmx4G)。
2. 优化ChromeDriver的启动参数
给Chrome加上几个内存优化和渲染稳定的参数,减少浏览器本身的内存占用,同时避免渲染异常:
ChromeOptions options = new ChromeOptions(); options.addArguments("start-maximized"); options.addArguments("disable-infobars"); options.addArguments("--disable-extensions"); // 新增优化参数 options.addArguments("--disable-gpu"); // 禁用GPU加速,减少内存占用 options.addArguments("--disable-dev-shm-usage"); // 避免/dev/shm内存限制(Windows下也兼容) options.addArguments("--no-sandbox"); // 关闭沙箱,减少内存开销 options.setPageLoadStrategy(PageLoadStrategy.EAGER); // 页面DOM加载完成就开始操作,不用等所有资源
注意:设置EAGER加载策略后,要确保你的WebDriverWait等待的是页面核心内容加载完成(比如你之前的titleContains("jQuery")就很合适)。
3. 调整AShot的截图策略
修改viewportPasting的参数,减少重叠区域裁剪,同时增加滚动后的等待时间,确保页面完全渲染:
// 第二个参数是裁剪掉的重叠像素,默认可能有冗余,设置为0减少内存消耗 // 同时把等待时间从100ms调整到200ms,确保长页面滚动后内容渲染完成 Screenshot myScreenshot = new AShot() .shootingStrategy(ShootingStrategies.viewportPasting(200, 0)) .takeScreenshot(driver);
如果还是有截断,可以尝试使用viewportPastingWithScroll策略,它会更智能地处理滚动和拼接:
Screenshot myScreenshot = new AShot() .shootingStrategy(ShootingStrategies.viewportPastingWithScroll(200, 100)) .takeScreenshot(driver);
4. 分块截取+手动拼接(内存友好终极方案)
如果上面的方法还是解决不了,那就换成分块截取的思路——每次只截取一个视口的内容,最后手动拼接成完整图片,这样内存压力会小很多:
import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.File; import java.util.ArrayList; import java.util.List; import javax.imageio.ImageIO; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import ru.yandex.qatools.ashot.AShot; import ru.yandex.qatools.ashot.Screenshot; public class ashot_CompletePage { public static void main(String[] args) throws Exception { System.setProperty("webdriver.chrome.driver", "C:\\Utility\\BrowserDrivers\\chromedriver.exe"); ChromeOptions options = new ChromeOptions(); options.addArguments("start-maximized"); options.addArguments("disable-infobars"); options.addArguments("--disable-extensions"); options.addArguments("--disable-gpu"); options.addArguments("--disable-dev-shm-usage"); options.addArguments("--no-sandbox"); WebDriver driver = new ChromeDriver(options); driver.get("https://www.smashingmagazine.com/2017/05/long-scrolling/"); new WebDriverWait(driver, 20).until(ExpectedConditions.titleContains("jQuery")); JavascriptExecutor js = (JavascriptExecutor) driver; // 获取页面总高度和视口高度 Long totalHeight = (Long) js.executeScript("return document.body.scrollHeight"); Long viewportHeight = (Long) js.executeScript("return window.innerHeight"); Long currentScroll = 0; List<BufferedImage> screenshotParts = new ArrayList<>(); // 分块截取每个视口 while (currentScroll < totalHeight) { // 滚动到当前位置 js.executeScript("window.scrollTo(0, " + currentScroll + ")"); // 等待页面渲染稳定 Thread.sleep(300); // 截取当前视口 Screenshot partShot = new AShot().takeScreenshot(driver); screenshotParts.add(partShot.getImage()); // 滚动到下一个视口(减去50像素避免内容截断) currentScroll += viewportHeight - 50; } // 拼接所有截图块 BufferedImage fullPageImage = new BufferedImage( screenshotParts.get(0).getWidth(), totalHeight.intValue(), BufferedImage.TYPE_INT_RGB ); Graphics2D g2d = fullPageImage.createGraphics(); int yPosition = 0; for (BufferedImage part : screenshotParts) { g2d.drawImage(part, 0, yPosition, null); yPosition += part.getHeight(); } g2d.dispose(); // 保存最终截图 ImageIO.write(fullPageImage, "PNG", new File("./Screenshots/fullPageScreenshot.png")); driver.quit(); } }
这个方法的核心是每次只处理一个视口的图片,不会一次性把所有拼接后的大图放在内存里,对超长页面特别友好。
5. 优化图片输出格式
如果输出PNG格式内存占用太高,可以改为JPEG格式并设置压缩质量,进一步减少内存消耗:
// 直接输出JPEG ImageIO.write(fullPageImage, "JPEG", new File("./Screenshots/fullPageScreenshot.jpg")); // 或者设置精细的压缩质量(0.8表示80%质量,平衡清晰度和大小) import com.sun.image.codec.jpeg.JPEGCodec; import com.sun.image.codec.jpeg.JPEGEncodeParam; import com.sun.image.codec.jpeg.JPEGImageEncoder; import java.io.FileOutputStream; JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(new FileOutputStream(new File("./Screenshots/fullPageScreenshot.jpg"))); JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(fullPageImage); param.setQuality(0.8f, true); encoder.encode(fullPageImage, param);
你可以从第一个方案开始尝试,逐步排查,应该能解决截图不完整的问题。
内容的提问来源于stack exchange,提问作者sankar
相关产品推荐
相关产品推荐

