2016-10-15 15 views
2

URLの内容(JavaScriptによって動的に読み込まれる可能性があります)を取得するには、クラスライブラリにメソッドを作成する必要があります。Webブラウザーをクラスライブラリで使用してWebをスクラビングする

私は無知ですが、この一日のためにグーグルで持つことは、私が思い付いたものです。(コードのほとんどはhereからである)これは、現在、このエラーがスローされます

using System; 
using System.Threading.Tasks; 
using System.Threading; 
using System.Windows.Forms; 

public static class WebScraper 
{ 
    [STAThread] 
    public async static Task<string> LoadDynamicPage(string url, CancellationToken token) 
    { 
     using (WebBrowser webBrowser = new WebBrowser()) 
     { 
      // Navigate and await DocumentCompleted 
      var tcs = new TaskCompletionSource<bool>(); 
      WebBrowserDocumentCompletedEventHandler onDocumentComplete = (s, arg) => tcs.TrySetResult(true); 

      using (token.Register(() => tcs.TrySetCanceled(), useSynchronizationContext: true)) 
      { 
       webBrowser.DocumentCompleted += onDocumentComplete; 
       try 
       { 
        webBrowser.Navigate(url); 
        await tcs.Task; // wait for DocumentCompleted 
       } 
       finally 
       { 
        webBrowser.DocumentCompleted -= onDocumentComplete; 
       } 
      } 

      // get the root element 
      var documentElement = webBrowser.Document.GetElementsByTagName("html")[0]; 

      // poll the current HTML for changes asynchronosly 
      var html = documentElement.OuterHtml; 
      while (true) 
      { 
       // wait asynchronously, this will throw if cancellation requested 
       await Task.Delay(500, token); 

       // continue polling if the WebBrowser is still busy 
       if (webBrowser.IsBusy) 
        continue; 

       var htmlNow = documentElement.OuterHtml; 
       if (html == htmlNow) 
        break; // no changes detected, end the poll loop 

       html = htmlNow; 
      } 

      // consider the page fully rendered 
      token.ThrowIfCancellationRequested(); 
      return html; 
     } 
    } 
} 

現在のスレッドが単一スレッドの アパートメントに存在しないため、ActiveXコントロール '8856f961-340a-11d0-a96b-00c04fd705a2'を にインスタンス化することはできません。

私は閉じていますか?上記の修正がありますか?

または、私がトラックから外れている場合は、.NET(クラスライブラリから呼び出すことができる)を使用して動的なWebコンテンツを取得するための準備ができていますか?

答えて

1

ここでは、Webアプリケーションでテストして正しく動作させています。

それは別のスレッドでWebBrowserコントロールを使用し、完全際に、ブラウザのコンテンツのロードが完了している含むTask<string>を返します

using System; 
using System.Threading.Tasks; 
using System.Threading; 
using System.Windows.Forms; 
public class BrowserBasedWebScraper 
{ 
    public static Task<string> LoadUrl(string url) 
    { 
     var tcs = new TaskCompletionSource<string>(); 
     Thread thread = new Thread(() => { 
      try { 
       Func<string> f =() => { 
        using (WebBrowser browser = new WebBrowser()) 
        { 
         browser.ScriptErrorsSuppressed = true; 
         browser.Navigate(url); 
         while (browser.ReadyState != WebBrowserReadyState.Complete) 
         { 
          System.Windows.Forms.Application.DoEvents(); 
         } 
         return browser.DocumentText; 
        } 
       }; 
       tcs.SetResult(f()); 
      } 
      catch (Exception e) { 
       tcs.SetException(e); 
      } 
     }); 
     thread.SetApartmentState(ApartmentState.STA); 
     thread.IsBackground = true; 
     thread.Start(); 
     return tcs.Task; 
    } 
} 
+0

ありがとうございました! https://www.google.com/#q=where+am+iでは動作しませんが、今必要なもので十分でしょう – Aximili

+1

よろしくお願いします。他の問題については、 'WebBrowser'コントロールがデフォルトであなたのブラウザの最新バージョンを使用していないためです。最新のバージョンを使用するように強制できます。私はWindowsフォームアプリケーションのために[解決策](http://stackoverflow.com/a/38514446/3110834)を適用しました。 –

関連する問題