• Python学习笔记(四十)— 内置模块(9)HTMLParser


    摘抄自:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014320023122880232500da9dc4a4486ad00426f081c15000

    如果要编写一个搜索引擎,第一步是用爬虫把目标网站的页面抓下来,第二步就是解析该HTML页面,看看里面的内容到底是新闻、图片还是视频。

    假设第一步已经完成了,第二步应该如何解析HTML呢?

    HTML本质上是XML的子集,但是HTML的语法没有XML那么严格,所以不能用标准的DOM或SAX来解析HTML。

    Python提供了HTMLParser来非常方便地解析HTML,只需简单几行代码:

    from html.parser import HTMLParser
    from html.entities import name2codepoint
    
    class MyHTMLParser(HTMLParser):
    
        def handle_starttag(self, tag, attrs):
            print('<%s>' % tag)
    
        def handle_endtag(self, tag):
            print('</%s>' % tag)
    
        def handle_startendtag(self, tag, attrs):
            print('<%s/>' % tag)
    
        def handle_data(self, data):
            print(data)
    
        def handle_comment(self, data):      # 解析评论
            print('<!--', data, '-->')
    
        def handle_entityref(self, name):    # 解析实体
            print('&%s:' % name)
    
        def handle_charref(self, name):
            print('&#%s:' % name)
    
    
    if __name__=='__main__':
        parser = MyHTMLParser()
        parser.feed('''<html>
        <head></head>
        <body>
        <!-- test html parser -->
            <p>Some <a href="#">html</a> HTML&nbsp;tutorial...<br>END</p>
        </body>
        </html>''')
        # HTML 中的常用字符实体是不间断空格(&nbsp;)。
        # 浏览器总是会截短 HTML 页面中的空格。如果您在文本中写 10 个空格,
        # 在显示该页面之前,浏览器会删除它们中的 9 个。如需在页面中增加空格的数量,
        # 您需要使用 &nbsp; 字符实体。

    结果:

    <html>
    
        
    <head>
    </head>
    
        
    <body>
    
        
    <!--  test html parser  -->
    
            
    <p>
    Some 
    <a>
    html
    </a>
     HTML tutorial...
    <br>
    END
    </p>
    
        
    </body>
    
        
    </html>

    feed()方法可以多次调用,也就是不一定一次把整个HTML字符串都塞进去,可以一部分一部分塞进去。

    特殊字符有两种,一种是英文表示的&nbsp;,一种是数字表示的&#1234;,这两种字符都可以通过Parser解析出来。

    小结

    利用HTMLParser,可以把网页中的文本、图像等解析出来。

    练习

    找一个网页,例如https://www.python.org/events/python-events/,用浏览器查看源码并复制,然后尝试解析一下HTML,输出Python官网发布的会议时间、名称和地点。

    # -*- coding: utf-8 -*-
    # 建议1: 子类在重载构造函数时不要忘了调用父类的构造函数
    # 建议2: HTMLParser的attrs是一个元素为tuple的list
    # 建议3: 调用类属性时,一定要加self, 否则相当于声明了新的临时变量
    
    from html.parser import HTMLParser
    from html.entities import name2codepoint
    from urllib import request
    
    class MyHTMLParser(HTMLParser):
    
        # 解析一下HTML,输出Python官网发布的会议时间、名称和地点。
        def __init__(self):
            super().__init__()
            self._event_title = []
            self._event_location = []
            self._event_time = []
            self._reading_title = False
            self._reading_time = False
            self._reading_location = False
    
        # 解析头标签
        def handle_starttag(self, tag, attrs):
            if tag == 'time':
                self._reading_time = True
            if len(attrs) >= 1:
                if tag == 'h3' and attrs[0][1] == 'event-title':
                    self._reading_title = True
                if tag == 'span' and attrs[0][1] == 'event-location':
                    self._reading_location = True
    
        # 解析内容
        def handle_data(self, data):
            if self._reading_title:
                self._event_title.append(data)
                self._reading_title = False
            if self._reading_time:
                self._event_time.append(data)
                self._reading_time = False
            if self._reading_location:
                self._event_location.append(data)
                self._reading_location = False
    
        @property
        def data(self):
            self._data = []
            for i in range(len(self._event_title)):
                dic = {}
                dic["title"] = self._event_title[i]
                dic["time"] = self._event_time[i]
                dic["location"] = self._event_location[i]
                self._data.append(dic)
            return self._data
    
    def getHtml():
        with request.urlopen('https://www.python.org/events/python-events/') as f:
            data = f.read().decode('utf-8')
        return data
    
    parser = MyHTMLParser()
    parser.feed(getHtml())
    for item in parser.data:
        print(str(item))

    结果:

    {'time': '07 Sept. – 11 Sept. ', 'location': 'Waseda University, Nishi-Waseda Campus, Building 63, Tokyo, Japan', 'title': 'PyCon JP 2017'}
    {'time': '08 Sept. – 11 Sept. ', 'location': 'Universidade de Caxias do Sul (UCS), Caxias do Sul, Rio Grande do Sul, Brazil', 'title': 'Python Sul'}
    {'time': '15 Sept. – 17 Sept. ', 'location': 'Lagos, Nigeria', 'title': 'PyCon Nigeria 2017'}
    {'time': '21 Sept. – 25 Sept. ', 'location': 'Toulouse, France', 'title': 'PyCon FR 2017'}
    {'time': '22 Sept. – 25 Sept. ', 'location': 'Caceres, Spain', 'title': 'PyConES17'}
    {'time': '28 Sept. – 30 Sept. ', 'location': 'United States International University, Nairobi, Kenya', 'title': 'PyConKE 2017'}
    {'time': '28 Aug. – 02 Sept. ', 'location': 'Erlangen, Germany', 'title': 'EuroSciPy 2017'}
    {'time': '26 Aug. – 28 Aug. ', 'location': 'Kuala Lumpur, Malaysia', 'title': 'PyCon APAC 2017'}
  • 相关阅读:
    Code First Migrations更新数据库结构(数据迁移) 【转】
    Lambda表达式详解【转】
    @Html.Raw用法
    ASP.NET MVC文件上传【转】
    SQL Server附加数据库拒绝访问错误解决方法
    window.location.href的用法
    vs2013中将复制过来的文件或文件夹显示到解决方案管理
    Expression<Func<TObject, bool>>与Func<TObject, bool>的区别
    VS中的一些标记
    ob_get_contents()
  • 原文地址:https://www.cnblogs.com/douzujun/p/7466343.html
Copyright © 2020-2023  润新知