Necesito realizar mediante programación 3 acciones en el sitio web
(después de eso, se produce una solicitud y la página me devuelve el resultado de la búsqueda)
si pongo la acción 1 y 2 en el botón 1:
private void Button1_Click(object sender, EventArgs e) { string jsScript1 = "document.getElementById('story').value=" + '\'' + textFind.Text + '\'' + ";" + "document.querySelector('body > div.wrapper > div.header > div.header44 > div.search_panel > span > form > button').click();"; var task1 = chrome.EvaluateScriptAsync(jsScript1); task1.Wait(); }Y la acción 3 en el botón 2:
private void Button2_Click(object sender, EventArgs e) { string jsScript3 = "document.getElementsByTagName('a')[1].click();"; var task3 = chrome.EvaluateScriptAsync(jsScript3); task3.Wait(); }Todo funciona perfectamente. Pero quiero hacer todas estas acciones dentro de un botón.
Encontré la siguiente solución:
private async void ButtonFind_Click(object sender, EventArgs e) { //Action 1 & 2 string jsScript1 = "document.getElementById('story').value=" + '\'' + textFind.Text + '\'' + ";" + "document.querySelector('body > div.wrapper > div.header > div.header44 > div.search_panel > span > form > button').click();"; await chrome.EvaluateScriptAsync(jsScript1); //Action3 Thread.Sleep(1000); //it is necessary to set exactly 1 seconds string jsScript3 = "document.getElementsByTagName('a')[2].click();"; await chrome.EvaluateScriptAsync(jsScript3); } Tengo que usar Thread.Sleep(1000); porque en la redirección de JavaScript o al hacer clic en el botón de búsqueda, se destruyen todos los scripts que se ejecutan actualmente en el navegador. Pero creo que usar Thread.Sleep o Task.Delay no es una buena idea. ¿De qué otra forma puedo cambiar mi código sin usar Thread.Sleep/Task.Delay?
Puede usar algo como lo siguiente para esperar a que se cargue la página
// create a static class for the extension method public static Task<LoadUrlAsyncResponse> WaitForLoadAsync(this IWebBrowser browser) { var tcs = new TaskCompletionSource<LoadUrlAsyncResponse>(TaskCreationOptions.RunContinuationsAsynchronously); EventHandler<LoadErrorEventArgs> loadErrorHandler = null; EventHandler<LoadingStateChangedEventArgs> loadingStateChangeHandler = null; loadErrorHandler = (sender, args) => { //Actions that trigger a download will raise an aborted error. //Generally speaking Aborted is safe to ignore if (args.ErrorCode == CefErrorCode.Aborted) { return; } //If LoadError was called then we'll remove both our handlers //as we won't need to capture LoadingStateChanged, we know there //was an error browser.LoadError -= loadErrorHandler; browser.LoadingStateChanged -= loadingStateChangeHandler; tcs.TrySetResult(new LoadUrlAsyncResponse(args.ErrorCode, -1)); }; loadingStateChangeHandler = (sender, args) => { //Wait for while page to finish loading not just the first frame if (!args.IsLoading) { browser.LoadError -= loadErrorHandler; browser.LoadingStateChanged -= loadingStateChangeHandler; var host = args.Browser.GetHost(); var navEntry = host?.GetVisibleNavigationEntry(); int statusCode = navEntry?.HttpStatusCode ?? -1; //By default 0 is some sort of error, we map that to -1 //so that it's clearer that something failed. if (statusCode == 0) { statusCode = -1; } tcs.TrySetResult(new LoadUrlAsyncResponse(statusCode == -1 ? CefErrorCode.Failed : CefErrorCode.None, statusCode)); } }; browser.LoadingStateChanged += loadingStateChangeHandler; browser.LoadError += loadErrorHandler; return tcs.Task; } // usage example await Task.WhenAll(chrome.WaitForLoadAsync(), chrome.EvaluateScriptAsync(script));Nunca debe usar Sleep de esa manera. La Web puede tomar más o menos tiempo y su código falla desde hace un tiempo. Debe trabajar siempre en modo asíncrono. Si lo desea, puede poner un tiempo de espera en caso de error, pero en modo normal, espere siempre hasta que obtenga lo que desea.
Por ejemplo, haga clic en el botón y configure el temporizador para esperar a que aparezcan sus enlaces. Luego, navegue hasta el primer enlace.
En otros casos, cuando ocurre una navegación real y pierde su contexto de JavaScript, puede usar el objeto vinculado para comunicar su aplicación C# y el navegador. Al hacer esto, puede consultar desde su JavaScript qué está haciendo y, desde JavaScript, dar retroalimentación a su código C#. Es una manera de persistir el estado.
Un ejemplo típico es cuando rellenas unos formularios y haces clic en continuar, continuar... navegando en varias páginas. Si desea recopilar toda la información, necesita el objeto vinculado. Lo uso con la serialización json para administrar datos más complejos.
Si vas a trabajar mucho con el navegador, te recomiendo que inyectes tus propios scripts en la página en la que navegas. De esta forma, puede trabajar con sus propias clases en la página cargada.