CefSharp网页元素点击
CefSharp webpage element click
我正在尝试对某些页面元素(如 btn 或 link)进行简单的点击。
我已经编写了 2 个通过 xpath 和 CSS 选择器点击的函数。
这两个功能在浏览器的开发人员控制台中都能完美运行,但部分在 CEF 中不起作用。
- 代码在开发者控制台和 Cef
中的简单 link 秒中完美点击
- 代码可以完美地点击开发人员控制台中的确切按钮,但不会从 CEF 中点击。它只是出于某种原因忽略它...
怎么会这样? js代码完全一样!...
public void Click(string xpath)
{
var js = "document.evaluate(\"" + xpath + "\", document, null, XPathResult.ANY_TYPE, null).iterateNext().click();";
EvaluateJavascript(js);
}
public void ClickCss(string css)
{
var js = "document.querySelector('"+ css + "').click()";
EvaluateJavascript(js);
}
public async Task EvaluateJavascript(string script)
{
JavascriptResponse javascriptResponse = await Browser.GetMainFrame().EvaluateScriptAsync(script);
if (!javascriptResponse.Success)
{
throw new JavascriptException(javascriptResponse.Message);
}
}
详情:
使用的点击代码:
_browser.ClickCss("#upload-container a");
再来一次:相同的 js 代码在浏览器开发控制台中完美运行,但由于某种原因在 CEF 中不起作用。
顺便说一句,我在Chrome中测试了JS代码。所以WebEngine在这两种情况下都是一样的。
PS:我也可以模拟将某些特定文件拖放到某些特定网络元素。但是我没有找到任何关于这个不是Cef的信息,不是Js的,不是JQuery... =(
问题在于 JS 代码的安全限制。
问题的解决方法是:
- 用JS代码获取button/link的坐标
用CEF模拟点击动作:
public void MouseClick(int x, int y)
{
Browser.GetBrowser().GetHost().SendMouseClickEvent(x, y, MouseButtonType.Left, false, 1, CefEventFlags.None);
Thread.Sleep(15);
Browser.GetBrowser().GetHost().SendMouseClickEvent(x, y, MouseButtonType.Left, true, 1, CefEventFlags.None);
}
上面的答案没问题。我只是想补充一些我认为很重要的信息...
获取 DOM 元素的位置,并模拟鼠标点击(和移动):
// get button's position
string jsonString = null;
var jsReponse = await chromiumWebBrowser1.EvaluateScriptAsync(
@"(function () {
var bnt = document.getElementById('pnnext');
bnt.focus();
var bntRect = bnt.getBoundingClientRect();
return JSON.stringify({ x: bntRect.left, y: bntRect.top });
})();"
);
if (jsReponse.Success && jsReponse.Result != null)
jsonString = (string)jsReponse.Result;
// send mouse click event
if (jsonString != null)
{
var jsonObject = JObject.Parse(jsonString);
var xPosition = (int)jsonObject["x"] + 1; // add +1 pixel to the click position
var yPosition = (int)jsonObject["y"] + 1; // add +1 pixel to the click position
var host = chromiumWebBrowser1.GetBrowser().GetHost();
host.SendMouseMoveEvent(xPosition, yPosition, false, CefEventFlags.None);
Thread.Sleep(50);
host.SendMouseClickEvent(xPosition, yPosition, MouseButtonType.Left, false, 1, CefEventFlags.None);
Thread.Sleep(50);
host.SendMouseClickEvent(xPosition, yPosition, MouseButtonType.Left, true, 1, CefEventFlags.None);
}
1 - 到目前为止,获取 DOM 元素在 CefSharp 上的位置的最佳方法是 执行自定义 JavaScript,并将结果解析回来。这就是上面代码第一段的目的。它通过其 ID(在加载网页的 HTML 结构中定义)获取元素,然后获取其相对于视口的位置,然后 returns 将其返回到 C# 代码。
回到 C#,我们使用 Newtonsoft 的 JObject.Parse
方法解析它。
2 - 点击发生在指定的 x
和 y
坐标处,但了解此坐标是相对于浏览器组件 window(视口)非常重要。因此,如果您的 Web 浏览器组件只有 100px
高,并且您将点击命令发送到 y
坐标 150px
,则点击将发生 但在 Web 浏览器之外 ,因此,不在网页中。
3 - 查看点击是否真的在执行以及准确执行的地方的一个技巧是将其从 MouseButtonType.Left
更改为 MouseButtonType.Right
。搞定了,如果网页没有限制,就可以看到“鼠标右键菜单”了。如果您在外部单击,您可能会在 OS (Windows 此处看到“鼠标右键菜单”,我能够看到我正在单击在我的组件之外使用这个技巧) .
4 - 有时(特别是在反爬虫环境中)还需要模仿鼠标移动。我使用第一行所示的方法 SendMouseMoveEvent
来完成。
5 - 如果您的组件中加载了一个非常高的页面,并且您需要单击真正位于组件边界之外的按钮,则需要滚动网页。您可以像上面的示例代码那样执行一些 JavaScript,或者您可以使用下面的代码来执行:
模拟鼠标滚动(鼠标滚轮事件):
// send scroll command
// (mouse position X, mouse position Y, how much to scroll X, how much to scroll Y, events)
chromiumWebBrowser1.GetBrowser().GetHost().SendMouseWheelEvent(10, 10, 0, -100, CefEventFlags.None);
Thread.Sleep(300);
参数的最大部分是不言自明的,但这里最重要的部分是第3个和第4个参数,分别是“X滚动多少”和“Y滚动多少”。要向下滚动,只需使用负值,向上滚动,使用正值。在上面的代码中,它在水平方向(x
轴)和垂直方向(y
轴)向下滚动 100 像素(零像素)。
您可以在 loop
中使用此代码来滚动您需要的数量。我将它与 JavaScript 代码结合使用来检索按钮的位置,检测它是否在视口上,或者我是否需要再次发送滚动事件。
我正在尝试对某些页面元素(如 btn 或 link)进行简单的点击。
我已经编写了 2 个通过 xpath 和 CSS 选择器点击的函数。
这两个功能在浏览器的开发人员控制台中都能完美运行,但部分在 CEF 中不起作用。
- 代码在开发者控制台和 Cef 中的简单 link 秒中完美点击
- 代码可以完美地点击开发人员控制台中的确切按钮,但不会从 CEF 中点击。它只是出于某种原因忽略它...
怎么会这样? js代码完全一样!...
public void Click(string xpath)
{
var js = "document.evaluate(\"" + xpath + "\", document, null, XPathResult.ANY_TYPE, null).iterateNext().click();";
EvaluateJavascript(js);
}
public void ClickCss(string css)
{
var js = "document.querySelector('"+ css + "').click()";
EvaluateJavascript(js);
}
public async Task EvaluateJavascript(string script)
{
JavascriptResponse javascriptResponse = await Browser.GetMainFrame().EvaluateScriptAsync(script);
if (!javascriptResponse.Success)
{
throw new JavascriptException(javascriptResponse.Message);
}
}
详情:
使用的点击代码:
_browser.ClickCss("#upload-container a");
再来一次:相同的 js 代码在浏览器开发控制台中完美运行,但由于某种原因在 CEF 中不起作用。
顺便说一句,我在Chrome中测试了JS代码。所以WebEngine在这两种情况下都是一样的。
PS:我也可以模拟将某些特定文件拖放到某些特定网络元素。但是我没有找到任何关于这个不是Cef的信息,不是Js的,不是JQuery... =(
问题在于 JS 代码的安全限制。
问题的解决方法是:
- 用JS代码获取button/link的坐标
用CEF模拟点击动作:
public void MouseClick(int x, int y) { Browser.GetBrowser().GetHost().SendMouseClickEvent(x, y, MouseButtonType.Left, false, 1, CefEventFlags.None); Thread.Sleep(15); Browser.GetBrowser().GetHost().SendMouseClickEvent(x, y, MouseButtonType.Left, true, 1, CefEventFlags.None); }
上面的答案没问题。我只是想补充一些我认为很重要的信息...
获取 DOM 元素的位置,并模拟鼠标点击(和移动):
// get button's position
string jsonString = null;
var jsReponse = await chromiumWebBrowser1.EvaluateScriptAsync(
@"(function () {
var bnt = document.getElementById('pnnext');
bnt.focus();
var bntRect = bnt.getBoundingClientRect();
return JSON.stringify({ x: bntRect.left, y: bntRect.top });
})();"
);
if (jsReponse.Success && jsReponse.Result != null)
jsonString = (string)jsReponse.Result;
// send mouse click event
if (jsonString != null)
{
var jsonObject = JObject.Parse(jsonString);
var xPosition = (int)jsonObject["x"] + 1; // add +1 pixel to the click position
var yPosition = (int)jsonObject["y"] + 1; // add +1 pixel to the click position
var host = chromiumWebBrowser1.GetBrowser().GetHost();
host.SendMouseMoveEvent(xPosition, yPosition, false, CefEventFlags.None);
Thread.Sleep(50);
host.SendMouseClickEvent(xPosition, yPosition, MouseButtonType.Left, false, 1, CefEventFlags.None);
Thread.Sleep(50);
host.SendMouseClickEvent(xPosition, yPosition, MouseButtonType.Left, true, 1, CefEventFlags.None);
}
1 - 到目前为止,获取 DOM 元素在 CefSharp 上的位置的最佳方法是 执行自定义 JavaScript,并将结果解析回来。这就是上面代码第一段的目的。它通过其 ID(在加载网页的 HTML 结构中定义)获取元素,然后获取其相对于视口的位置,然后 returns 将其返回到 C# 代码。
回到 C#,我们使用 Newtonsoft 的 JObject.Parse
方法解析它。
2 - 点击发生在指定的 x
和 y
坐标处,但了解此坐标是相对于浏览器组件 window(视口)非常重要。因此,如果您的 Web 浏览器组件只有 100px
高,并且您将点击命令发送到 y
坐标 150px
,则点击将发生 但在 Web 浏览器之外 ,因此,不在网页中。
3 - 查看点击是否真的在执行以及准确执行的地方的一个技巧是将其从 MouseButtonType.Left
更改为 MouseButtonType.Right
。搞定了,如果网页没有限制,就可以看到“鼠标右键菜单”了。如果您在外部单击,您可能会在 OS (Windows 此处看到“鼠标右键菜单”,我能够看到我正在单击在我的组件之外使用这个技巧) .
4 - 有时(特别是在反爬虫环境中)还需要模仿鼠标移动。我使用第一行所示的方法 SendMouseMoveEvent
来完成。
5 - 如果您的组件中加载了一个非常高的页面,并且您需要单击真正位于组件边界之外的按钮,则需要滚动网页。您可以像上面的示例代码那样执行一些 JavaScript,或者您可以使用下面的代码来执行:
模拟鼠标滚动(鼠标滚轮事件):
// send scroll command
// (mouse position X, mouse position Y, how much to scroll X, how much to scroll Y, events)
chromiumWebBrowser1.GetBrowser().GetHost().SendMouseWheelEvent(10, 10, 0, -100, CefEventFlags.None);
Thread.Sleep(300);
参数的最大部分是不言自明的,但这里最重要的部分是第3个和第4个参数,分别是“X滚动多少”和“Y滚动多少”。要向下滚动,只需使用负值,向上滚动,使用正值。在上面的代码中,它在水平方向(x
轴)和垂直方向(y
轴)向下滚动 100 像素(零像素)。
您可以在 loop
中使用此代码来滚动您需要的数量。我将它与 JavaScript 代码结合使用来检索按钮的位置,检测它是否在视口上,或者我是否需要再次发送滚动事件。