1. 程式人生 > >玩玩小爬蟲——抓取動態頁面

玩玩小爬蟲——抓取動態頁面

 

       在ajax橫行的年代,很多網頁的內容都是動態載入的,而我們的小爬蟲抓取的僅僅是web伺服器返回給我們的html,這其中就

跳過了js載入的部分,也就是說爬蟲抓取的網頁是殘缺的,不完整的,下面可以看下部落格園首頁

從首頁載入中我們看到,在頁面呈現後,還會有5個ajax非同步請求,在預設的情況下,爬蟲是抓取不到這些ajax生成的內容的,

這時候要想獲取就必須呼叫瀏覽器的核心引擎來下載這些動態頁面,目前核心引擎三足鼎立。

Trident: 也就是IE核心,WebBrowser就是基於該核心,但是載入性內比較差。

Gecko: FF的核心,效能相對Trident較好。

WebKit: Safari和Chrome的核心,效能你懂的,在真實場景中還是以它為主。

好了,為了簡單方便,這裡使用WebBrowser來玩一把,使用WebBrowser我們要注意以下幾點:

第一:因為WebBrowser在System.Windows.Forms 中,屬於winform控制元件,所以我們要設定STAThread標記。

第二:winform是事件驅動的,而Console並不會去響事件,所有事件在windows的訊息佇列中等待執行,為了不讓程式假死,

         我們需要呼叫DoEvents方法轉讓控制權,讓作業系統執行其他的事件。

第三:WebBrowser中的內容,我們需要用DomDocument來檢視,而不是DocumentText。

判斷一個動態網頁是否載入完畢,一般常會有兩種方法:

①:設定一個最大值,因為每當非同步載入一個js,都會觸發一個Navigating和DocumentCompleted事件,所以我們需要在此

       處記錄一下count值即可。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Windows.Forms;
 6 using System.Threading;
 7 using System.IO;
 8 
 9 namespace ConsoleApplication2
10 { 11 public class Program 12 { 13 static int hitCount = 0; 14 15 [STAThread] 16 static void Main(string[] args) 17 { 18 string url = "http://www.cnblogs.com"; 19 20 WebBrowser browser = new WebBrowser(); 21 22 browser.ScriptErrorsSuppressed = true; 23 24 browser.Navigating += (sender, e) => 25 { 26 hitCount++; 27 }; 28 29 browser.DocumentCompleted += (sender, e) => 30 { 31 hitCount++; 32 }; 33 34 browser.Navigate(url); 35 36 while (browser.ReadyState != WebBrowserReadyState.Complete) 37 { 38 Application.DoEvents(); 39 } 40 41 while (hitCount < 16) 42 Application.DoEvents(); 43 44 var htmldocument = (mshtml.HTMLDocument)browser.Document.DomDocument; 45 46 string gethtml = htmldocument.documentElement.outerHTML; 47 48 //寫入檔案 49 using (StreamWriter sw = new StreamWriter(Environment.CurrentDirectory + "//1.html")) 50 { 51 sw.WriteLine(gethtml); 52 } 53 54 Console.WriteLine("html 檔案 已經生成!"); 55 56 Console.Read(); 57 } 58 } 59 }

然後,我們開啟生成好的1.html,看看js載入的內容是不是有了。

②: 當然除了通過判斷最大值確定是否已經載入完成,我們還可以通過設定一個Timer來判斷,比如3s,4s,5s後來檢視

      WEBbrowser 是否載入完畢。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Windows.Forms;
 6 using System.Threading;
 7 using System.IO;
 8 
 9 namespace ConsoleApplication2
10 {
11     public class Program
12     {
13         [STAThread]
14         static void Main(string[] args)
15         {
16             string url = "http://www.cnblogs.com";
17 
18             WebBrowser browser = new WebBrowser();
19 
20             browser.ScriptErrorsSuppressed = true;
21 
22             browser.Navigate(url);
23 
24             //先要等待載入完畢
25             while (browser.ReadyState != WebBrowserReadyState.Complete)
26             {
27                 Application.DoEvents();
28             }
29 
30             System.Timers.Timer timer = new System.Timers.Timer();
31 
32             var isComplete = false;
33 
34             timer.Elapsed += new System.Timers.ElapsedEventHandler((sender, e) =>
35             {
36                 //載入完畢
37                 isComplete = true;
38 
39                 timer.Stop();
40             });
41 
42             timer.Interval = 1000 * 5;
43 
44             timer.Start();
45 
46             //繼續等待 5s,等待js載入完
47             while (!isComplete)
48                 Application.DoEvents();
49 
50             var htmldocument = (mshtml.HTMLDocument)browser.Document.DomDocument;
51 
52             string gethtml = htmldocument.documentElement.outerHTML;
53 
54             //寫入檔案
55             using (StreamWriter sw = new StreamWriter(Environment.CurrentDirectory + "//1.html"))
56             {
57                 sw.WriteLine(gethtml);
58             }
59 
60             Console.WriteLine("html 檔案 已經生成!");
61 
62             Console.Read();
63         }
64     }
65 }

當然,效果依舊,就不截圖了,從上面的兩種寫法來看,我們的WebBrowser都是放在主執行緒中,下面我們來看看如何放在工作執行緒上,

很簡單,只要將該工作執行緒設定為STA模式即可。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Windows.Forms;
 6 using System.Threading;
 7 
 8 namespace ConsoleApplication2
 9 {
10     public class Program
11     {
12         static int hitCount = 0;
13 
14         //[STAThread]
15         static void Main(string[] args)
16         {
17             Thread thread = new Thread(new ThreadStart(() =>
18             {
19                 Init();
20                 System.Windows.Forms.Application.Run();
21             }));
22 
23             //將該工作執行緒設定為STA模式
24             thread.SetApartmentState(ApartmentState.STA);
25 
26             thread.Start();
27 
28             Console.Read();
29         }
30 
31         static void Init()
32         {
33             string url = "http://www.cnblogs.com";
34 
35             WebBrowser browser = new WebBrowser();
36 
37             browser.ScriptErrorsSuppressed = true;
38 
39             browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(browser_DocumentCompleted);
40 
41             browser.Navigating += new WebBrowserNavigatingEventHandler(browser_Navigating);
42 
43             browser.Navigate(url);
44 
45             while (browser.ReadyState != WebBrowserReadyState.Complete)
46             {
47                 Application.DoEvents();
48             }
49 
50             while (hitCount < 16)
51                 Application.DoEvents();
52 
53             var htmldocument = (mshtml.HTMLDocument)browser.Document.DomDocument;
54 
55             string gethtml = htmldocument.documentElement.outerHTML;
56 
57             Console.WriteLine(gethtml);
58         }
59 
60         static void browser_Navigating(object sender, WebBrowserNavigatingEventArgs e)
61         {
62             hitCount++;
63         }
64 
65         static void browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
66         {
67             hitCount++;
68         }
69     }
70 }