翼度科技»论坛 编程开发 .net 查看内容

.Net6在Docker环境下操作Selenium.Chrome的那些坑

3

主题

3

帖子

9

积分

新手上路

Rank: 1

积分
9
.Net6中想实现对某个网址截屏,可通过Selenium模拟访问网址并实现截图。
实现
安装Nuget包
  1. [/code]之后可通过代码实现模拟访问网址并截图
  2. [code]public static string PageScreenshot(string url, string uploadbasepath)
  3. {
  4.     ChromeDriver driver = null;
  5.     try
  6.     {
  7.         ChromeOptions options = new ChromeOptions();
  8.         options.AddArguments("headless", "disable-gpu", "no-sandbox");
  9.         driver = new ChromeDriver(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), options);
  10.         //driver = new ChromeDriver("/usr/bin/google-chrome-stable", options);
  11.         driver.Navigate().GoToUrl(url);
  12.         string width = driver.ExecuteScript("return document.body.scrollWidth").ToString();
  13.         string height = driver.ExecuteScript("return document.body.scrollHeight").ToString();
  14.         driver.Manage().Window.Size = new System.Drawing.Size(int.Parse(width), int.Parse(height)); //=int.Parse( height);
  15.         var screenshot = (driver as ITakesScreenshot).GetScreenshot();
  16.         //directory create
  17.         var basepath = uploadbasepath + DateTime.Now.ToString("yyyyMMdd") + "/";
  18.         if (!Directory.Exists(uploadbasepath))
  19.         {
  20.             Directory.CreateDirectory(uploadbasepath);
  21.         }
  22.         if (!Directory.Exists(basepath))
  23.         {
  24.             Directory.CreateDirectory(basepath);
  25.         }
  26.         var path = basepath + Guid.NewGuid().ToString("N") + ".jpg";
  27.         screenshot.SaveAsFile(path);
  28.         return path;
  29.     }
  30.     catch (Exception ex)
  31.     {
  32.         throw;
  33.     }
  34.     finally
  35.     {
  36.         if (driver != null)
  37.         {
  38.             driver.Close();
  39.             driver.Quit();
  40.         }
  41.     }
  42. }
复制代码
 
需要另外做的一步是把chromedriver从bin/Release/netcoreapp3.1/chromedriver复制到publish目录。
你以为到这就完了?这个代码确实可以在windows/linux非容器环境下运行。但是在docker里还是有些不一样。
 
Docker中运行的那些坑
首先需要注意.netcore3.1在Docker中操作图片记得安装libgdiplus.so
  1. #Dockerfile
  2. 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异常,异常信息是
  1. 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中添加以下内容
  1. #dockerfile
  2. 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的命令
  1. #Dockerfile Install Chrome
  2. RUN apt-get update && apt-get install -y \
  3. apt-transport-https \
  4. ca-certificates \
  5. curl \
  6. gnupg \
  7. hicolor-icon-theme \
  8. libcanberra-gtk* \
  9. libgl1-mesa-dri \
  10. libgl1-mesa-glx \
  11. libpango1.0-0 \
  12. libpulse0 \
  13. libv4l-0 \
  14. fonts-symbola \
  15. --no-install-recommends \
  16. && curl -sSL https://dl.google.com/linux/linux_signing_key.pub | apt-key add - \
  17. && echo "deb [arch=amd64] https://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google.list \
  18. && apt-get update && apt-get install -y \
  19. google-chrome-stable \
  20. --no-install-recommends \
  21. && apt-get purge --auto-remove -y curl \
  22. && rm -rf /var/lib/apt/lists/*
复制代码
 
3.第三个坑
运行以上修改后的容器,又一个异常
  1. 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环境
  1. #Dockerfile
  2. ENV INDOCKER 1
复制代码
  1. public static string PageScreenshot(string url, string uploadbasepath)
  2. {
  3.     ChromeDriver driver = null;
  4.     try
  5.     {
  6.         var indocker = Environment.GetEnvironmentVariable("INDOCKER");
  7.         ChromeOptions options = new ChromeOptions();
  8.         if (indocker == "1")
  9.         {
  10.             options.AddArguments("headless", "disable-gpu", "no-sandbox", "disable-dev-shm-usage");
  11.             //driver = new ChromeDriver("/opt/google/chrome/chrome", options);
  12.         }
  13.         else
  14.         {
  15.             options.AddArguments("headless", "disable-gpu", "no-sandbox");
  16.         }
  17.         driver = new ChromeDriver(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), options);
  18.         //driver = new ChromeDriver("/usr/bin/google-chrome-stable", options);
  19.         driver.Navigate().GoToUrl(url);
  20.         string width = driver.ExecuteScript("return document.body.scrollWidth").ToString();
  21.         string height = driver.ExecuteScript("return document.body.scrollHeight").ToString();
  22.         driver.Manage().Window.Size = new System.Drawing.Size(int.Parse(width), int.Parse(height)); //=int.Parse( height);
  23.         var screenshot = (driver as ITakesScreenshot).GetScreenshot();
  24.         //directory create
  25.         var basepath = uploadbasepath + DateTime.Now.ToString("yyyyMMdd") + "/";
  26.         if (!Directory.Exists(uploadbasepath))
  27.         {
  28.             Directory.CreateDirectory(uploadbasepath);
  29.         }
  30.         if (!Directory.Exists(basepath))
  31.         {
  32.             Directory.CreateDirectory(basepath);
  33.         }
  34.         var path = basepath + Guid.NewGuid().ToString("N") + ".jpg";
  35.         screenshot.SaveAsFile(path);
  36.         return path;
  37.     }
  38.     catch (Exception ex)
  39.     {
  40.         throw;
  41.     }
  42.     finally
  43.     {
  44.         if (driver != null)
  45.         {
  46.             driver.Close();
  47.             driver.Quit();
  48.         }
  49.     }
  50. }
复制代码
 
4.第四个坑
尝试运行上面修改后的容器,又一个异常
  1. This version of ChromeDriver only supports Chrome version 99
  2. Current browser version is 109.0.5414.74 with binary path /usr/bin/google-chrome
复制代码
这个信息字面意思就是之前第一个坑复制的chromedriver版本较低。那就直接去官网下载最新的chromedriver,并放到镜像内
下载地址:http://chromedriver.storage.googleapis.com/index.html
  1. # Dockerfile
  2. COPY ["xxx/chromedriver", "."]
  3. RUN chmod +x chromedriver
复制代码
 
5.第五个坑
继续尝试运行,发现这次能成功截图了,等等...这字体咋还是乱码呢

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

 

来源:https://www.cnblogs.com/chenyishi/archive/2023/01/13/17044827.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具