.Net6中想实现对某个网址截屏,可通过Selenium模拟访问网址并实现截图。
实现
安装Nuget包
<PackageReference Include="Selenium.Chrome.WebDriver" Version="85.0.0" />
<PackageReference Include="Selenium.Support" Version="4.1.0" />
<PackageReference Include="Selenium.WebDriver" Version="4.1.0" />
之后可通过代码实现模拟访问网址并截图
public static string PageScreenshot(string url, string uploadbasepath)
{
ChromeDriver driver = null;
try
{
ChromeOptions options = new ChromeOptions();
options.AddArguments("headless", "disable-gpu", "no-sandbox");
driver = new ChromeDriver(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), options);
//driver = new ChromeDriver("/usr/bin/google-chrome-stable", options);
driver.Navigate().GoToUrl(url);
string width = driver.ExecuteScript("return document.body.scrollWidth").ToString();
string height = driver.ExecuteScript("return document.body.scrollHeight").ToString();
driver.Manage().Window.Size = new System.Drawing.Size(int.Parse(width), int.Parse(height)); //=int.Parse( height);
var screenshot = (driver as ITakesScreenshot).GetScreenshot();
//directory create
var basepath = uploadbasepath + DateTime.Now.ToString("yyyyMMdd") + "/";
if (!Directory.Exists(uploadbasepath))
{
Directory.CreateDirectory(uploadbasepath);
}
if (!Directory.Exists(basepath))
{
Directory.CreateDirectory(basepath);
}
var path = basepath + Guid.NewGuid().ToString("N") + ".jpg";
screenshot.SaveAsFile(path);
return path;
}
catch (Exception ex)
{
throw;
}
finally
{
if (driver != null)
{
driver.Close();
driver.Quit();
}
}
}
需要另外做的一步是把chromedriver从bin/Release/netcoreapp3.1/chromedriver复制到publish目录。
你以为到这就完了?这个代码确实可以在windows/linux非容器环境下运行。但是在docker里还是有些不一样。
Docker中运行的那些坑
首先需要注意.netcore3.1在Docker中操作图片记得安装libgdiplus.so
#Dockerfile
RUN apt-get update -y && apt-get install -y --allow-unauthenticated libgdiplus && apt-get clean && ln -s /usr/lib/libgdiplus.so /usr/lib/gdiplus.dll
1.第一个坑
首先遇到的就是OpenQA.Selenium.DriverServiceNotFoundException异常,异常信息是
OpenQA.Selenium.DriverServiceNotFoundException: The file /opt/google/chrome/chrome/chromedriver does not exist. The driver can be downloaded at http://chromedriver.storage.googleapis.com/index.html
这个异常明显是找不到chromedriver,那就与在非Docker环境linux中直接运行的方式一样,尝试把chromedriver复制到Docker的publish目录中,在Dockerfile中添加以下内容
#dockerfile
RUN cp /src/xxx/Release/netcoreapp3.1/chromedriver /app/publish/
2.第二个坑
尝试运行以上容器,还是失败,进入容器内部,直接运行chromedriver,可以看到缺少libxx.so之类的库。那咋办,只能尝试在镜像中安装chrome,这样相关库就有了
安装chrome相关资料
https://stackoverflow.com/questions/55206172/how-to-run-dotnet-core-app-with-selenium-in-docker
https://github.com/devpabloassis/seleniumdotnetcore/blob/master/Dockerfile
那在Dockerfile中添加安装chrome的命令
#Dockerfile Install Chrome
RUN apt-get update && apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg \
hicolor-icon-theme \
libcanberra-gtk* \
libgl1-mesa-dri \
libgl1-mesa-glx \
libpango1.0-0 \
libpulse0 \
libv4l-0 \
fonts-symbola \
--no-install-recommends \
&& curl -sSL https://dl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& echo "deb [arch=amd64] https://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google.list \
&& apt-get update && apt-get install -y \
google-chrome-stable \
--no-install-recommends \
&& apt-get purge --auto-remove -y curl \
&& rm -rf /var/lib/apt/lists/*
3.第三个坑
运行以上修改后的容器,又一个异常
DevToolsActivePort file doesn't exist
继续查资料发现需要加个参数disable-dev-shm-usage
https://stackoverflow.com/questions/50642308/webdriverexception-unknown-error-devtoolsactiveport-file-doesnt-exist-while-t
但是前面试了不在docker内运行,需要这个参数,那就加个环境变量区分开docker与非docker环境
#Dockerfile
ENV INDOCKER 1
public static string PageScreenshot(string url, string uploadbasepath)
{
ChromeDriver driver = null;
try
{
var indocker = Environment.GetEnvironmentVariable("INDOCKER");
ChromeOptions options = new ChromeOptions();
if (indocker == "1")
{
options.AddArguments("headless", "disable-gpu", "no-sandbox", "disable-dev-shm-usage");
//driver = new ChromeDriver("/opt/google/chrome/chrome", options);
}
else
{
options.AddArguments("headless", "disable-gpu", "no-sandbox");
}
driver = new ChromeDriver(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), options);
//driver = new ChromeDriver("/usr/bin/google-chrome-stable", options);
driver.Navigate().GoToUrl(url);
string width = driver.ExecuteScript("return document.body.scrollWidth").ToString();
string height = driver.ExecuteScript("return document.body.scrollHeight").ToString();
driver.Manage().Window.Size = new System.Drawing.Size(int.Parse(width), int.Parse(height)); //=int.Parse( height);
var screenshot = (driver as ITakesScreenshot).GetScreenshot();
//directory create
var basepath = uploadbasepath + DateTime.Now.ToString("yyyyMMdd") + "/";
if (!Directory.Exists(uploadbasepath))
{
Directory.CreateDirectory(uploadbasepath);
}
if (!Directory.Exists(basepath))
{
Directory.CreateDirectory(basepath);
}
var path = basepath + Guid.NewGuid().ToString("N") + ".jpg";
screenshot.SaveAsFile(path);
return path;
}
catch (Exception ex)
{
throw;
}
finally
{
if (driver != null)
{
driver.Close();
driver.Quit();
}
}
}
4.第四个坑
尝试运行上面修改后的容器,又一个异常
This version of ChromeDriver only supports Chrome version 99
Current browser version is 109.0.5414.74 with binary path /usr/bin/google-chrome
这个信息字面意思就是之前第一个坑复制的chromedriver版本较低。那就直接去官网下载最新的chromedriver,并放到镜像内
下载地址:http://chromedriver.storage.googleapis.com/index.html
# Dockerfile
COPY ["xxx/chromedriver", "."]
RUN chmod +x chromedriver
5.第五个坑
继续尝试运行,发现这次能成功截图了,等等...这字体咋还是乱码呢

明显是中文乱码了,应该是容器内没中文字体,那就安装中文字体,字体可以从C:\Windows\Fonts中获取ttc,ttf字体文件
#Dockerfile
RUN apt-get update
RUN apt-get install -y --no-install-recommends libgdiplus libc6-dev
RUN apt-get install -y fontconfig xfonts-utils
COPY fonts/ /usr/share/fonts/
RUN mkfontscale
RUN mkfontdir
RUN fc-cache -fv
再次运行,终于成功

作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou
我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain
我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur
之前在培训新生的时候,windows环境下配置opencv环境一直教的都是网上主流的vsstudio配置属性表,但是这个似乎对新生来说难度略高(虽然个人觉得完全是他们自己的问题),加之暑假之后对cmake实在是爱不释手,且这样配置确实十分简单(其实都不需要配置),故斗胆妄言vscode下配置CV之法。其实极为简单,图比较多所以很长。如果你看此文还配不好,你应该思考一下是不是自己的问题。闲话少说,直接开始。0.CMkae简介有的人到大二了都不知道cmake是什么,我不说是谁。CMake是一个开源免费并且跨平台的构建工具,可以用简单的语句来描述所有平台的编译过程。它能够根据当前所在平台输出对应的m
1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里
本文主要介绍在使用Selenium进行自动化测试或者任务时,对于使用了iframe的页面,如何定位iframe中的元素文章目录场景描述解决方案具体代码场景描述当我们在使用Selenium进行自动化测试的时候,可能会遇到一些界面或者窗体是使用HTML的iframe标签进行承载的。对于iframe中的标签,如果直接查找是无法找到的,会抛出没有找到元素的异常。比如近在咫尺的例子就是,CSDN的登录窗体就是使用的iframe,大家可以尝试通过F12开发者模式查看到的tag_name,class_name,id或者xpath来定位中的页面元素,会抛出NoSuchElementException异常。解决
我试图在rails中了解rubygems是如何变得可以自动使用的,而不是在使用required的文件中gem? 最佳答案 这是通过bundler/setup完成的:http://bundler.io/v1.3/bundler_setup.html.它在您的config/boot.rb文件中是必需的。简而言之,它首先将环境变量设置为指向您的Gemfile:ENV['BUNDLE_GEMFILE']||=File.expand_path('../../Gemfile',__FILE__)然后它通过要求bundler/setup将所有ge
我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption
我很好奇.NET将如何影响Python和Ruby应用程序。用IronPython/IronRuby编写的应用程序是否会非常特定于.NET环境,以至于它们实际上将变得特定于平台?如果他们不使用任何.NET功能,那么IronPython/IronRuby相对于非.NET同类产品的优势是什么? 最佳答案 我不能说任何关于IronRuby的东西,但是大多数Python实现(如IronPython、Jython和PyPy)都试图尽可能忠实于CPython实现。不过,IronPython正在迅速成为这方面的佼佼者之一,并且在PlanetPyth