zoukankan      html  css  js  c++  java
  • python:html元素解析

    说明

    主要是总结我通过python实现html解析的一个初步的思路和记录实现基础html解析的代码。本解析方式仅仅
    只是实现了html按元素解析的功能,具体元素的分类获取还得需要再进行进一步的优化。

    html解析

    html解析,当前实现我将其分为两个部分:一个是元素节点的定义,一个是元素节点解析。
    1) 解析实现

    解析通过html的节点进行控制,通过遍历html中的所有节点,对节点进行数据描述。html中的节点(即元素)
    格式为:

    <element ..../>            #单闭合
    <element ...>....</element>  #节点闭合

    目前支持这两类节点的解析(对于不规范的节点书写解析当前或存在一些问题),通过对节点的数据的定义(节点
    名称,节点状态(start,end),节点包含文本,节点包含属性等),python实现通过定义类对象对元素进行定
    义。代码如下:

    class Element:
        elementName="Doucument"
        START_DOCUMENT = 0
        START_HTML = 1
        START_HEAD = 2
        END_HEAD = 3
        START_BODY =4
        END_BODY=5
        START_ELEMENT=6
        END_ELEMENT=7
        ELEMENT_TEXT=8
        END_HTML=9
        END_DOCUMENT=10
        NO_ELEMENT=100
    
        '''
          html基本元素
          elementName:元素名称(header,body之类)
          text:元素包含文本内容
        '''
        def __init__(self,elementName=None,text=None,id=None,**attributes):
            if elementName:
                self.elementName=elementName
            if text:
                self.text=text
            if id:
                self.id=id
            if attributes and len(attributes)>0:
                self.attributes=attributes
            self.content=None
            self.elementDict={}
    
    
    
        def getElementId(self):
            return self.id
    
    
        def toString(self):
            if self.content:
                return self.content
            else:
                buffer=""
                if self.attributes and len(self.attributes):
                    for key in self.attributes:
                        if len(buffer):
                            buffer = "%s="%s"" % (key[0],key[1])
                        else:
                            a=buffer
                            buffer="%s %s="%s"" %(a,key[0],key[1])
                if self.text and len(self.text):
                    return "<%s %s> %s </%s>" %(self.elementName,buffer,self.text,self.elementName)
                else:
                    return "<%s %s/>" % (self.elementName,buffer)
    
    
    
        @staticmethod
        def element(content=None):
            # print  "content:%s" % content
            element = Element()
            if content and len(content.strip().rstrip())>0:
                eleStr=content.strip().rstrip()
                element.content=content
                if len(eleStr) and not eleStr.startswith("<"):
                    '''
                       text 内容
                    '''
                    element.elementName=Element.elementName
                    element.text=eleStr
                    element.id=Element.ELEMENT_TEXT
                elif len(eleStr) and eleStr.startswith("<"):
                    '''
                      标签内容
                    '''
                    if eleStr.startswith('</'):
                        '''
                         element 结束符号
                        '''
                        element.id=Element.END_ELEMENT
                        element.elementName=eleStr[2:len(eleStr)-1]
    
                        if element.elementName:
                            if hasattr(element,"END_"+element.elementName.upper()):
                                element.id=getattr(element,"END_"+element.elementName.upper())
                            else:
                                element.id=Element.END_ELEMENT
                    else:
                        '''
                        element 开始符号
                        '''
                        element.id=Element.START_ELEMENT
    
    
                        params_str=None
                        if eleStr.endswith("/>"):
                            params_str=eleStr[1:-2]
                        else:
                            params_str=eleStr[1:-1]
                        if not params_str:
                            assert "Unpredictable error."
                        params=params_str.split()
                        element.elementName=params[0]
    
    
                        attr_dict = {}
    
    
                        prev_key=None
                        for attr in params[1:]:
                            if "=" in attr:
                                attr_map=attr.split("=")
                                key=attr_map[0].strip().rstrip()
                                value_str=attr_map[1].strip().rstrip()
                                index=len(value_str)
                                value=value_str[1:index-1]
                                attr_dict[key]=value
                                prev_key=key
                            else:
                                if attr.endswith("""):
                                    attr_dict[prev_key]+=" "+attr[:-1]
                                else:
                                    attr_dict[prev_key] += " " + attr
    
                        if len(attr_dict) >0:
                            element.attributes=attr_dict
                        if hasattr(element,"START_"+element.elementName.upper()):
                            element.id = getattr(element, "START_" + element.elementName.upper())
                        else:
                            element.id=Element.START_ELEMENT
    
                        Element.elementName=element.elementName
            else:
                element.elementName=None
                element.text=None
                element.attributes=None
                element.id=Element.NO_ELEMENT
            return element
    

    2) 解析实现

    html解析通过标志”<”和”>”实现对html元素的解析,解析实现通过生成器的方式,逐个迭代。解析主要分为
    三个类型:

    • 简单的单个元素集合

      单一开始和结束元素集合,格式如下:

      <html> #单一开始
      
      </html> #单一结束
      
    • 单封闭(自封闭)元素集合

      自封闭的元素单独处理,会自动迭代成开始标签和结束标签,格式如下:

      <input type="submit" value="Submit" /> #自封闭
      
    • 元素文本数据

      元素文本单独处理,是处于元素开始和结束标签之间的文本数据,依赖文本之前的开始标签

    如上,为基本的格式介绍,python解析代码如下所示:

    import  codecs
    from  params import  *
    
    class Parser:
        '''
        html parser class.
    
        '''
    
        def __init__(self,fileName=None):
            self.fileName=fileName
            self.begin=0
            self.over=0
            self.index=0
    
    
    
        def parser(self):
            if  not self.fileName:
                raise  "File not found."
    
            with codecs.open(filename=self.fileName, mode='r', encoding='utf-8') as inputfile:
                content = inputfile.read()
    
            if (not content) or len(content.strip().rstrip())==0:
                raise  "get file content false."
    
            content=unicode(content.strip().rstrip())
    
            # print "total content:", content
            try:
                index=content.index("<html") if ("<html" in content) else content.index("<html")
            except BaseException as error:
                print "parse erro:",str(error)
                assert True
    
            content=content[index:]
            # print "get content:",content
            #----------------------------------begin parser-------------------------
            yield Element.element("<DOCUMENT>")
    
            while True:
                try:
                    self.begin= content.index("<",self.over) #element begin index.
    
    
                    if self.begin> self.over:
                        text=content[self.over+1:self.begin].strip().rstrip()
                        if text and len(text)>0:
                                yield Element.element(text)
                    self.over= content.index(">",self.begin) #element end index
                    elementStr=content[self.begin:self.over+1].rstrip().strip()
                    # print "elementStr:",elementStr
                    if elementStr and len(elementStr):
                        if elementStr.startswith("<!"):
                            pass
                        elif elementStr.endswith("/>"):
                            yield  Element.element(elementStr[:-2]+">")
                            yield  Element.element("</"+elementStr.split()[0][1:]+">")
                        else:
                            yield Element.element(elementStr)
                except BaseException as error:
                    print "index error:",str(error)
                    break
            #-------------------------------end parser----------------------------------
            yield Element.element("</DOCUMENT>")

    3) 使用

    完成如上的解析操作,使用就简单很多,直接通过for循环遍历,具体操作需要自行解析,代码如下:

    import codecs,sys,socket
    from parser import *
    
    
    fileName = "test.html"
    content = ""
    parser=Parser(fileName)
    a=parser.parser()
    for b in a:
        if b.elementName == 'img':
            print "img url is:", b.attributes['src']
    

    如上,即是一个简易版的html解析实现,
    示例代码在:https://github.com/fishly/graphicsProject-/tree/master/robots/htmlpraser

    Enjoytoday,EnjoyCoding

  • 相关阅读:
    【Mysql】Mysql常见的日志种类及作用
    【Mysql】执行sql的过程
    【Mysql】回表查询原理,利用联合索引实现索引覆盖
    【Mysql】explain详解与索引最佳实践
    【Mybatis】MyBatis源码编译
    【Mysql】MySQL数据存储文件详解
    【LoadRunner-工作原理】
    【LoadRunner-简介】
    【LoadRunner-基础篇】
    【LoadRunner-基础篇】
  • 原文地址:https://www.cnblogs.com/amiko/p/7906218.html
Copyright © 2011-2022 走看看