Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SeleniumWebDriver #417

Merged
merged 8 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,16 @@ public class ElementActionArgs
private BroswerActionEnum _action;
public BroswerActionEnum Action => _action;

private string _content;
public string Content => _content;
private string? _content;
public string? Content => _content;

public ElementActionArgs(BroswerActionEnum action)
private ElementPosition? _position;
public ElementPosition? Position => _position;

public ElementActionArgs(BroswerActionEnum action, ElementPosition? position = null)
{
_action = action;
_position = position;
}

public ElementActionArgs(BroswerActionEnum action, string content)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace BotSharp.Abstraction.Browsing.Models;

public class ElementPosition
{
public float X { get; set; } = default!;

public float Y { get; set; } = default!;
}
4 changes: 2 additions & 2 deletions src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@
<ItemGroup>
<PackageReference Include="Aspects.Cache" Version="2.0.4" />
<PackageReference Include="Colorful.Console" Version="1.2.15" />
<PackageReference Include="EntityFrameworkCore.BootKit" Version="6.3.1" />
<PackageReference Include="Fluid.Core" Version="2.7.0" />
<PackageReference Include="EntityFrameworkCore.BootKit" Version="8.1.1"/>
<PackageReference Include="Fluid.Core" Version="2.8.0" />
<PackageReference Include="Nanoid" Version="3.0.0" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
Expand Down Expand Up @@ -33,7 +33,6 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Dapper" Version="2.1.28" />
<PackageReference Include="MySqlConnector" Version="2.3.5" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.Playwright" Version="1.41.2" />
<PackageReference Include="Selenium.WebDriver" Version="4.19.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ public async Task<IBrowserContext> InitContext(string id)
Channel = "chrome",
IgnoreDefaultArgs = new[]
{
"--disable-infobars"
},
"--disable-infobars"
},
Args = new[]
{
"--disable-infobars",
// "--start-maximized"
}
"--disable-infobars",
// "--start-maximized"
}
});

_contexts[id].Page += async (sender, e) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,21 @@ public async Task DoAction(MessageInfo message, ElementActionArgs action, Browse

if (action.Action == BroswerActionEnum.Click)
{
await locator.ClickAsync();
if (action.Position == null)
{
await locator.ClickAsync();
}
else
{
await locator.ClickAsync(new LocatorClickOptions
{
Position = new Position
{
X = action.Position.X,
Y = action.Position.Y
}
});
}
}
else if (action.Action == BroswerActionEnum.InputText)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,21 @@ public async Task<BrowserActionResult> LaunchBrowser(string contextId, string? u
}

var page = await _instance.NewPage(contextId);
if (!string.IsNullOrEmpty(url))

try
{
try
{
var response = await page.GotoAsync(url, new PageGotoOptions
{
Timeout = 15 * 1000
});
await page.WaitForLoadStateAsync(LoadState.DOMContentLoaded);
result.IsSuccess = response.Status == 200;
}
catch(Exception ex)
var response = await page.GotoAsync(url, new PageGotoOptions
{
result.Message = ex.Message;
result.StackTrace = ex.StackTrace;
_logger.LogError(ex.Message);
}
Timeout = 15 * 1000
});
await page.WaitForLoadStateAsync(LoadState.DOMContentLoaded);
result.IsSuccess = response.Status == 200;
}
catch (Exception ex)
{
result.Message = ex.Message;
result.StackTrace = ex.StackTrace;
_logger.LogError(ex.Message);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using OpenQA.Selenium.Chrome;
using System.IO;

namespace BotSharp.Plugin.WebDriver.Drivers.SeleniumDriver;

public class SeleniumInstance : IDisposable
{
Dictionary<string, IWebDriver> _contexts = new Dictionary<string, IWebDriver>();

public Dictionary<string, IWebDriver> Contexts => _contexts;

public INavigation GetPage(string id)
{
InitInstance(id).Wait();
return _contexts[id].Navigate();
}

public string GetPageContent(string id)
{
InitInstance(id).Wait();
return _contexts[id].PageSource;
}

public async Task<IWebDriver> InitInstance(string id)
{
return await InitContext(id);
}

public async Task<IWebDriver> InitContext(string id)
{
if (_contexts.ContainsKey(id))
return _contexts[id];

string tempFolderPath = $"{Path.GetTempPath()}\\_selenium\\{id}";

var options = new ChromeOptions();
options.AddArgument("disable-infobars");
options.AddArgument($"--user-data-dir={tempFolderPath}");
var selenium = new ChromeDriver(options);
selenium.Manage().Window.Maximize();
selenium.Navigate().GoToUrl("about:blank");
_contexts[id] = selenium;

return _contexts[id];
}

public async Task<INavigation> NewPage(string id)
{
await InitContext(id);
var selenium = _contexts[id];
selenium.Navigate().GoToUrl("about:blank");
return _contexts[id].Navigate();
}

public async Task Wait(string id)
{
if (_contexts.ContainsKey(id))
{
_contexts[id].Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
}
await Task.Delay(100);
}

public async Task Close(string id)
{
if (_contexts.ContainsKey(id))
{
_contexts[id].Quit();
_contexts.Remove(id);
}
}

public async Task CloseCurrentPage(string id)
{
if (_contexts.ContainsKey(id))
{
}
}

public void Dispose()
{
foreach(var context in _contexts)
{
context.Value.Quit();
}
_contexts.Clear();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using OpenQA.Selenium;
using OpenQA.Selenium.Interactions;

namespace BotSharp.Plugin.WebDriver.Drivers.SeleniumDriver;

public partial class SeleniumWebDriver
{
public async Task DoAction(MessageInfo message, ElementActionArgs action, BrowserActionResult result)
{
var driver = await _instance.InitInstance(message.ContextId);
IWebElement element = default;
if (result.Selector.StartsWith("//"))
{
element = driver.FindElement(By.XPath(result.Selector));
}
else
{
element = driver.FindElement(By.CssSelector(result.Selector));
}


if (action.Action == BroswerActionEnum.Click)
{
if (action.Position == null)
{
element.Click();
}
else
{
var size = element.Size;
var actions = new Actions(driver);
actions.MoveToElement(element)
.MoveByOffset((int)action.Position.X - size.Width / 2, (int)action.Position.Y - size.Height / 2)
.Click()
.Perform();
}
}
else if (action.Action == BroswerActionEnum.InputText)
{
element.SendKeys(action.Content);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace BotSharp.Plugin.WebDriver.Drivers.SeleniumDriver;

public partial class SeleniumWebDriver
{
public async Task<string> GetAttributeValue(MessageInfo message, ElementLocatingArgs location, BrowserActionResult result)
{
var driver = await _instance.InitInstance(message.ContextId);
var locator = driver.FindElement(By.CssSelector(result.Selector));
var value = string.Empty;

if (!string.IsNullOrEmpty(location?.AttributeName))
{
value = locator.GetAttribute(location.AttributeName);
}

return value ?? string.Empty;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace BotSharp.Plugin.WebDriver.Drivers.SeleniumDriver;

public partial class SeleniumWebDriver
{
public async Task<BrowserActionResult> GoToPage(string contextId, string url, bool openNewTab = false)
{
var result = new BrowserActionResult();
try
{
var page = openNewTab ? await _instance.NewPage(contextId) :
_instance.GetPage(contextId);
page.GoToUrl(url);
await _instance.Wait(contextId);

result.Body = _instance.GetPageContent(contextId);
result.IsSuccess = true;
}
catch (Exception ex)
{
result.Message = ex.Message;
result.StackTrace = ex.StackTrace;
_logger.LogError(ex.Message);
}

return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
namespace BotSharp.Plugin.WebDriver.Drivers.SeleniumDriver;

public partial class SeleniumWebDriver
{
public async Task<BrowserActionResult> LaunchBrowser(string contextId, string? url, bool openIfNotExist = true)
{
var result = new BrowserActionResult()
{
IsSuccess = true
};
var context = await _instance.InitInstance(contextId);

if (!string.IsNullOrEmpty(url))
{
// Check if the page is already open
var page = await _instance.NewPage(contextId);

try
{
page.GoToUrl(url);
result.IsSuccess = true;
}
catch (Exception ex)
{
result.Message = ex.Message;
result.StackTrace = ex.StackTrace;
_logger.LogError(ex.Message);
}
}

return result;
}
}
Loading