python:html元素解析

来源:互联网 发布:软件项目汇报 模板 编辑:程序博客网 时间:2024/06/11 22:24

说明

主要是总结我通过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  codecsfrom  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,socketfrom 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

原创粉丝点击