根据@Michal Kalous 的回答,我创建了一个etension 课程。这也考虑了当前在寡妇中设置的字体大小和实际视口大小,并通过将 body.style.overflowY 设置为隐藏来移除垂直滚动条。
用法
RemoteWebDriver driver = new EdgeDriver();
driver.SetViewportSize(1200, 1200);
driver.Navigate().GoToUrl("https://www.bikereview.info/en/ktm-1290-super-duke-rr-innerhalb-von-48-minuten-ausverkauft.html");
Image tempImage = driver.TakeFullPageScreenshot();
tempImage.Save(@"c:\full.png", ImageFormat.Png);
driver.Close();
driver.Quit();
扩展类
using System;
using System.Drawing;
using System.IO;
using OpenQA.Selenium.Remote;
using System.Collections.ObjectModel;
using System.Runtime.InteropServices;
using OpenQA.Selenium;
namespace TestRenderHtmlToPng
{
public static class RemoteWebDriverExtensions
{
public static Image TakeFullPageScreenshot(this RemoteWebDriver driver, int maxHeight = 10000)
{
//Screenshots depend on fontscaleing-property in windows
double DpiScalingFactor = GetDpiScalingFactor();
Bitmap fullPageScreenshot = null;
using (var fullMs = new MemoryStream((driver.GetScreenshotOverflowHidden()).AsByteArray))
{
fullPageScreenshot = Image.FromStream(fullMs) as Bitmap;
}
var originalPageOffset = driver.GetPageOffset();
var prevPageOffset = 0;
var currentPageOffset = 0;
var scrollLength = driver.GetWindowInnerHeight();
while (fullPageScreenshot.Height < maxHeight)
{
prevPageOffset = driver.GetPageOffset().Y;
driver.ScrollPageBy(0, scrollLength);
System.Threading.Thread.Sleep(100);
currentPageOffset = driver.GetPageOffset().Y;
if (prevPageOffset == currentPageOffset)
{
break;
}
var pageMovedBy = currentPageOffset - prevPageOffset;
pageMovedBy = (int)(pageMovedBy * DpiScalingFactor);
using (var ms = new MemoryStream(driver.GetScreenshotOverflowHidden().AsByteArray))
{
Bitmap fullPageScreenshot1 = Image.FromStream(ms) as Bitmap;
using (var viewPortScreenshot = Image.FromStream(ms) as Bitmap)
{
var s = driver.Manage().Window.Size;
var croppedScreenshot = CropBitmapAtRect(viewPortScreenshot, new Rectangle(0, viewPortScreenshot.Height - pageMovedBy, viewPortScreenshot.Width, pageMovedBy));
var newFullPage = AppendBitmap(fullPageScreenshot, croppedScreenshot);
fullPageScreenshot.Dispose();
fullPageScreenshot = newFullPage;
}
}
}
driver.ScrollPageTo(originalPageOffset.X, originalPageOffset.Y);
return fullPageScreenshot;
}
private static Bitmap CropBitmapAtRect(Bitmap b, Rectangle r)
{
Bitmap nb = new Bitmap(r.Width, r.Height);
using (Graphics g = Graphics.FromImage(nb))
{
g.DrawImage(b, -r.X, -r.Y);
return nb;
}
}
private static Bitmap AppendBitmap(Bitmap source, Bitmap target, int spacing = 0)
{
int w = Math.Max(source.Width, target.Width);
int h = source.Height + target.Height + spacing;
Bitmap bmp = new Bitmap(w, h);
using (Graphics g = Graphics.FromImage(bmp))
{
g.DrawImage(source, 0, 0);
g.DrawImage(target, 0, source.Height + spacing);
}
return bmp;
}
private static Screenshot GetScreenshotOverflowHidden(this RemoteWebDriver driver)
{
driver.ExecuteScript(@" document.body.style.overflowY = ""hidden"";");
var s = driver.GetScreenshot();
driver.ExecuteScript(@" document.body.style.overflowY = """";");
return s;
}
private static void ScrollPageBy(this RemoteWebDriver driver, int x = 0, int y = 0)
{
driver.ExecuteScript(@"window.scroll(window.pageXOffset + arguments[0], window.pageYOffset + arguments[1]);", x, y);
}
private static void ScrollPageTo(this RemoteWebDriver driver, int x = 0, int y = 0)
{
driver.ExecuteScript(@"window.scroll(arguments[0], arguments[1]);", x, y);
}
public static void SetViewportSize(this RemoteWebDriver driver, int width, int height)
{
var jsGetPadding = @"return [ window.outerWidth - window.innerWidth,window.outerHeight - window.innerHeight ];";
var paddingArray = driver.ExecuteScript(jsGetPadding) as ReadOnlyCollection<object>;
driver.Manage().Window.Size = new Size(width + int.Parse(paddingArray[0].ToString()), height + int.Parse(paddingArray[1].ToString()));
}
private static Point GetPageOffset(this RemoteWebDriver driver)
{
var offsetArray = driver.ExecuteScript(@"return [window.pageXOffset, window.pageYOffset];") as ReadOnlyCollection<object>;
var x = int.Parse(offsetArray[0].ToString());
var y = int.Parse(offsetArray[1].ToString().Split(',')[0]);
return new Point((int)x, (int)y);
}
private static int GetWindowInnerHeight(this RemoteWebDriver driver)
{
var Value = driver.ExecuteScript(@"return [window.innerHeight];") as ReadOnlyCollection<object>;
return int.Parse(Value[0].ToString());
}
[DllImport("gdi32.dll")]
private static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
public enum DeviceCap
{
VERTRES = 10,
DESKTOPVERTRES = 117,
// http://pinvoke.net/default.aspx/gdi32/GetDeviceCaps.html
// https://stackoverflow.com/questions/5977445/how-to-get-windows-display-settings#answer-21450169
}
private static float GetDpiScalingFactor()
{
Graphics g = Graphics.FromHwnd(IntPtr.Zero);
IntPtr desktop = g.GetHdc();
int LogicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.VERTRES);
int PhysicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.DESKTOPVERTRES);
float ScreenScalingFactor = (float)PhysicalScreenHeight / (float)LogicalScreenHeight;
return ScreenScalingFactor; // 1.25 = 125%
}
}
}