zoukankan      html  css  js  c++  java
  • python:解析html(HTMLParser、SGMLParser) 分类: HTMLParser 2013-11-12 18:11 2302人阅读 评论(0) 收藏

    其实python里面有xml.dom模块,但是这次却不能用,为啥呢?因为服务器传回的html从xml角度看不是良构的,没有闭合的标签、没有被注释掉的javascript和css,xml.dom没法处理,这个时候要用sgmllib。

    sgmllib.py 包含一个重要的类: SGMLParser。SGMLParser 将 HTML 分解成有用的片段, 比如开始标记和结束标记。一旦它成功地分解出某个数据为一个有用的片段,它会根据 所发现的数据,调用一个自身内部的方法。为了使用这个分析器,您需要子类化 SGML- Parser类,并且覆盖这些方法。

    SGMLParser类里面包含了很多内部方法,开始读取html后,遇到相应的数据就会调用其对应的方法,最重要的方法有三个:

    • start_tagname(self, attrs)
    • end_tagname(self)
    • handle_data(self, text)

    tagname就是标签名称,比如当遇到<pre>,就会调用start_pre,遇到</pre>,就会调用 end_pre,attrs即为标签的参数,以[(attribute, value), (attribute, value), ...]的形式传回,我们要做的就是在其子类重载自己感兴趣标签对应的函数。

    一个经典的例子:

    1. from sgmllib import SGMLParser
    2. class URLLister(SGMLParser):
    3. self.urls = []
    4. def start_a(self, attrs):
    5. href = [v for k, v in attrs if k=='href']
    6. if href:
    7. self.urls.extend(href)

    顾名思义,这个类的作用就是把html中的所有连接(<a>标签)中的地址(href属性的值)提取出来,放到一个list里面,很实用的功能。^^

    比如处理下面的html:

    <tr>
    <td height="207" colspan="2" align="left" valign="top" class="normal">
    <p>Damien Rice - 《0》 </p>
    <a href="http://galeki.xy568.net/music/Delicate.mp3">1. Delicate</a><br />
    <a href="http://galeki.xy568.net/music/Volcano.mp3">2. Volcano</a><br />
    <a href="http://galeki.xy568.net/music/The Blower's Daughter.mp3">3. The Blower's Daughter</a><br />
    <a href="http://galeki.xy568.net/music/Cannonball.mp3">4. Cannonball </a><br />
    <a href="http://galeki.xy568.net/music/Older Chests.mp3">5. Order Chests</a><br />
    <a href="http://galeki.xy568.net/music/Amie.mp3">6. Amie</a><br />
    <a href="http://galeki.xy568.net/music/Cheers Darlin'.mp3">7. Cheers Darling</a><br />
    <a href="http://galeki.xy568.net/music/Cold Water.mp3">8. Cold water</a><br />
    <a href="http://galeki.xy568.net/music/I Remember.mp3">9. I remember</a><br />
    <a href="http://galeki.xy568.net/music/Eskimo.mp3">10. Eskimo</a></p>
    </td>
    </tr>

    很乱对吧?下面让举个例子利用URLLister提取出上面mp3下载的地址:

    1. date="上面那一堆…………"
    2. lister=URLLister()
    3. lister.feed(date)

    用feed()把要处理的html传递给对象实体,然后我们来看看处理结果:

    1. print lister.urls

    显示:

    ['http://galeki.xy568.net/music/Delicate.mp3',
    'http://galeki.xy568.net/music/Volcano.mp3',
    "http://galeki.xy568.net/music/The Blower's Daughter.mp3",
    'http://galeki.xy568.net/music/Cannonball.mp3',
    'http://galeki.xy568.net/music/Older Chests.mp3',
    'http://galeki.xy568.net/music/Amie.mp3',
    "http://galeki.xy568.net/music/Cheers Darlin'.mp3",
    'http://galeki.xy568.net/music/Cold Water.mp3',
    'http://galeki.xy568.net/music/I Remember.mp3',
    'http://galeki.xy568.net/music/Eskimo.mp3']

    好了,是不是很方便?现在我们知道了如何处理标签中的属性,那么如何处理标签包含的文字呢?就是上面列出的handle_data(self, text),当遇到标签内的内容,就会调用这个函数,传入的text自然就是标签内的内容了,不过,如何筛选出感兴趣标签内的内容呢?比如上面歌曲的列 表,这时候就要配合start_tagname、end_tagname,用做标记的方法来达到这个目的:

    1. class ListName(SGMLParser):
    2. is_a=""
    3. name=[]
    4. def start_a(self, attrs):
    5. self.is_a=1
    6. def end_a(self):
    7. self.is_a=""
    8. def handle_data(self, text):
    9. if self.is_a:
    10. self.name.append(text)

    这里添加了一个is_a标记,再在handle_date中添加一个if,也就是说,仅仅在a标签内,才会把标签里的内容加到name[]里去。

    看看结果:

    1. listname=ListName()
    2. listname.feed(date)
    3. print listname.name

    显示:

    ['1.Delicate', '2.Volcano', "3.The Blower's Daughter",
    '4.Cannonball ', '5.Order Chests', '6.Amie',
    '7.Cheers Darling', '8.Cold water', '9.I remember',
    '10.Eskimo']

    OK,搞定~

    SGMLParser内置的方法不仅仅只有这三个,还有处理注释的handle_comment,还有处理声明的handle_decl等等等等,不过使用方法和上面的基本相同,不再多写了。


    完整代码:

    #-------------------------------------------------------------------------------
    # Name:        模块6
    # Purpose:
    #
    # Author:      lovingJune
    #
    # Created:     12/11/2013
    # Copyright:   (c) lovingJune 2013
    # Licence:     <your licence>
    #-------------------------------------------------------------------------------
    #coding:utf-8
    
    from sgmllib import SGMLParser
    
    class ListName(SGMLParser):
    
        def reset(self):
            #变量标示是否是标签a,或使用self.is_a=True
            self.is_a=""
            self.name=[]
            #继承父类reset方法
            SGMLParser.reset(self)
    
        def start_a(self,attrs):
            #如果是标签a,则设置is_a=1
            self.is_a=1
    
        def end_a(self):
            self.is_a=""
    
        def handle_data(self,data):
            #如果是标签a的数据,则追加
            if self.is_a:
                self.name.append(data)
    
    if __name__ == '__main__':
        urls='''
        <tr>
    <td height="207" colspan="2" align="left" valign="top" class="normal">
    <p>Damien Rice - 《0》 </p>
    <a href="http://galeki.xy568.net/music/Delicate.mp3">1. Delicate</a><br />
    <a href="http://galeki.xy568.net/music/Volcano.mp3">2. Volcano</a><br />
    <a href="http://galeki.xy568.net/music/The Blower's Daughter.mp3">3. The Blower's Daughter</a><br />
    <a href="http://galeki.xy568.net/music/Cannonball.mp3">4. Cannonball </a><br />
    <a href="http://galeki.xy568.net/music/Older Chests.mp3">5. Order Chests</a><br />
    <a href="http://galeki.xy568.net/music/Amie.mp3">6. Amie</a><br />
    <a href="http://galeki.xy568.net/music/Cheers Darlin'.mp3">7. Cheers Darling</a><br />
    <a href="http://galeki.xy568.net/music/Cold Water.mp3">8. Cold water</a><br />
    <a href="http://galeki.xy568.net/music/I Remember.mp3">9. I remember</a><br />
    <a href="http://galeki.xy568.net/music/Eskimo.mp3">10. Eskimo</a></p>
    </td>
    </tr>
        '''
        listname=ListName()
        listname.feed(urls)
        #输出文本的列表结果
        print listname.name
        listname.close()



  • 相关阅读:
    第十三课、计算器核心解析算法(中)------------------狄泰软件学院
    Machine Learning in Action(1) K-*邻
    Machine Learning in Action(0) 开篇
    machine learning for hacker记录(3) 贝叶斯分类器
    machine learning for hacker记录(2) 数据分析
    machine learning for hacker记录(1) R与机器学习
    Hive性能优化
    博客园
    机器学习:CART
    机器学习:线性回归
  • 原文地址:https://www.cnblogs.com/think1988/p/4628015.html
Copyright © 2011-2022 走看看