【Python入门】32.常用内置模块之 HTMLParser & 抓取网页信息

摘要:教你如何用Python自带的HTMLParser解析HTML文本。


写在前面:为了更好的学习python,博主记录下自己的学习路程。本学习笔记基于廖雪峰的Python教程,如有侵权,请告知删除。欢迎与博主一起学习Pythonヽ( ̄▽ ̄)ノ


目录

常用内置模块

HTMLParser

HTMLParser是解析HTML文本的工具。

与解析XML类似,我们需要定义好标签处理的方法。

HTMLParser常用方法有:

handle_starttag(tag, attrs) :处理开始标签,比如<head>

handle_endtag(tag) :处理结束标签,比如</head>

handle_startendtag(tag, attrs) :处理自己结束的标签,如<img />

handle_data(data) :处理数据,标签之间的文本;

handle_comment(data) :处理注释,<!-- -->之间的文本。

这里的tag是指标签,attrs是指属性列表,以元组tuple的方式展示;

看个示例:

from html.parser import HTMLParser                   # 引入HTML解析模块

class MyHTMLParser(HTMLParser):

    def handle_starttag(self, tag, attrs):
        print("<start tag>:", tag)

    def handle_endtag(self, tag):
        print("<end tag>:", tag)

    def handle_data(self, data):
        print("<some data>:", data)

    def handle_startendtag(self, tag, attrs):
        print("<startendtag>:", tag)

    def handle_comment(self,data):
        print("<comment>:", data)


parser = MyHTMLParser()                                      # 创建HTML解析器
parser.feed('<html><head><title>Test</title></head>'         # 解析HTML文本
            '<body><h1>Parse me!</h1><img src = "" />'
            '<!-- comment --></body></html>')

运行结果:

<start tag>: html 
<start tag>: head 
<start tag>: title 
<some data>: Test 
<end tag>: title 
<end tag>: head 
<start tag>: body 
<start tag>: h1 
<some data>: Parse me! 
<end tag>: h1 
<startendtag>: img 
<comment>:  comment  
<end tag>: body 
<end tag>: html 

其中feed( )方法就是来解析HTML文本,可以分多次调用,不用一次把所有文本都解析。

【练习】解析网页源代码

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

#!/usr/bin/python3
# -*- coding:utf-8 -*-

from html.parser import HTMLParser                    # 引入HTML解析模块
from urllib import request                            # 引入URL请求模块
import re                                             # 引入正则表达式模块

class MyHTMLParser(HTMLParser):

    def __init__(self):
        HTMLParser.__init__(self)                     # 继承父类的属性
        self.is_time = False                          # 初始化时间布尔值,用于判断标签是否表示时间,下面类似
        self.is_title = False
        self.is_location = False
        self.is_year = False
        self.info = []                                # 初始化一个list,用于储存获取的信息

    def handle_starttag(self, tag, attrs):            # 定义开始标签处理器
        if tag == 'time' :                            # 判断标签是否表示时间,若是,更改布尔值,下面类似
            self.is_time = True

        if tag == 'h3' and ('class','event-title') in attrs:         # 判断标题标签
            self.is_title = True

        if tag == 'span' and ('class','event-location') in attrs:    # 判断地点标签
            self.is_location = True

        if tag == 'span' and ('class','say-no-more') in attrs:       # 判断年份标签
            self.is_year = True


    def handle_data(self, data):                              # 定义数据内容处理器
        if self.is_time == True:                              # 如果标签为时间
            self.is_time = False                              # 初始化时间布尔值
            self.info.append(dict(会议时间=data))              # 把数据储存在info中,下面类似操作标题、地点、年份
        if self.is_title == True:
            self.is_title = False
            self.info.append(dict(会议名称=data))
        if self.is_location == True:
            self.is_location = False
            self.info.append(dict(会议地点=data))
        if self.is_year == True:
            self.is_year = False
            # 由于网页源码中出现是年份标签但显示的内容不是年份,所以增加一个正则表达式来判断
            if re.match(r'[0-9]', data.strip()):         
                self.info.append(dict(会议年份=data))     



def getinfo(data,u):                                 # 定义信息处理函数
    parser = MyHTMLParser()                        # 创建HTML解析器
    parser.feed(data)                              # 解析HTML文件
    count = 0                                      # 初始化count
    print('抓取网址:%s\n抓取信息如下:' % u)
    for x in parser.info:                          # 打印info
        for key in x :                             # 由于info存的是dict组成的list,所以还要遍历dict
            print(key + ':' + str(x[key]))
        count += 1
        if count % 4 == 0:                         # 当输出四个数据后,打印分割线
            print('-------------------------------')

web = 'https://www.python.org/events/python-events/'
with request.urlopen(web) as f:       # 打开网页
    Data = f.read()
    Data = Data.decode('utf-8')                                                  

getinfo(Data,web)                                      # 解析文件并打印信息

运行结果:

抓取网址:https://www.python.org/events/python-events/ 
抓取信息如下: 
会议名称:PyCon Nigeria 
会议时间:13 Sept. – 16 Sept.  
会议年份: 2018 
会议地点:Lagos, Nigeria 
------------------------------- 
会议名称:PyCon UK 2018 
会议时间:15 Sept. – 20 Sept.  
会议年份: 2018 
会议地点:Cardiff City Hall, Cathays Park, Cardiff, CF10 3ND, UK 
------------------------------- 
会议名称:PyConJP 2018 
会议时间:17 Sept. – 19 Sept.  
会议年份: 2018 
会议地点:Tokyo, Japan 
------------------------------- 
会议名称:PyCon Estonia 
会议时间:04 Oct. – 05 Oct.  
会议年份: 2018 
会议地点:Tallinn, Estonia 
------------------------------- 
会议名称:PyCon India 2018 
会议时间:05 Oct. – 10 Oct.  
会议年份: 2018 
会议地点:Hyderabad, India 
------------------------------- 
会议名称:PyCon ZA 2018 
会议时间:10 Oct. – 15 Oct.  
会议年份: 2018 
会议地点:Johannesburg, South Africa 
------------------------------- 
会议名称:FrOSCon 2018 
会议时间:25 Aug. – 27 Aug.  
会议年份: 2018 
会议地点:University of Applied Sciences Bonn-Rhein-Sieg, Sankt Augustin, Germany 
------------------------------- 
会议名称:PyCon AU 2018 
会议时间:24 Aug. – 29 Aug.  
会议年份: 2018 
会议地点:ICC, Sydney, Australia 
------------------------------- 

上面是解析HTML文本的一个实例,源码都附有具体的注释,小伙伴们应该都能看得懂(`・ω・´)嗯。


以上就是本节的全部内容,感谢你的阅读。

下一节内容:常用第三方模块

有任何问题与想法,欢迎评论与吐槽。

和博主一起学习Python吧( ̄▽ ̄)~*

猜你喜欢

转载自blog.csdn.net/lecorn/article/details/82224770