呵呵,由于正则不熟,所以另谋出路——利用XML去解析html。

要想将抓取到的数据(直接抓取到的是byte[])  转为XML文档(即XMLDocument对象),有两个要点:

一、判断编码(http头 charset 在某些网站上是不准确的)

我利用的是 第三方的一开源项目 去判断编码的,效果还不错:链接 。

二、将html转为XHTML

我利用的是 : SgmlReaderDll.dll ,微软提供的,虽然不是100%的准确,但是足以满足 轻量级的商业需求 。

核心代码如下:

    public class XHtmlTools
{
private const string RegBody = @"<body[\s\S]*?>(?<body>[\s\S]*)</body>"; /// <summary>
/// 获取xml文档
/// </summary>
/// <param name="html"></param>
/// <returns></returns>
public XmlDocument GetXmlDocument(byte[] html)
{
StringBuilder XMLHEAD = new StringBuilder();
XMLHEAD.Append("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
XMLHEAD.Append("<!DOCTYPE ARTICLE[");
XMLHEAD.Append("<!ENTITY nbsp \" \"><!ENTITY iexcl \"¡\"><!ENTITY cent \"¢\"><!ENTITY pound \"£\"><!ENTITY curren \"¤\"><!ENTITY yen \"¥\">");
XMLHEAD.Append("<!ENTITY brvbar \"¦\"><!ENTITY sect \"§\"><!ENTITY uml \"¨\"><!ENTITY copy \"©\"><!ENTITY ordf \"ª\"><!ENTITY laquo \"«\">");
XMLHEAD.Append("<!ENTITY not \"¬\"><!ENTITY shy \"-\"><!ENTITY reg \"®\"><!ENTITY macr \"¯\"><!ENTITY deg \"°\"><!ENTITY plusmn \"±\">");
XMLHEAD.Append("<!ENTITY sup2 \"²\"><!ENTITY sup3 \"³\"><!ENTITY acute \"´\"><!ENTITY micro \"µ\"><!ENTITY para \"¶\"><!ENTITY middot \"·\">");
XMLHEAD.Append("<!ENTITY cedil \"¸\"><!ENTITY sup1 \"¹\"><!ENTITY ordm \"º\"><!ENTITY raquo \"»\"><!ENTITY frac14 \"¼\"><!ENTITY frac12 \"½\">");
XMLHEAD.Append("<!ENTITY frac34 \"¾\"><!ENTITY iquest \"¿\"><!ENTITY times \"×\"><!ENTITY divide \"÷\"><!ENTITY Agrave \"À\"><!ENTITY Aacute \"Á\">");
XMLHEAD.Append("<!ENTITY Acirc \"Â\"><!ENTITY Atilde \"Ã\"><!ENTITY Auml \"Ä\"><!ENTITY Aring \"Å\"><!ENTITY AElig \"Æ\"><!ENTITY Ccedil \"Ç\">");
XMLHEAD.Append("<!ENTITY Egrave \"È\"><!ENTITY Eacute \"É\"><!ENTITY Ecirc \"Ê\"><!ENTITY Euml \"Ë\"><!ENTITY Igrave \"Ì\"><!ENTITY Iacute \"Í\">");
XMLHEAD.Append("<!ENTITY Icirc \"Î\"><!ENTITY Iuml \"Ï\"><!ENTITY ETH \"Ð\"><!ENTITY Ntilde \"Ñ\"><!ENTITY Ograve \"Ò\"><!ENTITY Oacute \"Ó\">");
XMLHEAD.Append("<!ENTITY Ocirc \"Ô\"><!ENTITY Otilde \"Õ\"><!ENTITY Ouml \"Ö\"><!ENTITY Oslash \"Ø\"><!ENTITY Ugrave \"Ù\"><!ENTITY Uacute \"Ú\">");
XMLHEAD.Append("<!ENTITY Ucirc \"Û\"><!ENTITY Uuml \"Ü\"><!ENTITY Yacute \"Ý\"><!ENTITY THORN \"Þ\"><!ENTITY szlig \"ß\"><!ENTITY agrave \"à\">");
XMLHEAD.Append("<!ENTITY aacute \"á\"><!ENTITY acirc \"â\"><!ENTITY atilde \"ã\"><!ENTITY auml \"ä\"><!ENTITY aring \"å\"><!ENTITY aelig \"æ\">");
XMLHEAD.Append("<!ENTITY ccedil \"ç\"><!ENTITY egrave \"è\"><!ENTITY eacute \"é\"><!ENTITY ecirc \"ê\"><!ENTITY euml \"ë\"><!ENTITY igrave \"ì\">");
XMLHEAD.Append("<!ENTITY iacute \"í\"><!ENTITY icirc \"î\"><!ENTITY iuml \"ï\"><!ENTITY eth \"ð\"><!ENTITY ntilde \"ñ\"><!ENTITY ograve \"ò\">");
XMLHEAD.Append("<!ENTITY oacute \"ó\"><!ENTITY ocirc \"ô\"><!ENTITY otilde \"õ\"><!ENTITY ouml \"ö\"><!ENTITY oslash \"ø\"><!ENTITY ugrave \"ù\">");
XMLHEAD.Append("<!ENTITY uacute \"ú\"><!ENTITY ucirc \"û\"><!ENTITY uuml \"ü\"><!ENTITY yacute \"ý\"><!ENTITY thorn \"þ\"><!ENTITY yuml \"ÿ\">");
XMLHEAD.Append("<!ENTITY lsquo \"‘\"><!ENTITY rsquo \"’\"><!ENTITY ldquo \"“\"><!ENTITY rdquo \"”\"><!ENTITY sbquo \"'\"><!ENTITY mdash \"—\">");
XMLHEAD.Append("<!ENTITY Prime \"′\"><!ENTITY hellip \"…\">");
XMLHEAD.Append("]>"); if (html == null)
return null; string xml = Convert(html); if (string.IsNullOrEmpty(xml))
return null; try
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.XmlResolver = null;
xmlDoc.LoadXml(string.Format("{0}{1}", XMLHEAD.ToString(), xml)); return xmlDoc;
}
catch (XmlException)
{
return null;
}
} /// <summary>
/// 将html转为xml
/// </summary>
/// <param name="html"></param>
/// <returns></returns>
public string Convert(byte[] html)
{
string xml = string.Empty;
try
{
using (HtmlReader reader = new HtmlReader(GetString(html)))
{
StringBuilder sb = new StringBuilder(); using (HtmlWriter writer = new HtmlWriter(sb))
{
while (!reader.EOF)
{
writer.WriteNode(reader, true);
}
} xml = sb.ToString();
}
}
catch (Exception)
{
} Match match = Regex.Match(xml, RegBody, RegexOptions.IgnoreCase);
if (match.Success)
{
xml = match.Value;
} if (string.IsNullOrEmpty(xml))
{
xml = "<body></body>";
} return xml;
} /// <summary>
/// 解析编码并获得字符串
/// </summary>
/// <param name="buffer"></param>
/// <returns></returns>
public string GetString(byte[] buffer)
{
string result = string.Empty; if (buffer == null)
return result; using (MemoryStream msTemp = new MemoryStream(buffer))
{
if (msTemp.Length > )
{
msTemp.Seek(, SeekOrigin.Begin);
int DetLen = ;
byte[] DetectBuff = new byte[]; UniversalDetector det = new UniversalDetector(null);
while ((DetLen = msTemp.Read(DetectBuff, , DetectBuff.Length)) > && !det.IsDone())
{
det.HandleData(DetectBuff, , DetectBuff.Length);
}
det.DataEnd();
if (det.GetDetectedCharset() != null)
{
try
{
result = System.Text.Encoding.GetEncoding(det.GetDetectedCharset()).GetString(buffer);
}
catch (ArgumentException)
{
}
}
}
} return result;
} } public class HtmlReader : Sgml.SgmlReader
{
public HtmlReader(TextReader reader)
: base()
{
base.InputStream = reader;
base.DocType = "HTML";
}
public HtmlReader(string content)
: base()
{
base.InputStream = new StringReader(System.Web.HttpUtility.HtmlDecode(content));
base.DocType = "HTML";
} public override bool Read()
{
bool status = false;
try
{
status = base.Read();
if (status)
{
if (base.NodeType == XmlNodeType.Element
&& (string.Compare(base.Name, "head", true) ==
|| string.Compare(base.Name, "script", true) == ))
{
base.Skip();
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return status;
}
} public class HtmlWriter : XmlTextWriter
{
private char[] chArrFilter = new char[] { '\'', '=', '?', '\"', '.', ';', ':', ')', '(', ' ', ' ' }; public HtmlWriter(TextWriter writer)
: base(writer)
{
} public HtmlWriter(StringBuilder builder)
: base(new StringWriter(builder))
{
} public HtmlWriter(Stream stream, Encoding enc)
: base(stream, enc)
{ } public override void WriteCData(string text)
{
// base.WriteCData(text);
} public override void WriteComment(string text)
{ } public override void WriteWhitespace(string ws)
{
if (ws.IndexOf("\r\n") > - || ws.IndexOf("\t") > -)
{
return;
} if (ws != " ")
{
// 处理空白字符
base.WriteWhitespace(ws);
}
} public override void WriteStartElement(string prefix, string localName, string ns)
{
if (localName != "")
{
int index = localName.LastIndexOf(':'); if (index > -)
{
// 防止带有前缀
localName = localName.Substring(index + );
} localName = string.Join("", localName.Split(chArrFilter)).ToLower(); base.WriteStartElement("", localName, "");
}
} public override void WriteAttributes(XmlReader reader, bool defattr)
{
if ((reader.NodeType == XmlNodeType.Element) || (reader.NodeType == XmlNodeType.XmlDeclaration))
{
if (reader.MoveToFirstAttribute())
{
this.WriteAttributes(reader, defattr);
reader.MoveToElement();
}
}
else if (reader.NodeType == XmlNodeType.Attribute)
{
string localName = "";
string value = "";
do
{
localName = reader.LocalName.ToLower(); // 单过滤
if (localName != "xml:space" && (localName.LastIndexOf(':') > - || localName.StartsWith("xml")))
{
// 防止带有前缀
continue;
} localName = string.Join("", localName.Split(chArrFilter)); if (localName == "")
{
continue;
} this.WriteStartAttribute("", localName, ""); while (reader.ReadAttributeValue())
{
// if (reader.NodeType == XmlNodeType.EntityReference)
// {
// this.WriteEntityRef(reader.Name);
// continue;
// } value = reader.Value; if (value == "")
{
continue;
} this.WriteString(value); // this.WriteRawString(reader.Value);
// this.WriteAttributeString(localName, reader.Value);
} this.WriteEndAttribute(); // ===========================================
//string attributeLocalName = reader.LocalName;
//while (reader.ReadAttributeValue())
//{
// string str = reader.Name;
//} //string strValue = reader.Value;
//attributeLocalName = reader.Name; //// 过滤无效的属性
//if (attributeLocalName == "" || strValue == "")
//{
// attributeLocalName = attributeLocalName.TrimStart(new char[] { '\'', '=', '?', '\"', '.' }).ToLower();
// this.WriteAttributeString(attributeLocalName, strValue);
//} } while (reader.MoveToNextAttribute());
}
} }

上述源码及DLL : http://files.cnblogs.com/08shiyan/XHtmlTools.zip

下面再说一下解析XML,我利用的XPath:

XPath 和 jQuery所支持的选择器有一定的相似之处,借助jQuery所支持的选择器去理解XPath会更容易一些。

XmlNode.SelectSingleNode

XmlNode.SelectNodes

http://www.cnblogs.com/08shiyan/archive/2013/05/02/3055078.html

续:

imfunny  分享的 HtmlAgilityPack,开源的力量很强大!

HtmlAgilityPack 里的部分类 的元属性截图

支持多个 .NET 版本

HtmlAgilityPack地址:http://htmlagilitypack.codeplex.com/

C# 解析html —— 将html转为XHTML,然后利用Xml解析的更多相关文章

  1. 多级xml解析方案

    package com.people.xmlToSql; import java.io.File; import java.io.IOException; import java.io.StringW ...

  2. Duilib源码分析(三)XML解析器—CMarkup

    上一节介绍了控件构造器CDialogBuilder,接下来将分析其XML解析器CMarkup: CMarkup:xml解析器,目前内置支持三种编码格式:UTF8.UNICODE.ASNI,默认为UTF ...

  3. 网络热恋之XML解析

    XML 可扩展标记语言 用于标记电子文件使其具有结构性的标记语言,可以用来标记数据.定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言 易读性高,编码手写难度小,数据量大 NSXMLPars ...

  4. XML解析方案

    在iOS中,解析XML的手段有很多 苹果原生 NSXMLParser:SAX方式解析,使用简单 第三方框架 libxml2:纯C语言,默认包含在iOS SDK中,同时支持DOM和SAX方式解析 GDa ...

  5. iOS开发——网络篇——JSON和XML,NSJSONSerialization ,NSXMLParser(XML解析器),NSXMLParserDelegate,MJExtension (字典转模型),GDataXML(三方框架解析XML)

    一.JSON 1.JSON简介什么是JSONJSON是一种轻量级的数据格式,一般用于数据交互服务器返回给客户端的数据,一般都是JSON格式或者XML格式(文件下载除外) JSON的格式很像OC中的字典 ...

  6. IOS 网络浅析-(五 xml解析)

    XML 可扩展标记语言 用于标记电子文件使其具有结构性的标记语言,可以用来标记数据.定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言 易读性高,编码手写难度小,数据量大 NSXMLPars ...

  7. 网络数据的XML解析

    网络应用中的数据解析,因为最近的应用,无论是Android的和ios平台的,一直用也是建议用的都是Json解析, xml解析都有点被遗忘了. 然后最近自己在做着玩一个ios的小应用,涉及网络数据的抓取 ...

  8. XML解析技术研究(一)

      摘要:XML作为过去十年中出现的最流行的技术之一,得到了广泛的应用,而其中XML解析技术是XML应用的关键.本文介绍了XML解析技术的研究动向,分析和比较了4种XML解析技术的优劣,并归纳总结了应 ...

  9. XML概念定义以及如何定义xml文件编写约束条件java解析xml DTD XML Schema JAXP java xml解析 dom4j 解析 xpath dom sax

    本文主要涉及:xml概念描述,xml的约束文件,dtd,xsd文件的定义使用,如何在xml中引用xsd文件,如何使用java解析xml,解析xml方式dom sax,dom4j解析xml文件 XML来 ...

随机推荐

  1. 64位进程池HashCode兼容处理

    背景 net旧项目使用32位生成的HashCode,存储到数据库中.迁移到64位上,就需要对HashCode做兼容处理. 解决方案 1:进程池配置支持32位程序. 2:对Hashcode做兼容处理,[ ...

  2. Visual Studio 2015速递(3)——ASP.NET 新特性

    系列文章 Visual Studio 2015速递(1)——C#6.0新特性怎么用 Visual Studio 2015速递(2)——提升效率和质量(VS2015核心竞争力) Visual Studi ...

  3. node.js小结 2

    下载node安装npm什么的就不说了 入门总结 http://www.cnblogs.com/Darren_code/archive/2011/10/31/nodejs.html 进入node_HOM ...

  4. 缓存篇~第七回 Redis实现基于方法签名的数据集缓存(可控更新,分布式数据缓存)

    返回目录 本篇文章可以说是第六回 Microsoft.Practices.EnterpriseLibrary.Caching实现基于方法签名的数据集缓存(可控更新,WEB端数据缓存)的续篇,事实上,有 ...

  5. Java程序员的日常 —— 多进程开发

    最近再弄进程管理相关的工作,因此必要的就涉及到各种系统下关于进程的管理. 这里简单的介绍下: 如何在Java中执行命令 在windows下肯定是dos命令了,而在linux则为shell命令.执行的方 ...

  6. WindowManager 实现悬浮窗 详解

    WindowManager 实现悬浮窗 详解 一:对于想直接看效果的,可以看看我的demo app. 链接:http://sj.qq.com/myapp/detail.htm?apkName=com. ...

  7. html学习记录之表格、表单基础

    ①编码:charset="utf-8": ​②描述及关键词:name="description":name="keywords": ③a标签 ...

  8. Model-View-Controller(MVC) is an architectural pattern that frequently used in web applications. Which of the following statement(s) is(are) correct?

    Model-View-Controller(MVC) is an architectural pattern that frequently used in web applications. Whi ...

  9. 各浏览器Iframe对contentWindow、contentDocument、document及frames属性测试

    Iframe易于嵌套及管理页面,但经常遇到跨域.父子页面访问问题,对于子页面访问父页面可以兼容性地通过window.Top或window.Parent或window.frameElement等操作,但 ...

  10. How to select Multiple images from UIImagePickerController [duplicate]

    accepted You have to use custom imagepicker. And I think ELCImagePickerController is the best option ...