在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 ConsoleApplication210 {11 public class Program12 {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 ConsoleApplication210 {11 public class Program12 {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 Program11 {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 }
共同学习,写下你的评论
评论加载中...
作者其他优质文章