整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

HtmlParse:一款超轻量级的HTML文件解析和爬取工具

tmlParse 是一款基于windwos平台的HTML文档解析工具,可快速构建DOM树,从而轻松实现网页元素的爬取工作。DOM树就是一个HTML文档的节点树,每个节点由:标签(Tag)、属性(Attribute)、文本(Text)三个值来描述。

所谓的HTML文档解析,指的就是如何构建一颗DOM树,只有成功构建出DOM树,才有可能进行后续的数据爬取和分析工作。显然,构建DOM树是比较复杂的过程,因为不是每一个HTML文档都会严格按照规范来书写,因此解析过程需要具有一定容错能力。此外,解析效率也是一个需要考虑的因素,也就是说最好通过一次文档扫描即可建立起DOM树,而不是反复扫描。

下面是HtmlParse介绍。

工具特点

1、绿色纯天然,无任何第三方依赖库,文件大小不到150K; 2、解析速度快,具有一定的HTML语法容错能力,可快速将HMTL文档解析为DOM树; 3、基于命令行参数,可通过不同参数获取指定TAG的属性值和文本内容,从而实现网页爬取功能; 4、可将爬取数据输出为json格式,方便第三方程序进一步分析和使用; 5、可爬取script脚本到指定的js文件中;

下载地址:http://softlee.cn/HtmlParse.zip

使用方法

HtmlParse HtmlPathFile -tag TagName [-attr] [Attribute] [-o] [JsonPathFile]

解析指定的HTML文档,并将文档中指定的标签及属性输出到指定文件中。

HtmlPathFile:必选参数,要解析的HTML文档路径名,如果文件路径中有空格,可使用双引号将文件路径包含;

-tag:必选参数,用于指定要抓取的HTML标签名称; -attr:可选参数,用于指定标签的属性值,如果不指定,则返回该标签的所有属性值; -o:可选参数,用于指定抓取内容输出的文件,可将抓取的内容保存为json格式的文件。 如果该参数不指定,则进行控制台输出。 如果抓取的是script、style则会保存为js格式文件。

如果要抓取doctype,可使用-tag doctype,将整个doctype内容获取。此时将会忽略-attr指定的任何属性值。

举例说明

1、爬取网页中所有超链接

HtmlParse c:/sina.html -tag a -attr href -o c:/sina.json

解析C盘下的sina.html文档,并提取该文档中的所有超链接到sina.json文件中。其中**-tag a -attr href,用于指定获取超链接标签ahref**属性。

2、爬取网页中所有图片链接

HtmlParse c:/sina.html -tag img -attr src -o c:/sina.json

解析C盘下的sina.html文档,并提取该文档中的所有图片链接到sina.json文件中。

3、爬取网页中所有脚本

HtmlParse c:/sina.html -tag script -o c:/sina.js

解析C盘下的sina.html文档,并提取该文档中的所有脚本函数到sina.js文件中。

输出内容

如果通过-o参数指定输出文件,则会生成一个json格式的文档。 TagName为爬取的标签名称,比如超链接的a,其值是一个json数组,数组中的每个内容为Json对象,每个Json对象,有属性和文本构成。如果-attr 指定了要爬取的属性,则AttrName为指定的属性名称,比如href或src。text为该标签的文本内容,有些标签不存在文本内容,比如img、meta等,则该值为空。json格式如下:

{
  "TagName":
  {
     {"AttrName":"AttrValue1", "text":"text1"}
     {"AttrName":"AttrValue1", "text":"text2"}
  }
}

下面是一个sina网页的所有超链接json

{
 "a": [{
  "href": "javascript:;",
  "text": "设为首页"
 }, {
  "href": "javascript:;",
  "text": "我的菜单"
 }, {
  "href": "https://sina.cn/",
  "text": "手机新浪网"
 }, {
  "href": "",
  "text": "移动客户端"
 }, {
  "href": "https://c.weibo.cn/client/guide/download",
  "text": "新浪微博"
 }, {
  "href": "https://so.sina.cn/palmnews/web-sinanews-app-download.d.html",
  "text": "新浪新闻"
 }, {
  "href": "https://finance.sina.com.cn/mobile/comfinanceweb.shtml",
  "text": "新浪财经"
 }, {
  "href": "https://m.sina.com.cn/m/sinasports.shtml",
  "text": "新浪体育"
 }, {
  "href": "https://tousu.sina.com.cn/about_app/index?frompage=heimaopc",
  "text": "黑猫投诉"
 }, {
  "href": "http://blog.sina.com.cn/lm/z/app/",
  "text": "新浪博客"
 }, {
  "href": "https://games.sina.com.cn/o/kb/12392.shtml",
  "text": "新浪游戏"
 }, {
  "href": "https://zhongce.sina.com.cn/about/app",
  "text": "新浪众测"
 }, {
  "href": "https://mail.sina.com.cn/client/mobile/index.php?suda-key=mail_app&suda-value=login",
  "text": "新浪邮箱客户端"
 }, {
  "href": "javascript:;",
  "text": "关闭置顶"
 }, {

来源:https://www.cnblogs.com/softlee/p/16374079.html

在的学习路径跟以前是不一样的,以前是没什么资料,很多东西要看必须得去正面刚。所以我计划做一个专栏,聊一下Webkit相关的实现。但是放心,难度我会降低到最低,文章也会同步到掘金,账号应该是同步的,这里还在审批,有兴趣可以双击支持一下。

·第一章:序列化与反序列化。官方的解释就不念了,直接用前端的例子来说明一下。如果有一个介绍对象,如何把它存储到local story里面?只要能够写出这种代码,并且认为这种方式是正常的,没问题,这就是序列化的操作。同样的,把它转换成object的对象,这个操作就叫反序列化。

这里为什么要提这个内容?因为获取到的协议通过HTTP获取到的内容就是一个字符串,通过字符串将它转换成动物的过程就是parseHtml,就是这个解析html,就是parseHtml。这里是把它改成了中文,它的左边是字母串,右边是DOM,内存中的结构。

顺便提一嘴,解析样式表是什么?左边就是一个字母串儿样式,比如link或者是style都没问题,右边就是CSSOM。

·最后给个思考题,前端如何去存储一个很恶心的对象?就是这种包含了继承、包含了封装的存储关系。如果想不到也没关系,给个提示,比如有一个element,正常情况下直接in sense of element就可以了,它就是一个元素。

但是为什么还有一个nototype?这个东西有兴趣可以考虑一下。当然nototype不一定是解决这个问题的,但是有一点点小关联。



于parseHTML函数代码实在过于庞大,我这里就不一次性贴出源代码了,大家可以前往(https://github.com/vuejs/vue/blob/dev/src/compiler/parser/html-parser.js)查看源代码。

我们来总结一下该函数的主要功能:

1、匹配标签的 "<" 字符

匹配的标签名称不能是:script、style、textarea

有如下情况:

1、注释标签 /^<!\--/

2、条件注释 /^<!\[/

3、html文档头部 /^<!DOCTYPE [^>]+>/i

4、标签结束 /^<\/ 开头

5、标签开始 /^</ 开头

然后开始匹配标签的属性包括w3的标准属性(id、class)或者自定义的任何属性,以及vue的指令(v-、:、@)等,直到匹配到 "/>" 标签的结尾。然后把已匹配的从字符串中删除,一直 while 循环匹配。

解析开始标签函数代码:

function parseStartTag () {
   // 标签的开始 如<div
    const start = html.match(startTagOpen)
    if (start) {
      const match = {
        tagName: start[1], // 标签名称
        attrs: [], // 标签属性
        start: index // 开始位置
      }
       // 减去已匹配的长度
      advance(start[0].length)
      let end, attr
      while (!(end = html.match(startTagClose)) && (attr = html.match(dynamicArgAttribute) || html.match(attribute))) {
        attr.start = index
        v
        advance(attr[0].length)  
        attr.end = index
        match.attrs.push(attr) // 把匹配到的属性添加到attrs数组
      }
      if (end) { // 标签的结束符 ">"
        match.unarySlash = end[1]
        advance(end[0].length)  // 减去已匹配的长度
        match.end = index  // 结束位置
        return match
      }
    }
  }

处理过后结构如下:

接下来就是处理组合属性,调用 “handleStartTag” 函数

 function handleStartTag (match) {
    const tagName = match.tagName // 标签名称
    const unarySlash = match.unarySlash // 一元标签
    if (expectHTML) {
      if (lastTag === 'p' && isNonPhrasingTag(tagName)) {
        // 解析标签结束
        parseEndTag(lastTag)
      }
      if (canBeLeftOpenTag(tagName) && lastTag === tagName) {
        parseEndTag(tagName)
      }
    }
   // 是否为一元标签
    const unary = isUnaryTag(tagName) || !!unarySlash
    const l = match.attrs.length
    // 标签属性集合
    const attrs = new Array(l)
    for (let i = 0; i < l; i++) {
      const args = match.attrs[i]
      const value = args[3] || args[4] || args[5] || ''
      const shouldDecodeNewlines = tagName === 'a' && args[1] === 'href' ? options.shouldDecodeNewlinesForHref : options.shouldDecodeNewlines
      attrs[i] = {
        name: args[1], // 属性名称
        value: decodeAttr(value, shouldDecodeNewlines) // 属性值
      }
      if (process.env.NODE_ENV !== 'production' && options.outputSourceRange) {
        // 开始位置
        attrs[i].start = args.start + args[0].match(/^\s*/).length
        // 结束位置
        attrs[i].end = args.end
      }
    }

    if (!unary) {
      stack.push({ tag: tagName, lowerCasedTag: tagName.toLowerCase(), attrs: attrs, start: match.start, end: match.end })
      lastTag = tagName
    }
		// 调用start函数
    if (options.start) {
      options.start(tagName, attrs, unary, match.start, match.end)
    }
  }

我们简单说一下最后调用的start函数的作用:

1、判断是否为svg标签,并处理svg在ie下的兼容性问题

2、遍历标签属性,验证其名称是否有效

3、标签名是否为 style 或者 script ,如果在服务端会提示warn警告

4、检查属性是否存在 v-for、v-if、v-once指令

5、如果是更元素就验证其合法性,不能是 slot 和 template 标签,不能存在 v-for指令

以上就是界面html模板的开始标签的分析,接下来我们来分析如何匹配结束标签。

请看:Vue源码全面解析三十 parseHTML函数(解析html(二)结束标签)

如有错误,欢迎指正,谢谢。