• 玩玩小爬虫——抓取动态页面


           在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 }
  • 相关阅读:
    javaweb学习总结(二十四)——jsp传统标签开发
    javaweb学习总结(二十三)——jsp自定义标签开发入门
    javaweb学习总结(二十二)——基于Servlet+JSP+JavaBean开发模式的用户登录注册
    javaweb学习总结(二十一)——JavaWeb的两种开发模式
    javaweb学习总结(二十)——JavaBean总结
    javaweb学习总结(十九)——JSP标签
    javaweb学习总结(十八)——JSP属性范围
    JavaWeb学习总结(十七)——JSP中的九个内置对象
    javaweb学习总结(十六)——JSP指令
    javaweb学习总结(十五)——JSP基础语法
  • 原文地址:https://www.cnblogs.com/huangxincheng/p/2756196.html
Copyright © 2020-2023  润新知