【问题标题】:Using Selenium WebDriver in library csproj with .NET Core在带有 .NET Core 的库 csproj 中使用 Selenium WebDriver
【发布时间】:2019-03-08 15:57:21
【问题描述】:

我正在尝试使用 Selenium 和 .NET Core 组合一个网络抓取应用程序,但我无法找到我的 WebDriver exes。

我有一个 .csproj 将运行该项目的 API,它调用(以及其他)另一个将处理 webscraping 的 .csproj。 所有都在一个 .sln 中,并且都在运行 .NET Core 2.1

在抓取项目中,我已经安装了 Selenium.WebDriverSelenium.WebDriver.ChromeDriver

我在 API 中创建了一个端点,它调用抓取项目,并运行一个尝试调用 new ChromeDriver() 的方法。它不起作用:(具体来说,我得到:

The chromedriver.exe file does not exist in the current directory or in a directory on the PATH environment variable. The driver can be downloaded at ... <url>

看起来相当清楚(尽管令人失望的是它没有告诉你“当前目录”是什么意思。我很快就会为此提交 PR)


通过观察重建期间的变化以及其他在线研究,我发现:
  • nuget 包中的所有dlls 和exes 都存储在全局Nuget 缓存中,而不是解决方案目录中的nuget packages 文件夹中。
  • chromedriver.exe 似乎已复制到 &lt;solutionFolder&gt;\&lt;ScrapingProjectFolder&gt;\bin\Debug\chromeDriver.exe
    • 我认为这就是ChromeDriver Nuget 包的作用;当然不是我自己配置​​的。
    • 从表面上看,ChromeDriver 软件包尝试“安装它以制作 new ChromeDriver() JustWork”是一件合理的事情。
  • 深入研究 WebDriver 代码库,发现它正在查看的“currentDirectory”是“WebDriver.dll 的位置”。
    • 就我而言,就是“&lt;globalNugetPackagesCache&gt;\selenium.webdriver\3.141.0\lib\netstandard2.0
    • 似乎我不应该尝试让chromedriver.exe 最终出现在此文件夹中 - 将其复制到不同包的全局缓存中似乎是错误的? (人们同意吗?)
  • This article 似乎得出了大致相同的结论,并表示解决方案是将驱动程序调用为:

    new ChromeDriver(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location))

    • 不幸的是,该路径将我带到&lt;solutionFolder&gt;\&lt;APIProjectFolder&gt;\bin\Debug\&lt;ScrapingProjectFolder&gt;.dll,因为 dll 被复制到 API 项目的文件夹中。

我想到了几个解决方案,但没有一个真正吸引人:

  • 我可以将Selenium.WebDriver.ChromeDriver 安装到API 项目中。
    • Eww...API 项目不知道 WebDriver 或 Selenium,现在 Scraping 项目没有驱动程序 exe。
  • 我可以手动将 exe 复制到正确的位置。
    • 感觉不太对劲,感觉很脆弱。我怀疑这会使部署变得痛苦。
  • 我可以手动将 ChromeDriver 构造函数指向一个硬编码路径,我只是碰巧知道它包含当前的exe
    • 看起来和上面类似;虽然没有那么糟糕。
  • ???有没有办法让一个项目的所有 DLL 等都被编译到一个公共文件夹中? ???

有没有一种很好的、​​非hacky的方法来解决这个问题。哪个会产生一个 JustWorks 的 git 存储库,并且将来部署到服务器上会相对轻松?

我上面描述的任何事情是错误的还是配置错误?

【问题讨论】:

  • 我认为一个简单的解决方案是使用 VS Add Item -> Existing Item 将 chromedriver.exe 添加到项目中。然后选择chromedriver.exe,将“Copy to Output Directory”改为“Copy always”
  • 你有没有想过将驱动程序的路径放在环境变量中,然后在项目中读取它?

标签: c# selenium selenium-webdriver asp.net-core-2.0


【解决方案1】:

据我了解,您有一个依赖于 Scraping 项目的 API 项目。

Scraping.csproj:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>  
    <LangVersion>7.2</LangVersion>
    <PublishChromeDriver>true</PublishChromeDriver>    
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Selenium.WebDriver" Version="3.141.0" />
    <PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="2.46.0" />
  </ItemGroup>
</Project>

API.csproj:

<Project Sdk="Microsoft.NET.Sdk">

  <ItemGroup>
    <ProjectReference Include="..\Scraping\Scraping.csproj" />
  </ItemGroup>

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <LangVersion>7.2</LangVersion>
  </PropertyGroup>

</Project>

诀窍是将&lt;PublishChromeDriver&gt;true&lt;/PublishChromeDriver&gt; 添加到传递项目中,使其在运行dotnet publish API.csproj 时发布chromedriver。ChromeDriver 包在NuGet 包中有自定义构建目标,因此它是自定义。 p>

您现在可以使用

new ChromeDriver(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));

dotnet run API.csproj

【讨论】:

  • 我不认为在这里发布 chrome 驱动程序有问题。
  • true 为我做了诀窍,将 chrome.exe 复制到引用程序集。谢谢。
  • 对于下一个人:请注意,PublishChromeDriver 可与 Selenium.WebDriver.ChromeDriver 一起使用,但不适用于 Selenium.Chrome.WebDriver ...
  • 其他驱动呢? csproj 会支持 IE、Edge 和 Firefox 吗?有人试过吗?
【解决方案2】:

如果我错了,请纠正我。您有某种引用 Selenium 的类库,并且您想使用 ChromeDriver.exe,但您收到一个错误,无法在以下位置找到它。这相当简单。 目前您正在引用类库,让我们说 Foo 到 API。您的 Assembly Location 将指向 API bin 位置,而 chromedriver.exe 位于 Class library bin 下。 如果是这种情况,您唯一需要做的就是将以下 chromedriver.exe 复制到最终的 bin 目录,即 API。

将以下 Post Build Event 添加到您的 API 项目以复制 chromedriver:

  <Target Name="PostBuild" AfterTargets="PostBuildEvent">
    <Exec Command="copy $(SolutionDir)\ClassLibrary\bin\Debug\netstandard2.0\chromedriver.exe $(TargetDir)" />
  </Target>

这会将您的 chromedriver.exe 复制到 API bin。稍后在初始化 ChromeDriver 使用时:

        var options = new ChromeOptions();
        var service = ChromeDriverService.CreateDefaultService(AppDomain.CurrentDomain.BaseDirectory);

        WebDriver = new ChromeDriver(service, options);

AppDomain.CurrentDomain.BaseDirectory 将指向您的 API bin 目录。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-25
    • 1970-01-01
    • 2016-12-05
    • 2020-12-21
    • 1970-01-01
    • 2020-04-03
    相关资源
    最近更新 更多