c#抓取动态页面WebBrowser
在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 }
c#抓取动态页面WebBrowser的更多相关文章
- 手把手视频:万能开源Hawk抓取动态网站
Hawk是沙漠之鹰历时五年开发的开源免费网页抓取工具(爬虫),无需编程,全部可视化. 自从上次发布Hawk 2.0过了小半年,可是还是有不少朋友通过邮件或者微信的方式询问如何使用.看文档还是不如视频教 ...
- java抓取动态生成的网页
最近在做项目的时候有一个需求:从网页面抓取数据,要求是首先抓取整个网页的html源码(后期更新要使用到).刚开始一看这个简单,然后就稀里哗啦的敲起了代码(在这之前使用过Hadoop平台的分布式爬虫框架 ...
- php抓取ajax页面返回图片。
要抓取的页面:http://pic.hao123.com/ 当我们往下滚动的时候,图片是用ajax来动态获取的.这就需要我们仔细分析页面了. 可以看到,异步加载的ajax文件为: http://pic ...
- C#抓取AJAX页面的内容
原文 C#抓取AJAX页面的内容 现在的网页有相当一部分是采用了AJAX技术,所谓的AJAX技术简单一点讲就是事件驱动吧(当然这种说法可能很不全面),在你提交了URL后,服务器发给你的并不是所有是页面 ...
- Chrome + Python 抓取动态网页内容
用Python实现常规的静态网页抓取时,往往是用urllib2来获取整个HTML页面,然后从HTML文件中逐字查找对应的关键字.如下所示: import urllib2 url="http: ...
- selenium抓取动态网页数据
1.selenium抓取动态网页数据基础介绍 1.1 什么是AJAX AJAX(Asynchronouse JavaScript And XML:异步JavaScript和XML)通过在后台与服务器进 ...
- 使用scrapy-selenium, chrome-headless抓取动态网页
在使用scrapy抓取网页时, 如果遇到使用js动态渲染的页面, 将无法提取到在浏览器中看到的内容. 针对这个问题scrapy官方给出的方案是scrapy-selenium, 这是一个把sel ...
- scrapy和selenium结合抓取动态网页
1.安装python (我用的是2.7版本的) 2.安装scrapy: 详情请参考 http://blog.csdn.net/wukaibo1986/article/details/8167590 ...
- 利用curl抓取远程页面内容
最基本的操作如下 $curlPost = 'a=1&b=2';//模拟POST数据$cookie_file = tempnam('./temp','kie');//可选,保存ses ...
随机推荐
- Android异步载入全解析之使用多线程
异步载入之使用多线程 初次尝试 异步.异步,事实上说白了就是多任务处理.也就是多线程执行.多线程那就会有各种问题,我们一步步来看.首先.我们创建一个class--ImageLoaderWithoutC ...
- PHP学习之-正则表达式
PHP学习之-正则表达式 1.什么是正则表达式 正则表达式是对字符串处理额一种逻辑公式,就是用特定的字符串组合成一个规则的字符串,称之为正则匹配模式 $p = '/apple/'; $str = '' ...
- Spring MVC RedirectAttributes的用法解决办法
Spring MVC RedirectAttributes的用法很久没发过技术贴了,今天对于一个问题纠结了2小时,遂放弃研究用另一种方法解决,奈何心中一直存在纠结,发帖求解 我先解释下什么是Redir ...
- 深入理解Arrays.sort() (转)
Arrays.sort(T[], Comparator < ? super T > c) 方法用于对象数组按用户自定义规则排序.官方Java文档只是简要描述此方法的作用,并未进行详细的介绍 ...
- 使用 PyCrypto 进行 AES/ECB/PKCS#5(7) 加密
东篱 使用 PyCrypto 进行 AES/ECB/PKCS#5(7) 加密 2013/06/05 · tech PyCrypto 是流行的 Python 加密/解密库.但是其 AES 的 ECB 模 ...
- LintCode 推断一个二叉树树是否是还有一个二叉树的子书
有两个不同大小的二进制树: T1 有上百万的节点: T2 有好几百的节点. 请设计一种算法.判定 T2 是否为 T1的子树. /** * Definition of TreeNode: * class ...
- J2EE开发框架搭建(1) - maven搭建多项目
怎样使用maven搭建多个项目 1. 创建一个maven project 2. 在frame-parent项目上面点击右键,新建Maven Module 3. 完毕之后再建立一个web项目 4. 依照 ...
- 数据字典的QUAN DEC类型与ABAP P型转换
转至:http://sap.iteye.com/blog/121584 今天突然想到的,肯定很多人知道,但是也肯定有一大堆人不知道. 转换公式 (n+1)/2 比如DEC定义为13位,其中3位小数 ...
- 手动配置S2SH三大框架报错(三)
十二月 08, 2013 10:24:43 下午 org.apache.catalina.core.AprLifecycleListener init 严重: An incompatible vers ...
- c/c++ unix ipc
c/c++ unix ipc 一个例子 //c_unix.c #include <stdio.h> #include <sys/types.h> #include <sy ...