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

简介:

       在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值即可。

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 是否加载完毕。

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模式即可。

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++;
        }
    }
}

相关文章
|
6月前
|
数据采集 存储 前端开发
动态渲染爬虫:Selenium抓取京东关键字搜索结果
动态渲染爬虫:Selenium抓取京东关键字搜索结果
|
6月前
|
数据采集 存储 前端开发
Java爬虫性能优化:多线程抓取JSP动态数据实践
Java爬虫性能优化:多线程抓取JSP动态数据实践
|
6月前
|
数据采集 存储 JSON
地区电影市场分析:用Python爬虫抓取猫眼/灯塔专业版各地区票房
地区电影市场分析:用Python爬虫抓取猫眼/灯塔专业版各地区票房
|
9月前
|
数据采集 Web App开发 JavaScript
基于Selenium的Python爬虫抓取动态App图片
基于Selenium的Python爬虫抓取动态App图片
705 68
|
6月前
|
数据采集 存储 XML
Python爬虫XPath实战:电商商品ID的精准抓取策略
Python爬虫XPath实战:电商商品ID的精准抓取策略
|
9月前
|
数据采集
Haskell编程中,利用HTTP爬虫实现IP抓取
以上就是利用Haskell编写IP抓取爬虫的详细步骤。希望这篇文章的演示对于理解在Haskell这种函数式编程语言中如何实现网络爬虫有所帮助,而其中的网络访问、标签解析和列表处理等技术在许多其他的问题中都有广泛的应用。
209 26
|
9月前
|
数据采集 存储 前端开发
Python爬虫自动化:批量抓取网页中的A链接
Python爬虫自动化:批量抓取网页中的A链接
|
9月前
|
数据采集 缓存 监控
如何提高爬虫的抓取效率
提高爬虫的抓取效率是爬虫开发中的一个重要目标。以下是一些可以提高爬虫抓取效率的方法和技巧: 1. 合理设置请求频率 避免过高频率:频繁的请求可能会对目标服务器造成过大压力,甚至导致被封禁。合理设置请求间隔时间,例如每次请求间隔几秒到几十秒。 动态调整频率:根据目标网站的响应时间动态调整请求频率。如果响应时间较长,适当降低请求频率;如果响应时间较短,可以适当提高请求频率。
321 6
|
10月前
|
数据采集 存储 缓存
Python爬虫与代理IP:高效抓取数据的实战指南
在数据驱动的时代,网络爬虫是获取信息的重要工具。本文详解如何用Python结合代理IP抓取数据:从基础概念(爬虫原理与代理作用)到环境搭建(核心库与代理选择),再到实战步骤(单线程、多线程及Scrapy框架应用)。同时探讨反爬策略、数据处理与存储,并强调伦理与法律边界。最后分享性能优化技巧,助您高效抓取公开数据,实现技术与伦理的平衡。
505 4
|
10月前
|
数据采集 搜索推荐 API
Python 原生爬虫教程:京东商品列表页面数据API
京东商品列表API是电商大数据分析的重要工具,支持开发者、商家和研究人员获取京东平台商品数据。通过关键词搜索、分类筛选、价格区间等条件,可返回多维度商品信息(如名称、价格、销量等),适用于市场调研与推荐系统开发。本文介绍其功能并提供Python请求示例。接口采用HTTP GET/POST方式,支持分页、排序等功能,满足多样化数据需求。