Mam listę Uri, które chcę „kliknąć” Aby to osiągnąć, próbuję utworzyć nową kontrolkę przeglądarki internetowej na Uri. Tworzę nowy wątek na Uri. Problemem jest koniec wątku przed dokumentem jest w pełni załadowany, więc nigdy nie mogę skorzystać ze zdarzenia DocumentComplete. Jak mogę to przezwyciężyć?
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
Art W.
źródło
źródło
WebBrowser
obiekt przy życiu (aby zapisać stan / pliki cookie itp.) I wykonywać wieleNavigate()
połączeń w czasie. Ale nie jestem pewien, gdzie mam wykonać mojeApplication.Run()
wywołanie, ponieważ blokuje dalsze wykonywanie kodu. Jakieś wskazówki?Application.Exit();
i pozwolićApplication.Run()
wrócić.Oto jak zorganizować pętlę komunikatów w wątku spoza interfejsu użytkownika, aby uruchamiać zadania asynchroniczne, takie jak
WebBrowser
automatyzacja. Używaasync/await
do zapewnienia wygodnego liniowego przepływu kodu i ładuje zestaw stron internetowych w pętli. Kod jest gotową do uruchomienia aplikacją konsolową, która jest częściowo oparta na tym doskonałym poście .Powiązane odpowiedzi:
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(); } } } }
źródło
task.Wait();
. Robię coś źleZ mojego doświadczenia wynika, że przeglądarka internetowa nie lubi działać poza głównym wątkiem aplikacji.
Spróbuj zamiast tego użyć httpwebrequests, możesz ustawić je jako asynchroniczne i utworzyć procedurę obsługi dla odpowiedzi, która będzie wiedziała, kiedy się powiedzie:
how-to-use-httpwebrequest-net-asynchronously
źródło
webRequest.Credentials = CredentialsCache.DefaultCredentials;
Credentials
właściwością obiektu i jak wypełnić HTML.WindowsIdentity.GetCurrent().Name
po zaimplementowaniu personifikacji i przetestować je pod kątem wyszukiwania AD, jeśli chcesz. Nie jestem pewien, jak pliki cookie i pamięć podręczna zostałyby wykorzystane do tego celu.WebBrowser
co wskazywałoby, że ładowane są strony HTML, OP powiedział nawet, żeWebRequest
nie osiągnie tego, czego chce, dlatego jeśli witryna oczekuje wejścia HTML do logowania, ustawienieCredentials
obiektu nie zadziała. Ponadto, jak mówi OP, strony te obejmują Facebooka; Uwierzytelnianie systemu Windows nie będzie działać w tym przypadku.Proste rozwiązanie, w którym występuje jednoczesne działanie kilku przeglądarek internetowych
Napisz następującą procedurę obsługi kliknięcia 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);
źródło