একটি নতুন থ্রেডে ওয়েব ব্রাউজার নিয়ন্ত্রণ


84

আমার একটি তালিকা উরির রয়েছে যা আমি "ক্লিক" করতে চাইছি এটি অর্জনের জন্য আমি উরির জন্য একটি নতুন ওয়েব-ব্রাউজার নিয়ন্ত্রণ তৈরি করার চেষ্টা করছি U আমি প্রতি উরির জন্য একটি নতুন থ্রেড তৈরি করেছি I'm ডকুমেন্টের আগে থ্রেড শেষ হওয়া আমার সমস্যাটি হ'ল পুরোপুরি লোড হয়েছে, তাই ডকুমেন্ট কমপ্লিট ইভেন্টটি আমি কখনই ব্যবহার করতে পাই না I আমি কীভাবে এটি পরাভূত করতে পারি?

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);
}

উত্তর:


152

আপনাকে একটি এসটিএ থ্রেড তৈরি করতে হবে যা একটি বার্তা লুপকে পাম্প করে। ওয়েব ব্রাউজারের মতো অ্যাক্টিভ এক্স উপাদানটির জন্য এটি কেবলমাত্র আতিথেয় পরিবেশ। অন্যথায় আপনি ডকুমেন্ট কমপ্লিট ইভেন্টটি পাবেন না। কিছু নমুনা কোড:

private void runBrowserThread(Uri url) {
    var th = new Thread(() => {
        var br = new WebBrowser();
        br.DocumentCompleted += browser_DocumentCompleted;
        br.Navigate(url);
        Application.Run();
    });
    th.SetApartmentState(ApartmentState.STA);
    th.Start();
}

void browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) {
    var br = sender as WebBrowser;
    if (br.Url == e.Url) {
        Console.WriteLine("Natigated to {0}", e.Url);
        Application.ExitThread();   // Stops the thread
    }
}

8
হ্যাঁ! কেবল System.Windows.forms যুক্ত করুন। আমার দিনও বাঁচিয়েছে। ধন্যবাদ
জি

4
আমি আমার কোডটি এই পরিস্থিতিতে মানিয়ে নেওয়ার চেষ্টা করছি। আমাকে WebBrowserঅবজেক্টটি জীবিত রাখতে হবে (রাষ্ট্র / কুকিজ ইত্যাদি সংরক্ষণ করতে) এবং Navigate()সময়ের সাথে সাথে একাধিক কল করতে হবে । তবে আমি নিশ্চিত নই যে আমার Application.Run()কলটি কোথায় রাখা হবে , কারণ এটি আরও কোড কার্যকর করতে বাধা দেয়। কোন সংকেত সনাক্ত করুন?
ডটনেট

আপনি ফিরে আসতে কল Application.Exit();করতে Application.Run()পারেন।
মাইক ডি ক্লার্ক

26

WebBrowserঅটোমেশনের মতো অ্যাসিঙ্ক্রোনাস টাস্কগুলি চালানোর জন্য, অ-ইউআই থ্রেডে কোনও বার্তা লুপটি কীভাবে সংগঠিত করবেন তা এখানে is এটি async/awaitসুবিধাজনক লিনিয়ার কোড প্রবাহ সরবরাহ করতে ব্যবহার করে এবং একটি লুপে ওয়েব পৃষ্ঠাগুলির একটি সেট লোড করে। কোডটি একটি প্রস্তুত-চালিত কনসোল অ্যাপ্লিকেশন যা আংশিকভাবে এই দুর্দান্ত পোস্টের উপর ভিত্তি করে ।

সম্পর্কিত উত্তর:

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();
            }
        }
    }
}

4
উজ্জ্বল এবং তথ্যবহুল উত্তরের জন্য ধন্যবাদ! এটি ঠিক আমি যা খুঁজছিলাম তবে আপনার কাছে মনে হয় (ইচ্ছাকৃতভাবে?) ডিসপোজ () বিবৃতিটি ভুল জায়গায় রেখেছেন।
wodzu

@ পাওয়ে, আপনি ঠিক বলেছেন, সেই কোডটিও সংকলন করেনি :) আমি মনে করি একটি ভুল সংস্করণ আটকানো হয়েছে, এটি এখন ঠিক। এটি সন্ধানের জন্য ধন্যবাদ। : আপনি একটি আরো জেনেরিক পদ্ধতির চেক করতে পারেন stackoverflow.com/a/22262976/1768303
noseratio

আমি এই কোডটি চালানোর চেষ্টা করেছি, তবে এটি আটকে যায় task.Wait();। আমি কিছু ভুল করছি ?
0014

4
হাই, সম্ভবত আপনি এটির সাথে আমাকে সাহায্য করতে পারেন: স্ট্যাকওভারফ্লো.com/ প্রশ্নগুলি / ৪১৫৩99৯///২ - পদ্ধতিটি ভালভাবে কাজ করে তবে মেসেজলুপ ওয়ার্কারারের আগে ফর্মটি ইনস্ট্যান্ট করা থাকলে এটি কাজ করা বন্ধ করে দেয়।
অ্যালেক্স নেটকাচভ

3

অতীতে আমার অভিজ্ঞতা থেকে ওয়েব ব্রাউজার মূল অ্যাপ্লিকেশন থ্রেডের বাইরে অপারেটিং পছন্দ করে না।

পরিবর্তে httpwebrequests ব্যবহার করে দেখুন, আপনি এগুলি অ্যাসিক্রোনাস হিসাবে সেট করতে পারেন এবং প্রতিক্রিয়াটির জন্য এটি হ্যান্ডলার তৈরি করতে পারে যখন এটি সফল হবে:

কীভাবে ব্যবহার করতে হবে- httpwebrequest- নেট-অ্যাসিনক্রোনাসলি


তার সাথে আমার সমস্যা এটি। উরি ক্লিক করা হচ্ছে সাইট লগ ইন করা প্রয়োজন। আমি ওয়েবআরকোয়েস্ট দিয়ে এটি অর্জন করতে পারি না। ওয়েব ব্রাউজার ব্যবহার করে এটি ইতিমধ্যে আইআই ক্যাশে ব্যবহার করে তাই সাইটগুলিতে লগ ইন করা that এর আশেপাশে কোনও উপায় আছে কি? লিঙ্কগুলি ফেসবুক জড়িত। সুতরাং আমি কি ফেসবুকে লগইন করতে পারি এবং ওয়েবউইকুইয়েস্টের সাথে লিঙ্কটি ক্লিক করতে পারি?
আর্ট ডব্লিউ

@ আর্টডাব্লু আমি জানি এটি একটি পুরানো মন্তব্য, তবে লোকেরা সম্ভবত এটি সেট করে সমাধান করতে পারেwebRequest.Credentials = CredentialsCache.DefaultCredentials;
vapcguy

@ বাপকুই যদি এটি এপিআই হয় তবে হ্যাঁ, তবে এটি যদি লগ ইন করার জন্য এইচটিএমএল উপাদানযুক্ত কোনও ওয়েবসাইট থাকে তবে এটির জন্য আই কুকিজ বা ক্যাশে ব্যবহার করা দরকার, অন্যথায় ক্লায়েন্ট জানে না যে Credentialsঅবজেক্টের সম্পত্তি এবং কীভাবে পূরণ করতে হবে এইচটিএমএল।
কলিনম

@ কলিনম এই পুরো পৃষ্ঠাটি প্রসঙ্গে যে প্রসঙ্গে কথা বলছে তা হ'ল HTTPWebRequest অবজেক্ট এবং সি #। নেট ব্যবহার করছে, আপনি জাভাস্ক্রিপ্ট / এজেএক্সের মতো করতে পারেন এমন সহজ HTML এবং ফর্ম উপাদানগুলি পোস্ট করা হচ্ছে না। তবে নির্বিশেষে, আপনার একটি রিসিভার আছে। এবং লগ-অনের জন্য আপনার উইন্ডোজ প্রমাণীকরণ ব্যবহার করা উচিত এবং আইআইএস যেভাবেই হোক না কেন এটি স্বয়ংক্রিয়ভাবে পরিচালনা করে। আপনার যদি এগুলি ম্যানুয়ালি পরীক্ষা করার প্রয়োজন হয় তবে আপনি WindowsIdentity.GetCurrent().Nameছদ্মবেশ প্রয়োগের পরে ব্যবহার করতে পারেন এবং এটি পছন্দ করলে এটি কোনও AD অনুসন্ধানের বিরুদ্ধে পরীক্ষা করতে পারেন। কীভাবে কুকি এবং ক্যাশে এর কোনওটির জন্য ব্যবহৃত হবে তা নিশ্চিত নয়।
vapcguy

@vapcguy প্রশ্নটি এই বিষয়ে কথা বলছে WebBrowserযা এইচটিএমএল পৃষ্ঠাগুলি লোড হচ্ছে বলে ইঙ্গিত করবে, ওপি এমনকি বলেছেন যে WebRequestতিনি যা চান তা অর্জন করবে না, সুতরাং কোনও ওয়েবসাইট যদি লগইনের জন্য এইচটিএমএল ইনপুট আশা করে তবে Credentialsঅবজেক্টটি সেট করা কাজ করবে না। অতিরিক্ত হিসাবে ওপি যেমন বলেছে, সাইটগুলিতে ফেসবুক অন্তর্ভুক্ত রয়েছে; উইন্ডোজ প্রমাণীকরণ এটিতে কাজ করবে না।
কলিনম

0

একটি সহজ সমাধান যেখানে বেশ কয়েকটি ওয়েব ব্রাউজারের একযোগে অপারেশন ঘটে

  1. একটি নতুন উইন্ডোজ ফর্ম অ্যাপ্লিকেশন তৈরি করুন
  2. বোতাম 1 নামক বোতামটি রাখুন
  3. টেক্সটবক্স 1 নামের পাঠ্য বাক্সটি রাখুন
  4. পাঠ্য ক্ষেত্রের বৈশিষ্ট্য সেট করুন: একাধিক সত্য এবং স্ক্রোলবার উভয়ই
  5. নিম্নলিখিত বাটন 1 ক্লিক হ্যান্ডলার লিখুন:

    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);
    
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.