I'm trying to put together a web-scraping app, using Selenium and .NET Core, but I'm having trouble getting my WebDriver exes to be found.
I have one .csproj that will run the API for the project, which calls out to (amongst others) another .csproj that will handle the webscraping. All are in a single .sln, and all are running .NET Core 2.1
In the scraping proj, I've nuget-installed Selenium.WebDriver and Selenium.WebDriver.ChromeDriver.
I've created an endpoint in the API, which calls out to the scraping project, and runs a method that attempts to invoke new ChromeDriver(). It doesn't work :( Specifically, I get:
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>
Seems fairly clear (although it dissappointingly doesn't tell you what "current directory" means. I'll be submitting a PR for that imminently)
By observing changes during a rebuild, and other research online, I see that:
- All the
dlls andexes from the nuget packages are stored in the Global Nuget cache, rather than a nugetpackagesfolder in the solution directory.- This appears to be expected behaviour: "Bug" raised in dotnet Std; MSDN migration docs.
- The
chromedriver.exeappears to get copied to<solutionFolder>\<ScrapingProjectFolder>\bin\Debug\chromeDriver.exe.- I assume that this is what the
ChromeDriverNuget package does; certainly I haven't configured it myself. - This superficially feels like a reasonable thing for that ChromeDriver package to be doing as an attempt at "install this to make
new ChromeDriver()JustWork."
- I assume that this is what the
- Digging into the WebDriver codebase, reveals that the "currentDirectory" that it's looking at is "the location of
WebDriver.dll".- In my case, that's "
<globalNugetPackagesCache>\selenium.webdriver\3.141.0\lib\netstandard2.0" - It doesn't seem like I should be trying to get the
chromedriver.exeto end up in this folder - copying it into a different package's global cache seems wrong? (Do people agree?)
- In my case, that's "
This article seems to have reached broadly the same conclusion and says that the solution is to invoke the driver as:
new ChromeDriver(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location))- Unfortunately, that path takes me to
<solutionFolder>\<APIProjectFolder>\bin\Debug\<ScrapingProjectFolder>.dll, because the dll gets copied over the the API project's folder.
- Unfortunately, that path takes me to
A couple of solutions occur to me, none of which really appeal:
- I could install
Selenium.WebDriver.ChromeDriverinto the API project.- Eww... the API project doesn't know about WebDriver or Selenium, and now the Scraping project doesn't have the driver exe.
- I could manually explictly copy the exe into the right place.
- Doesn't really feel right, and feels fragile. I suspect this will make deployment painful.
- I could manually point the ChromeDriver constructor to a hard-coded path, that I just happen to know contains the current
exe.- Seems similar to the above; though not quite as bad.
- ??? Is there some way to make all the DLLs etc. of a project get compiled into a single common folder? ???
Is there a good, non-hacky way to solve this problem. Which will result in a git repo that JustWorks, and is going to be relatively painless to deploy to a server in the future?
Are any of the things I've described above wrong, or mis-configured?