如何使用 Watir 和 geckodriver + Firefox 进行整页截图?
How to take full page screenshots with Watir and geckodriver + Firefox?
我将我的 Watir / Firefox 自动化堆栈升级到最新版本,并添加了 geckodriver。我很惊讶地发现现在屏幕截图默认只显示视口。
require 'watir'
require 'mini_magick'
b = Watir::Browser.new :firefox
b.goto "https://daringfireball.net"
base = b.screenshot.base64
blob = Base64.decode64(base)
image = MiniMagick::Image.read(blob)
image.height
=> 1760 # macOS 'Retina' resolution doubling
b.execute_script "return window.innerHeight"
=> 880 # 880 * 2 = 1760
b.execute_script "return document.documentElement.scrollHeight"
=> 34692
如何在不回滚我的环境的情况下使用 Watir 驱动 Firefox 截取整个页面的屏幕截图?
使用 Watir 的 .execute_script
,可以在移动滚动位置的同时重复截取视口的屏幕截图。然后可以使用 MiniMagick 将图像拼接在一起。
我开发了 the watir-screenshot-stitch gem 来封装我解决这个问题的最佳方法,尽管它带有警告,您可以在那里阅读。它也是内存密集型的,而且速度可能很慢。
这不是一个真正的整页截图解决方案,我很乐意接受任何对此进行改进的替代方法。
我用 C# 解决了这个问题。但我猜这个解决方案可以用任何语言重写。我使用了一个名为 HTML2Canvas 的 JavaScript 库来生成完整的页面截图。这是 C# 代码:
[Test]
public void TakingHTML2CanvasFullPageScreenshot()
{
using (var driver = new ChromeDriver())
{
driver.Manage().Timeouts().PageLoad = TimeSpan.FromSeconds(5);
driver.Navigate().GoToUrl(@"https://automatetheplanet.com");
IJavaScriptExecutor js = driver;
var html2canvasJs = File.ReadAllText($"{GetAssemblyDirectory()}html2canvas.js");
js.ExecuteScript(html2canvasJs);
string generateScreenshotJS = @"function genScreenshot () {
var canvasImgContentDecoded;
html2canvas(document.body, {
onrendered: function (canvas) {
window.canvasImgContentDecoded = canvas.toDataURL(""image/png"");
}});
}
genScreenshot();";
js.ExecuteScript(generateScreenshotJS);
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.IgnoreExceptionTypes(typeof(InvalidOperationException));
wait.Until(
wd =>
{
string response = (string)js.ExecuteScript
("return (typeof canvasImgContentDecoded === 'undefined' || canvasImgContentDecoded === null)");
if (string.IsNullOrEmpty(response))
{
return false;
}
return bool.Parse(response);
});
wait.Until(wd => !string.IsNullOrEmpty((string)js.ExecuteScript("return canvasImgContentDecoded;")));
var pngContent = (string)js.ExecuteScript("return canvasImgContentDecoded;");
pngContent = pngContent.Replace("data:image/png;base64,", string.Empty);
byte[] data = Convert.FromBase64String(pngContent);
var tempFilePath = Path.GetTempFileName().Replace(".tmp", ".png");
Image image;
using (var ms = new MemoryStream(data))
{
image = Image.FromStream(ms);
}
image.Save(tempFilePath, ImageFormat.Png);
}
}
您可以在 article.
中找到更多示例和解释
现在可以在 Firefox 中执行此操作,使用 geckodriver 功能。据我所知,这个特性没有融入 Selenium/可能不是 W3C 规范的一部分。
require 'watir'
browser = Watir::Browser.new :firefox
bridge = browser.driver.session_storage.instance_variable_get(:@bridge)
server_uri = bridge.instance_variable_get(:@http).instance_variable_get(:@server_url)
sid = bridge.instance_variable_get(:@session_id)
driver_path = "session/#{sid}/moz/screenshot/full"
request_url = server_uri.to_s + driver_path
url = URI.parse(request_url)
req = Net::HTTP::Get.new(request_url)
raw = Net::HTTP.start(url.host, url.port) {|http| http.request(req) }.body
base64_screenshot = JSON.parse(raw, symbolize_names: true)[:value]
这种方法现在也是 the watir-screenshot-stitch gem 中的一个选项:
require 'watir-screenshot-stitch'
b = Watir::Browser.new :firefox
b.goto "https://github.com/mozilla/geckodriver/issues/570"
base64_screenshot = b.base64_geckodriver
我将我的 Watir / Firefox 自动化堆栈升级到最新版本,并添加了 geckodriver。我很惊讶地发现现在屏幕截图默认只显示视口。
require 'watir'
require 'mini_magick'
b = Watir::Browser.new :firefox
b.goto "https://daringfireball.net"
base = b.screenshot.base64
blob = Base64.decode64(base)
image = MiniMagick::Image.read(blob)
image.height
=> 1760 # macOS 'Retina' resolution doubling
b.execute_script "return window.innerHeight"
=> 880 # 880 * 2 = 1760
b.execute_script "return document.documentElement.scrollHeight"
=> 34692
如何在不回滚我的环境的情况下使用 Watir 驱动 Firefox 截取整个页面的屏幕截图?
使用 Watir 的 .execute_script
,可以在移动滚动位置的同时重复截取视口的屏幕截图。然后可以使用 MiniMagick 将图像拼接在一起。
我开发了 the watir-screenshot-stitch gem 来封装我解决这个问题的最佳方法,尽管它带有警告,您可以在那里阅读。它也是内存密集型的,而且速度可能很慢。
这不是一个真正的整页截图解决方案,我很乐意接受任何对此进行改进的替代方法。
我用 C# 解决了这个问题。但我猜这个解决方案可以用任何语言重写。我使用了一个名为 HTML2Canvas 的 JavaScript 库来生成完整的页面截图。这是 C# 代码:
[Test]
public void TakingHTML2CanvasFullPageScreenshot()
{
using (var driver = new ChromeDriver())
{
driver.Manage().Timeouts().PageLoad = TimeSpan.FromSeconds(5);
driver.Navigate().GoToUrl(@"https://automatetheplanet.com");
IJavaScriptExecutor js = driver;
var html2canvasJs = File.ReadAllText($"{GetAssemblyDirectory()}html2canvas.js");
js.ExecuteScript(html2canvasJs);
string generateScreenshotJS = @"function genScreenshot () {
var canvasImgContentDecoded;
html2canvas(document.body, {
onrendered: function (canvas) {
window.canvasImgContentDecoded = canvas.toDataURL(""image/png"");
}});
}
genScreenshot();";
js.ExecuteScript(generateScreenshotJS);
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.IgnoreExceptionTypes(typeof(InvalidOperationException));
wait.Until(
wd =>
{
string response = (string)js.ExecuteScript
("return (typeof canvasImgContentDecoded === 'undefined' || canvasImgContentDecoded === null)");
if (string.IsNullOrEmpty(response))
{
return false;
}
return bool.Parse(response);
});
wait.Until(wd => !string.IsNullOrEmpty((string)js.ExecuteScript("return canvasImgContentDecoded;")));
var pngContent = (string)js.ExecuteScript("return canvasImgContentDecoded;");
pngContent = pngContent.Replace("data:image/png;base64,", string.Empty);
byte[] data = Convert.FromBase64String(pngContent);
var tempFilePath = Path.GetTempFileName().Replace(".tmp", ".png");
Image image;
using (var ms = new MemoryStream(data))
{
image = Image.FromStream(ms);
}
image.Save(tempFilePath, ImageFormat.Png);
}
}
您可以在 article.
中找到更多示例和解释现在可以在 Firefox 中执行此操作,使用 geckodriver 功能。据我所知,这个特性没有融入 Selenium/可能不是 W3C 规范的一部分。
require 'watir'
browser = Watir::Browser.new :firefox
bridge = browser.driver.session_storage.instance_variable_get(:@bridge)
server_uri = bridge.instance_variable_get(:@http).instance_variable_get(:@server_url)
sid = bridge.instance_variable_get(:@session_id)
driver_path = "session/#{sid}/moz/screenshot/full"
request_url = server_uri.to_s + driver_path
url = URI.parse(request_url)
req = Net::HTTP::Get.new(request_url)
raw = Net::HTTP.start(url.host, url.port) {|http| http.request(req) }.body
base64_screenshot = JSON.parse(raw, symbolize_names: true)[:value]
这种方法现在也是 the watir-screenshot-stitch gem 中的一个选项:
require 'watir-screenshot-stitch'
b = Watir::Browser.new :firefox
b.goto "https://github.com/mozilla/geckodriver/issues/570"
base64_screenshot = b.base64_geckodriver