python:html要素解析

17136 ワード

説明
主に私がpythonを通じてhtml解析を実現する初歩的な考え方と記録を通じて基礎html解析を実現するコードを総括します.本解析方式はhtmlの要素解析機能を実現しただけで,具体的な要素の分類取得にはさらに最適化が必要である.
html解析
html解析、現在実装されている私はそれを2つの部分に分けます:1つは要素ノードの定義で、1つは要素ノードの解析です.1)解析実装
解析はhtmlのノードによって制御され,html内のすべてのノードを遍歴することによってノードに対してデータ記述が行われる.htmlのノード(要素)のフォーマットは次のとおりです.
            #   
...>....  #    

現在、この2つのノードの解析(規範化されていないノードの書き込みに対して現在またはいくつかの問題がある)がサポートされており、pythonは、ノードのデータの定義(ノード名、ノード状態(start,end)、ノードにテキスト、ノードに属性などを含む)によって、定義クラスオブジェクトを通じて要素を定義することを実現しています.コードは次のとおりです.
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>" %(self.elementName,buffer,self.text,self.elementName)
            else:
                return "" % (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要素の解析を実現し、解析はジェネレータによって実現され、個々に反復される.解析は主に3つのタイプに分けられます.
  • 単純な単一要素集合単一開始および終了要素集合.フォーマットは以下の通りである:
     #    
    
     #    
    
  • 単一閉鎖(自己閉鎖)要素集合自己閉鎖の要素は単独で処理され、自動的に開始ラベルと終了ラベルに反復され、フォーマットは以下の通りである:
    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(") if (" in content) else content.index(")
            except BaseException as error:
                print "parse erro:",str(error)
                assert True
    
            content=content[index:]
            # print "get content:",content
            #----------------------------------begin parser-------------------------
            yield Element.element("")
    
            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("")

    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