抓取动态网页(横行的年代,性能相对Trident较好的抓取 )
优采云 发布时间: 2021-10-26 12:20抓取动态网页(横行的年代,性能相对Trident较好的抓取
)
您需要登录才能下载或查看,还没有账号?立即注册
x
楼主今天在博客园看到了这个文章,转载并交流。
在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事件,所以我们需要在这里
记录计数值
.
[C#] 纯文本视图复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.IO;
namespace ConsoleApplication2
{
public class Program
{
static int hitCount = 0;
[STAThread]
static void Main(string[] args)
{
string url = "http://www.cnblogs.com";
WebBrowser browser = new WebBrowser();
browser.ScriptErrorsSuppressed = true;
browser.Navigating += (sender, e) =>
{
hitCount++;
};
browser.DocumentCompleted += (sender, e) =>
{
hitCount++;
};
browser.Navigate(url);
while (browser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
while (hitCount < 16)
Application.DoEvents();
var htmldocument = (mshtml.HTMLDocument)browser.Document.DomDocument;
string gethtml = htmldocument.documentElement.outerHTML;
//写入文件
using (StreamWriter sw = new StreamWriter(Environment.CurrentDirectory + "//1.html"))
{
sw.WriteLine(gethtml);
}
Console.WriteLine("html 文件 已经生成!");
Console.Read();
}
}
}
然后,我们打开生成的1.html,看看js加载的内容有没有。
②:当然,除了通过判断最大值来判断加载是否完成,我们也可以通过设置一个Timer来判断,比如3s、4s、5s,然后再检查WEBbrowser是否加载完毕。
[C#] 纯文本视图复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.IO;
namespace ConsoleApplication2
{
public class Program
{
[STAThread]
static void Main(string[] args)
{
string url = "http://www.cnblogs.com";
WebBrowser browser = new WebBrowser();
browser.ScriptErrorsSuppressed = true;
browser.Navigate(url);
//先要等待加载完毕
while (browser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
System.Timers.Timer timer = new System.Timers.Timer();
var isComplete = false;
timer.Elapsed += new System.Timers.ElapsedEventHandler((sender, e) =>
{
//加载完毕
isComplete = true;
timer.Stop();
});
timer.Interval = 1000 * 5;
timer.Start();
//继续等待 5s,等待js加载完
while (!isComplete)
Application.DoEvents();
var htmldocument = (mshtml.HTMLDocument)browser.Document.DomDocument;
string gethtml = htmldocument.documentElement.outerHTML;
//写入文件
using (StreamWriter sw = new StreamWriter(Environment.CurrentDirectory + "//1.html"))
{
sw.WriteLine(gethtml);
}
Console.WriteLine("html 文件 已经生成!");
Console.Read();
}
}
}
当然效果还是一样的,就不截图了。从上面两种写法来看,我们的WebBrowser是放在主线程的。让我们看看如何将它放在工作线程上。这很简单。工作线程可以设置为STA模式。
[C#] 纯文本视图复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace ConsoleApplication2
{
public class Program
{
static int hitCount = 0;
//[STAThread]
static void Main(string[] args)
{
Thread thread = new Thread(new ThreadStart(() =>
{
Init();
System.Windows.Forms.Application.Run();
}));
//将该工作线程设定为STA模式
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
Console.Read();
}
static void Init()
{
string url = "http://www.cnblogs.com";
WebBrowser browser = new WebBrowser();
browser.ScriptErrorsSuppressed = true;
browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(browser_DocumentCompleted);
browser.Navigating += new WebBrowserNavigatingEventHandler(browser_Navigating);
browser.Navigate(url);
while (browser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
while (hitCount < 16)
Application.DoEvents();
var htmldocument = (mshtml.HTMLDocument)browser.Document.DomDocument;
string gethtml = htmldocument.documentElement.outerHTML;
Console.WriteLine(gethtml);
}
static void browser_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
hitCount++;
}
static void browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
hitCount++;
}
}
}