基于HSharp 使用C#反序列化HTML并获取HTML中的特定内容

最近有一个项目,要把别人网站上一些数据扒下来。(其实就是一个查课表)

通过HTTP GET得到网页HTML源码倒是不难……难点在于这个网页内容非常混乱,有的时候格式都会发生变化。

我最开始用Python做,可以直接把网页建立Dom。最简单的方法还是用jQuery,轻轻松松就可以把网站上的特定内容处理掉。

但这个项目是用ASP.Net结合C#语言做的。我找了很多方案,都很费劲。

下面这几个方案都是挺费劲的示例……告诉大家不要学啊

方案一:根据网站建立对应的类。然后过XML反序列化

这个方法很作死,首先建立对应的类就够建一整天的。坑爹在C#是强类型的语言。没法直接对着这个对象操作。只能先建立类。

好像有一些库可以让这个过程稍微舒服点。比如xpath。

方案二:自己用String的substring和正则表达式这些处理HTML

这样写确实可行。但我写的正则表达式和Substring实在太难维护了。代码丑陋不堪,效率低下,还经常神之Exception。

一个比较高效的方案

最后我还是找到了一个比较可行的方法。大概方法是用到了一个叫做HSharp的库。用来以一种弱类型语言的处理方式来应用在C#,处理HTML。

HSharp在Github上的主页:https://github.com/Obisoft2017/HSharp

看上去还是蛮不错的。开源免费,源码也很短。

类似的库也有HTMLagility。那个要复杂不少。C#自带一个Document,那个比较官方,但依赖WebBrowser对象,而且……速度慢的一笔。

我主要用它进行HTML“反序列化”了。

(严格意义上它的工作方式不是强类型的反序列化,而是把各个标签都塞进了字典里。起码这样还是可以查询了)

首先在VS的PM里执行命令:

1 Install-Package Obisoft.HSharp 

基于HSharp 使用C#反序列化HTML并获取HTML中的特定内容

然后直接使用它的HtmlConvert.DeserializeHtml方法来反序列化HTML。官网的示例都挺清楚。

using Obisoft.HSharp.Models;
using System;

namespace Obisoft.HSharp
{
    class Example
    {
        public static void Main(string[] args)
        {
            var NewDocument = HtmlConvert.DeserializeHtml($@"
<html>
<head>
    <meta charset={"\"utf-8\""}>
    <meta name={"\"viewport\""}>
    <title>Example</title>
</head>
<body>
    Some Text
    <table>
        <tr>OneLine</tr>
        <tr>TwoLines</tr>
        <tr>ThreeLines</tr>
    </table>
    Other Text
</body>
</html>");
            Console.WriteLine(NewDocument["html"]["head"]["meta",0].Properties["charset"]);
            Console.WriteLine(NewDocument["html"]["head"]["meta",1].Properties["name"]);
            foreach (var Line in NewDocument["html"]["body"]["table"])
            {
                Console.WriteLine(Line.Son);
            }
    }
}

在上面代码中,反序列化了HTML,并对这段HTML的两个meta的charset和name属性值进行了打印。然后遍历了table的所有元素,打印了元素的内容。

输出结果:

utf-8
viewport
OneLine
TwoLines
ThreeLines

回到项目

我试了试反序列化一个真实的网站。这里拿Obisoft的主页举例子吧。他们的网站属于很复杂很复杂的了。

这里假想要获取他们网站中随意一个数值。这里我获取一下他页面上一个普通数字:

基于HSharp 使用C#反序列化HTML并获取HTML中的特定内容

仔细检查他们代码后,这个数字出现在第5个section标签下面N重div的迭代里的一个span里。编写代码:

            var WebSiteResult = HtmlConvert.DeserializeHtml(new Uri("http://www.obisoft.com.cn/"));
            Console.WriteLine(NeuAaoResult["html"]["body"]["section", 5]["div"]["div"]["div"]["div"]["div"]["div", 2]["span"].Son);

果然,程序成功输出了10. 速度还是挺快的。

考虑到这个库确实挺好用而且足够强大。准备研究研究,去写一些接口。它好像还有挺多方法,应该也可以构建HTML。