Tengo una lista de Uri en los que quiero "hacer clic". Para lograr esto, estoy tratando de crear un nuevo control de navegador web por Uri. Creo un nuevo hilo por Uri. El problema que tengo es el final del hilo antes del documento está completamente cargado, por lo que nunca puedo utilizar el evento DocumentComplete. ¿Cómo puedo superar esto?
var item = new ParameterizedThreadStart(ClicIt.Click);
var thread = new Thread(item) {Name = "ClickThread"};
thread.Start(uriItem);
public static void Click(object o)
{
var url = ((UriItem)o);
Console.WriteLine(@"Clicking: " + url.Link);
var clicker = new WebBrowser { ScriptErrorsSuppressed = true };
clicker.DocumentCompleted += BrowseComplete;
if (String.IsNullOrEmpty(url.Link)) return;
if (url.Link.Equals("about:blank")) return;
if (!url.Link.StartsWith("http://") && !url.Link.StartsWith("https://"))
url.Link = "http://" + url.Link;
clicker.Navigate(url.Link);
}
c#
multithreading
browser
Arte W
fuente
fuente
WebBrowser
vivo el objeto (para guardar estado / cookies, etc.) y realizar múltiplesNavigate()
llamadas a lo largo del tiempo. Pero no estoy seguro de dónde realizar miApplication.Run()
llamada, porque bloquea la ejecución de más código. ¿Alguna pista?Application.Exit();
para dejarApplication.Run()
volver.A continuación, se explica cómo organizar un bucle de mensajes en un hilo que no sea de interfaz de usuario para ejecutar tareas asincrónicas como la
WebBrowser
automatización. Se utilizaasync/await
para proporcionar el flujo de código lineal conveniente y carga un conjunto de páginas web en un bucle. El código es una aplicación de consola lista para ejecutar que se basa parcialmente en esta excelente publicación .Respuestas relacionadas:
using System; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace ConsoleApplicationWebBrowser { // by Noseratio - https://stackoverflow.com/users/1768303/noseratio class Program { // Entry Point of the console app static void Main(string[] args) { try { // download each page and dump the content var task = MessageLoopWorker.Run(DoWorkAsync, "http://www.example.com", "http://www.example.net", "http://www.example.org"); task.Wait(); Console.WriteLine("DoWorkAsync completed."); } catch (Exception ex) { Console.WriteLine("DoWorkAsync failed: " + ex.Message); } Console.WriteLine("Press Enter to exit."); Console.ReadLine(); } // navigate WebBrowser to the list of urls in a loop static async Task<object> DoWorkAsync(object[] args) { Console.WriteLine("Start working."); using (var wb = new WebBrowser()) { wb.ScriptErrorsSuppressed = true; TaskCompletionSource<bool> tcs = null; WebBrowserDocumentCompletedEventHandler documentCompletedHandler = (s, e) => tcs.TrySetResult(true); // navigate to each URL in the list foreach (var url in args) { tcs = new TaskCompletionSource<bool>(); wb.DocumentCompleted += documentCompletedHandler; try { wb.Navigate(url.ToString()); // await for DocumentCompleted await tcs.Task; } finally { wb.DocumentCompleted -= documentCompletedHandler; } // the DOM is ready Console.WriteLine(url.ToString()); Console.WriteLine(wb.Document.Body.OuterHtml); } } Console.WriteLine("End working."); return null; } } // a helper class to start the message loop and execute an asynchronous task public static class MessageLoopWorker { public static async Task<object> Run(Func<object[], Task<object>> worker, params object[] args) { var tcs = new TaskCompletionSource<object>(); var thread = new Thread(() => { EventHandler idleHandler = null; idleHandler = async (s, e) => { // handle Application.Idle just once Application.Idle -= idleHandler; // return to the message loop await Task.Yield(); // and continue asynchronously // propogate the result or exception try { var result = await worker(args); tcs.SetResult(result); } catch (Exception ex) { tcs.SetException(ex); } // signal to exit the message loop // Application.Run will exit at this point Application.ExitThread(); }; // handle Application.Idle just once // to make sure we're inside the message loop // and SynchronizationContext has been correctly installed Application.Idle += idleHandler; Application.Run(); }); // set STA model for the new thread thread.SetApartmentState(ApartmentState.STA); // start the thread and await for the task thread.Start(); try { return await tcs.Task; } finally { thread.Join(); } } } }
fuente
task.Wait();
. Estoy haciendo algo mal ?Según mi experiencia en el pasado, al navegador web no le gusta operar fuera del hilo principal de la aplicación.
Intente usar httpwebrequests en su lugar, puede configurarlos como asíncronos y crear un controlador para que la respuesta sepa cuándo es exitosa:
cómo-utilizar-httpwebrequest-net-asincrónicamente
fuente
webRequest.Credentials = CredentialsCache.DefaultCredentials;
Credentials
propiedad del objeto y cómo completar el HTML.WindowsIdentity.GetCurrent().Name
después de implementar la suplantación y probarlos con una búsqueda de AD, si lo desea. No estoy seguro de cómo se usarían las cookies y el caché para nada de eso.WebBrowser
qué indicaría que se están cargando páginas HTML, OP incluso ha dicho queWebRequest
no logrará lo que quiere, por lo tanto, si un sitio web espera una entrada HTML para el inicio de sesión, la configuración delCredentials
objeto no funcionará. Además, como dice OP, los sitios incluyen Facebook; La autenticación de Windows no funcionará en esto.Una solución sencilla en la que se produce el funcionamiento simultáneo de varios WebBrowsers
Escriba el siguiente controlador de clic de button1:
textBox1.Clear(); textBox1.AppendText(DateTime.Now.ToString() + Environment.NewLine); int completed_count = 0; int count = 10; for (int i = 0; i < count; i++) { int tmp = i; this.BeginInvoke(new Action(() => { var wb = new WebBrowser(); wb.ScriptErrorsSuppressed = true; wb.DocumentCompleted += (cur_sender, cur_e) => { var cur_wb = cur_sender as WebBrowser; if (cur_wb.Url == cur_e.Url) { textBox1.AppendText("Task " + tmp + ", navigated to " + cur_e.Url + Environment.NewLine); completed_count++; } }; wb.Navigate("/programming/4269800/webbrowser-control-in-a-new-thread"); } )); } while (completed_count != count) { Application.DoEvents(); Thread.Sleep(10); } textBox1.AppendText("All completed" + Environment.NewLine);
fuente