前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python:HTMLParser模块进

Python:HTMLParser模块进

作者头像
py3study
发布2020-01-10 16:02:25
7220
发布2020-01-10 16:02:25
举报
文章被收录于专栏:python3python3

    这是从用Python开发开始到现在第二次使用HTMLParser模块进行html解析了,第一次用的时候,由于是刚刚接触Python,对其中的一些用法不是很理解,因为赶进度,虽然照着参考资料也写出来了,但是其中的原理还是不怎么了解。第二次用的时候,有一定的经验了,对Python的理解也更加深刻了,所以第二次用的时候,对HTMLParser模块的一些用法不像第一次用时那么茫然。结合鄙人第二次用该模块的经验,来讲讲HTMLParser模块的基本使用方法,希望对你有帮助。

    HTMLParser是python用来解析html的模块。它可以分析出html里面的标签、数据等等,是一种处理html的简便途径。HTMLParser采用的是一种事件驱动的模式,当HTMLParser找到一个特定的标记时,它会去调用一个用户定义的函数,以此来通知程序处理。它主要的用户回调函数的命名都是以handler_开头的,都是HTMLParser的成员函数。当我们使用时,就从HTMLParser派生出新的类,然后重新定义这几个以handler_开头的函数即可。这几个函数包括:

handle_startendtag(tag, attrs)  处理开始标签和结束标签

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

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

handle_charref(name)      处理特殊字符串,就是以&#开头的,一般是内码表示的字符

handle_entityref(name)    处理一些特殊字符,以&开头的,比如  

handle_data(data)         处理数据,就是<xx>data</xx>中间的那些数据

handle_comment(data)      处理注释

handle_decl(decl)         处理<!开头的,比如<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"

handle_pi(data)           处理形如<?instruction>的东西

tag是的html标签,attrs是 (属性,值)元组(tuple)的列表(list). 

HTMLParser自动将tag和attrs都转为小写。

下面以从中国银行官网上解析html文件以获取实时汇率(这就是我第二此用该模块时的解析任务)为例,来定义一个HTMLParser派生类。

在构造这个派生类之前,肯定要分析网页的源码的,找出你要获取的那一个值,在此不做介绍。直接上代码了,要仔细理解

代码语言:javascript
复制
#coding=utf-8
import HTMLParser
import requests
class MyHTMLParser(HTMLParser.HTMLParser):
    """

    """
    def __init__(self):
        HTMLParser.HTMLParser.__init__(self)
        self.result = []#记录结果
        self.flag = False#标记


    def handle_starttag(self,tag,attrs):
        if tag == "td" and self.flag == False and len(attrs) == 0:
        #attrs(属性,值)元组(tuple)的列表(list),由于我要获取的值的html标签的没有属性
        #所以要求它长度0以排除其它有属性的标签,缩小获取结果的范围。
        #如果有属性的话,attrs不会为空,它是元组列表可以用条件语句来判断
            self.flag = True

    def handle_end(self,tag):
        if tag == "td" and self.flag == True:
            self.flag = False

    def handle_data(self, data):
        if self.flag == True:
            self.result.append(data)

上面代码不难理解,都是重载HTMLParser类里的方法。

再接着就是爬取网页了,获取数据,代码如下:

代码语言:javascript
复制
def _filter_string(string):
    """
    除去字符串中的空格,换行等等
    由于网页源码中空格、换行符等会使返回的结果中带有换行符(\t)等,所以在此除去,
    其实也可以得到结果(返回的结果是个列表)后用列表的内建方法除去这些带有换行符的元素,
    其实这样用‘+’拼接字符串的效率很低,这个问题我也是刚刚发现,过段时间在研究一下,
    找到了好的方法,再跟大家分享下。
    """
    s = ''
    for one in string:
        if one != '\n' and one != '\r' and one != '\t' and one != ' ':
            s = s + one
    return s
    
def get_rate():
    """
    获取汇率
    Returns:

    """
    url = "http://srh.bankofchina.com/search/whpj/search.jsp"
    headers = {'user-agent':'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:46.0) Gecko/20100101 Firefox/46.0'}
    usd_data = {
                 'pjname':1316,#美元在中国银行官网的代码
                }
    hkd_data = {
                 'pjname':1315,#港币在中国银行官网的代码
                 }
    usd_result = requests.post(url, data=usd_data, headers=headers)
    hkd_result = requests.post(url, data=hkd_data, headers=headers)
    usd_parser = MyHTMLParser()
    hkd_parser = MyHTMLParser()
    usd_text = usd_result.text
    hkd_text = hkd_result.text
    # text = _filter_string(text)
    usd_text = _filter_string(usd_text)
    hkd_text = _filter_string(hkd_text)

    usd_parser.feed(usd_text)
    usd_parser.close()
    # print usd_result.text
    hkd_parser.feed(hkd_text)
    hkd_parser.close()
    usd_start = usd_parser.result.index(u"美元")  # 美元第一个出现的位置是最新值
    usd_rate = usd_parser.result[usd_start + 3]
    usd_rate = float(usd_rate) / 100  # 最新美元汇率
    usd_uptime = usd_parser.result[usd_start + 7]  # 发布时间
    hkd_start = hkd_parser.result.index(u"港币")
    hkd_rate = hkd_parser.result[hkd_start + 3]
    hkd_rate = float(hkd_rate) / 100
    hkd_uptime = hkd_parser.result[hkd_start + 7]  # 发布时间
    return usd_rate, usd_uptime, hkd_rate, hkd_uptime

HTMLParser类的其它一些方法:

HTMLParser.reset()

重置该实例。失去所有未处理的数据。这个在实例化对象时被隐含地调用。

HTMLParser.feed(data)

提供一些文本给解析器。在由完整元素组成的限度内进行处理,不完整的数据被缓冲直到更多的数据提供或者close()被调用。

HTMLParser.close()

强制将所有的缓冲数据按跟在结束标记的数据一样进行处理。该方法可以通过派生类定义对输入结尾的额外处理来进行重定义,但是重定义的版本应该总是调用HTMLParser基类方法close()

HTMLParser.getpos()

返回当前行数和位移值。

HTMLParser.get_starttag_text()

返回当前位置最近的开始标签的内容

这是给公司内部财务人员记账用的,所以做成了API供调用。隐约感觉上面代码最后几行获取结果的方法不是最佳方法,如果你有更好的方法,欢迎您与我分享,如果我找到了更好的我会及时分享给大家。

当然,如果是个简单的任务,用HTMLParser模块抓取一些想要的数据还是绰绰有余,如果是复杂的任务,有一定要求(比如性能要求)的任务,那就要用第三方库,比如Beautiful Soup,不过这个库我没用过,有时间研究一下,然后再和大家分享一下我的学习习得。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-08-28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档