zoukankan      html  css  js  c++  java
  • 用python解析html

    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
    1. #------------------ HTMLParser_stack.py ------------------#  
    2. #-- coding: GBK --  
    3. import HTMLParser,sys,os,string  
    4. html = """<html><head><title>Advice</title></head><body> 
    5. <p>The <a href="http://ietf.org" mce_href="http://ietf.org">IETF admonishes: 
    6. <i>Be strict in what you <b>send</b>.</i></a></p> 
    7. <form> 
    8. <input type=submit >  <input type=text name=start size=4></form> 
    9. </body></html> 
    10. """  
    11.   
    12. tagstack = []  
    13. class ShowStructure(HTMLParser.HTMLParser):  
    14.     def handle_starttag(self, tag, attrs): tagstack.append(tag)  
    15.     def handle_endtag(self, tag): tagstack.pop()  
    16.     def handle_data(self, data):  
    17.         if data.strip():  
    18.             for tag in tagstack: sys.stdout.write('/'+tag)  
    19.             sys.stdout.write(' >> %s/n' % data[:40].strip())  
    20. 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
    1. #*--------------- TagStack class example -----------------#  
    2. class TagStack:  
    3.     def __init__(self, lst=[]): self.lst = lst  
    4.     def __getitem__(self, pos): return self.lst[pos]  
    5.     def append(self, tag):  
    6.     # Remove every paragraph-level tag if this is one  
    7.     if tag.lower() in ('p','blockquote'):  
    8.         self.lst = [t for t in self.lst  
    9.                 if t not in ('p','blockquote')]  
    10.         self.lst.append(tag)  
    11.     def pop(self, tag):  
    12.         # "Pop" by tag from nearest pos, not only last item  
    13.         self.lst.reverse()  
    14.         try:  
    15.         pos = self.lst.index(tag)  
    16.         except ValueError:  
    17.             raise HTMLParser.HTMLParseError, "Tag not on stack"  
    18.         del self.lst[pos]  
    19.         self.lst.reverse()  
    20. 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
    1. #------------------ HTMLParser_stack.py ------------------#  
    2. #-- coding: GBK --  
    3. import sgmllib,sys,os,string  
    4. html = """<lala><head><title>Advice</title></head><body> 
    5. <p>The <a href="http://ietf.org" mce_href="http://ietf.org">IETF admonishes: 
    6. <i>Be strict in what you <b>send</b>.</i></a></p> 
    7. <form> 
    8. <input type=submit name='我'> 我 <input type=text name=start size=4></form> 
    9. </body></lala> 
    10. """  
    11.   
    12. os.chdir('d://python')  
    13. f=file('testboard.txt','r')  
    14. contest=f.read()  
    15. tagstack = []  
    16. class ShowStructure(sgmllib.SGMLParser):  
    17.     def handle_starttag(self, tag, method,attrs): tagstack.append(tag)  
    18.     def handle_endtag(self, tag): tagstack.pop()  
    19.     def handle_data(self, data):  
    20.         if data.strip():  
    21.             for tag in tagstack: sys.stdout.write('/'+tag)  
    22.             sys.stdout.write(' >> %s/n' % data[:40].strip())  
    23.               
    24.     def unknown_starttag(self,tag,attrs):  
    25.         print 'start tag:<'+tag+'>'  
    26.     def unknown_endtag(self,tag):  
    27.         print 'end tag:</'+tag+'>'  
    28.     def start_lala(self,attr):  
    29.         print 'lala tag found'  
    30. 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函数

  • 相关阅读:
    vue----webpack模板----axios请求
    vue-----meta路由元信息
    vue----webpack模板----全局路由守卫
    vue----webpack模板----局部路由守卫
    vue----webpack模板----组件复用解决方法
    vue----webpack模板----编程式导航
    vue----webpack模板----路由跳转的3中方式
    vue----webpack模板----路由传值
    vue----webpack模板----children子路由,路由嵌套
    vue----webpack模板----路由配置项
  • 原文地址:https://www.cnblogs.com/mfryf/p/3691591.html
Copyright © 2011-2022 走看看