您的位置:首页 > 编程语言 > Python开发

python中html解析 HTMLParser与sgmllib

2013-12-06 13:59 489 查看
python中,有三个库可以解析html文本,HTMLParser,sgmllib,htmllib。他们的实现方法不通,但功能差不多。这三个库中提供解析html的类都是基类,本身并不做具体的工作。他们在发现的元件后(如标签、注释、声名等),会调用相应的函数,这些函数必须重载,因为基类中不作处理。
 
比如:
"""<html><head><title>Advice</title></head><body>

<p>The <a href="http://ietf.org">IETF admonishes:

<i>Be strict in what you <b>send</b>.</i></a></p>

<form>

<input type=submit >  <input type=text name=start size=4></form>

</body></html>

"""
 
如果对这个数据做处理,当检测到<html>标签时,对于HTMLParser,会调用handle_starttag函数。
 
 
下面具体介绍下几个库

1、HTMLParser

[python] view plaincopy

#------------------ HTMLParser_stack.py ------------------#  
#-- coding: GBK --  
import HTMLParser,sys,os,string  
html = """<html><head><title>Advice</title></head><body> 
<p>The <a href="http://ietf.org" mce_href="http://ietf.org">IETF admonishes: 
<i>Be strict in what you <b>send</b>.</i></a></p> 
<form> 
<input type=submit >  <input type=text name=start size=4></form> 
</body></html> 
"""  
  
tagstack = []  
class ShowStructure(HTMLParser.HTMLParser):  
    def handle_starttag(self, tag, attrs): tagstack.append(tag)  
    def handle_endtag(self, tag): tagstack.pop()  
    def handle_data(self, data):  
        if data.strip():  
            for tag in tagstack: sys.stdout.write('/'+tag)  
            sys.stdout.write(' >> %s/n' % data[:40].strip())  
ShowStructure().feed(html)  

此函数的输出:
/html/body/p >> The

/html/body/p/a >> IETF admonishes:

/html/body/p/a/i >> Be strict in what you

/html/body/p/a/i/b >> send

/html/body/p/a/i >> .

对于一些网页,可能并没有严格的开始结束标签对,这时,我们可以去忽略一些标签。可以自己写个堆栈来处理这些标签。

[python] view plaincopy

#*--------------- TagStack class example -----------------#  
class TagStack:  
    def __init__(self, lst=[]): self.lst = lst  
    def __getitem__(self, pos): return self.lst[pos]  
    def append(self, tag):  
    # Remove every paragraph-level tag if this is one  
    if tag.lower() in ('p','blockquote'):  
        self.lst = [t for t in self.lst  
                if t not in ('p','blockquote')]  
        self.lst.append(tag)  
    def pop(self, tag):  
        # "Pop" by tag from nearest pos, not only last item  
        self.lst.reverse()  
        try:  
        pos = self.lst.index(tag)  
        except ValueError:  
            raise HTMLParser.HTMLParseError, "Tag not on stack"  
        del self.lst[pos]  
        self.lst.reverse()  
tagstack = TagStack()  

 
 
HTMLParser有个bug,就是不能处理中文属性,比如说,如果网页里有这么一段:
<input type=submit value=跳转到>
那么解析到这一行时就会出错。

错误原因还是正则表达式惹的祸。

 

attrfind = re.compile(

    r'/s*([a-zA-Z_][-.:a-zA-Z_0-9]*)(/s*=/s*'

    r'(/'[^/']*/'|"[^"]*"|[-a-zA-Z0-9./,:;+*%?!&$/(/)_#=~@]*))?') 

attrfind 没有匹配中文字符。
可以更改这个匹配已修正这个错误。sgmllib则不存在这种错误。
 

2、sgmllib

html格式为sgml格式的一个子集,所以sgml可以处理跟多的东西,下面通过一段代码来示例sgmllib的用法。
 

[python] view plaincopy

#------------------ HTMLParser_stack.py ------------------#  
#-- coding: GBK --  
import sgmllib,sys,os,string  
html = """<lala><head><title>Advice</title></head><body> 
<p>The <a href="http://ietf.org" mce_href="http://ietf.org">IETF admonishes: 
<i>Be strict in what you <b>send</b>.</i></a></p> 
<form> 
<input type=submit name='我'> 我 <input type=text name=start size=4></form> 
</body></lala> 
"""  
  
os.chdir('d://python')  
f=file('testboard.txt','r')  
contest=f.read()  
tagstack = []  
class ShowStructure(sgmllib.SGMLParser):  
    def handle_starttag(self, tag, method,attrs): tagstack.append(tag)  
    def handle_endtag(self, tag): tagstack.pop()  
    def handle_data(self, data):  
        if data.strip():  
            for tag in tagstack: sys.stdout.write('/'+tag)  
            sys.stdout.write(' >> %s/n' % data[:40].strip())  
              
    def unknown_starttag(self,tag,attrs):  
        print 'start tag:<'+tag+'>'  
    def unknown_endtag(self,tag):  
        print 'end tag:</'+tag+'>'  
    def start_lala(self,attr):  
        print 'lala tag found'  
ShowStructure().feed(html)  

 输出:

start tag:<head>

start tag:<title>

/lala >> Advice

end tag:</title>

end tag:</head>

start tag:<body>

start tag:<p>

/lala >> The

start tag:<a>

/lala >> IETF admonishes:

start tag:<i>

/lala >> Be strict in what you

start tag:<b>

/lala >> send

end tag:</b>

/lala >> .

end tag:</i>

end tag:</a>

end tag:</p>

start tag:<form>

start tag:<input>

/lala >> ϒ

start tag:<input>

end tag:</form>

end tag:</body>

end tag:</lala>

 
和HTMLParser一样,如果要用sgmllib解析html,则要继承sgmllib.SGMLParser类,此类里的函数都是空的,用户需要重载它。这个类提供的功能是在特定情况下调用相应的函数。
比如当发现<html>标签时,如果并没有定义 start_html(self,attr)函数,则会调用unknown_starttag函数,具体怎么处理则更具用户。
sgml的标签是可以自定义的,比如自己定义了一个start_lala函数,则就会处理<lala>标签。
 
有个地方要说明下,如果定义了start_tagname函数,有定义了handle_starttag函数,则函数只会运行handle_starttag函数,start_tagname为空函数都没有问题,如果没有定义handle_starttag函数,则遇到<tagname>标签时,会运行start_tagname函数。如果没有定义tagname的start函数,则此标签为未知标签,调用unknown_starttag函数
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  python
相关文章推荐