使用python提取html文件中的特定数据的实现代码


Posted in Python onMarch 24, 2013

例如 具有如下结构的html文件

<div class='entry-content'> 
<p>感兴趣内容1</p> 
<p>感兴趣内容2</p> 
…… 
<p>感兴趣内容n</p> 
</div> 
<div class='content'> 
<p>内容1</p> 
<p>内容2</p> 
…… 
<p>内容n</p> 
</div>

我们尝试获得'感兴趣内容'

对于文本内容,我们保存到IDList中。
可是如何标记我们遇到的文本是感兴趣的内容呢,也就是,处于

<div class='entry-content'> 
<p>这里的内容</p> 
<p>还有这里</p> 
…… 
<p>以及这里的内容</p> 
</div>

思路如下

  1. 遇到<div class='entry-content'> 设置标记flag = True
  2. 遇到</div>后 设置标记flag = False
  3. 当flag 为True时遇到<p> 设置标记getdata = True
  4. 遇到</p> 且getdata = True,设置getdata = False

python为我们提供了SGMLParser类,SGMLParser 将 HTML 分析成 8 类数据[1],然后对每一类调用单独的方法:使用时只需继承SGMLParser 类,并编写页面信息的处理函数。

可用的处理函数如下

  • 开始标记 (Start tag) 
是一个开始一个块的 HTML 标记,象 <html>,<head>,<body> 或 <pre> 等,或是一个独一的标记,象 <br> 或 <img> 等。当它找到一个开始标记 tagname,SGMLParser 将查找名为 start_tagname 或 do_tagname 的方法。例如,当它找到一个 <pre> 标记,它将查找一个 start_pre 或 do_pre 的方法。如果找到了,SGMLParser 会使用这个标记的属性列表来调用这个方法;否则,它用这个标记的名字和属性列表来调用 unknown_starttag 方法。 
  • 结束标记 (End tag) 
是结束一个块的 HTML 标记,象 </html>,</head>,</body> 或 </pre> 等。当找到一个结束标记时,SGMLParser 将查找名为 end_tagname 的方法。如果找到,SGMLParser 调用这个方法,否则它使用标记的名字来调用 unknown_endtag 。 
  • 字符引用 (Character reference) 
用字符的十进制或等同的十六进制来表示的转义字符,象  。当找到,SGMLParser 使用十进制或等同的十六进制字符文本来调用 handle_charref 。 
  • 实体引用 (Entity reference) 
HTML 实体,象 ©。当找到,SGMLParser 使用 HTML 实体的名字来调用 handle_entityref 。 
  • 注释 (Comment) 
HTML 注释, 包括在 <!-- ... -->之间。当找到,SGMLParser 用注释内容来调用 handle_comment。 
  • 处理指令 (Processing instruction) 
HTML 处理指令,包括在 <? ... > 之间。当找到,SGMLParser 用处理指令内容来调用 handle_pi。 
  • 声明 (Declaration) 
HTML 声明,如 DOCTYPE,包括在 <! ... >之间。当找到,SGMLParser 用声明内容来调用 handle_decl。 
  • 文本数据 (Text data) 
文本块。不满足其它 7 种类别的任何东西。当找到,SGMLParser 用文本来调用 handle_data。 

综上,的到如下代码

from sgmllib import SGMLParser
class GetIdList(SGMLParser):
    def reset(self):
        self.IDlist = []
        self.flag = False
        self.getdata = False
        SGMLParser.reset(self)    def start_div(self, attrs):
        for k,v in attrs:#遍历div的所有属性以及其值
            if k == 'class' and v == 'entry-content':#确定进入了<div class='entry-content'>
                self.flag = True
                return

    def end_div(self):#遇到</div>
 self.flag = False
    def start_p(self, attrs):
        if self.flag == False:
            return
        self.getdata = True
    def end_p(self):#遇到</p>
        if self.getdata:
            self.getdata = False
    def handle_data(self, text):#处理文本
        if self.getdata:
            self.IDlist.append(text)
    def printID(self):
        for i in self.IDlist:
            print i

上面的思路存在一个bug
遇到</div>后 设置标记flag = False
如果遇到div嵌套怎么办?

<div class='entry-content'><div>我是来捣乱的</div><p>感兴趣</p></div>

在遇到第一个</div>之后标记flag = False,导致无法的到‘感兴趣内容'。
怎么办呢?如何判断遇到的</div>是和<div class='entry-content'>匹配的哪个呢?
很简单,</div>和<div>是对应的,我们可以记录他所处的层数。进入子层div verbatim加1,退出子层div  verbatim减1.这样就可以判断是否是同一层了。

修改后 如下

from sgmllib import SGMLParser
class GetIdList(SGMLParser):
    def reset(self):
        self.IDlist = []
        self.flag = False
        self.getdata = False
        self.verbatim = 0
        SGMLParser.reset(self)    def start_div(self, attrs):
        if self.flag == True:
            self.verbatim +=1 #进入子层div了,层数加1
            return
        for k,v in attrs:#遍历div的所有属性以及其值
            if k == 'class' and v == 'entry-content':#确定进入了<div class='entry-content'>
                self.flag = True
                return

    def end_div(self):#遇到</div>
        if self.verbatim == 0:
            self.flag = False
        if self.flag == True:#退出子层div了,层数减1
            self.verbatim -=1
    def start_p(self, attrs):
        if self.flag == False:
            return
        self.getdata = True
    def end_p(self):#遇到</p>
        if self.getdata:
            self.getdata = False
    def handle_data(self, text):#处理文本
        if self.getdata:
            self.IDlist.append(text)
    def printID(self):
        for i in self.IDlist:
            print i

最后  建立了我们自己的类GetIdList后如何使用呢?
简单建立实例 t = GetIdList()
the_page为字符串,内容为html
t.feed(the_page)#对html解析

t.printID()打印出结果

全部测试代码为

from sgmllib import SGMLParser
class GetIdList(SGMLParser):
    def reset(self):
        self.IDlist = []
        self.flag = False
        self.getdata = False
        self.verbatim = 0
        SGMLParser.reset(self)    def start_div(self, attrs):
        if self.flag == True:
            self.verbatim +=1 #进入子层div了,层数加1
            return
        for k,v in attrs:#遍历div的所有属性以及其值
            if k == 'class' and v == 'entry-content':#确定进入了<div class='entry-content'>
                self.flag = True
                return

    def end_div(self):#遇到</div>
        if self.verbatim == 0:
            self.flag = False
        if self.flag == True:#退出子层div了,层数减1
            self.verbatim -=1
    def start_p(self, attrs):
        if self.flag == False:
            return
        self.getdata = True
    def end_p(self):#遇到</p>
        if self.getdata:
            self.getdata = False
    def handle_data(self, text):#处理文本
        if self.getdata:
            self.IDlist.append(text)
    def printID(self):
        for i in self.IDlist:
            print i

##import urllib2
##import datetime
##vrg = (datetime.date(2012,2,19) - datetime.date.today()).days
##strUrl = 'http://www.nod32id.org/nod32id/%d.html'%(200+vrg)
##req = urllib2.Request(strUrl)#通过网络获取网页
##response = urllib2.urlopen(req)
##the_page = response.read()
the_page ='''<html>
<head>
<title>test</title>
</head>
<body>
<h1>title</h1>
<div class='entry-content'>
<div class= 'ooxx'>我是来捣乱的</div>
<p>感兴趣内容1</p>
<p>感兴趣内容2</p>
……
<p>感兴趣内容n</p>
<div class= 'ooxx'>我是来捣乱的2<div class= 'ooxx'>我是来捣乱的3</div></div>
</div>
<div class='content'>
<p>内容1</p>
<p>内容2</p>
……
<p>内容n</p>
</div>
</body>
</html>
'''
lister = GetIdList()
lister.feed(the_page)
lister.printID()

执行后 输出为

感兴趣内容1
感兴趣内容2
感兴趣内容n

参考文献

[1] 深入 Python:Dive Into Python 中文版

Python 相关文章推荐
python操作xml文件示例
Apr 07 Python
Python获取脚本所在目录的正确方法
Apr 15 Python
Python使用PyGreSQL操作PostgreSQL数据库教程
Jul 30 Python
python常规方法实现数组的全排列
Mar 17 Python
Python中处理字符串之endswith()方法的使用简介
May 18 Python
python自带的http模块详解
Nov 06 Python
python批量爬取下载抖音视频
Jun 17 Python
Python生成验证码、计算具体日期是一年中的第几天实例代码详解
Oct 16 Python
简单了解python装饰器原理及使用方法
Dec 18 Python
3种python调用其他脚本的方法
Jan 06 Python
python使用matplotlib的savefig保存时图片保存不完整的问题
Jan 08 Python
变长双向rnn的正确使用姿势教学
May 31 Python
python 切片和range()用法说明
Mar 24 #Python
python list中append()与extend()用法分享
Mar 24 #Python
python del()函数用法
Mar 24 #Python
python dict remove数组删除(del,pop)
Mar 24 #Python
python str与repr的区别
Mar 23 #Python
python 布尔操作实现代码
Mar 23 #Python
python 字符串split的用法分享
Mar 23 #Python
You might like
为什么夜间收到的中波电台比白天多
2021/03/01 无线电
jQuery学习笔记 获取jQuery对象
2012/09/19 Javascript
关于JavaScript与HTML的交互事件
2013/04/12 Javascript
框架页面高度自动刷新的Javascript脚本
2013/11/01 Javascript
javascript的switch用法注意事项分析
2015/02/02 Javascript
JQuery boxy插件在IE中边角图片不显示问题的解决
2015/05/20 Javascript
JS实现的页面自定义滚动条效果
2015/10/26 Javascript
React实现双向绑定示例代码
2016/09/19 Javascript
三种方式实现瀑布流布局
2017/02/10 Javascript
Node使用Sequlize连接Mysql报错:Access denied for user ‘xxx’@‘localhost’
2018/01/03 Javascript
JS实现简易换图时钟功能分析
2018/01/04 Javascript
Vue中的混入的使用(vue mixins)
2018/06/01 Javascript
在小程序中使用canvas的方法示例
2018/09/17 Javascript
Vue组件之单向数据流的解决方法
2018/11/10 Javascript
详解vue挂载到dom上会发生什么
2019/01/20 Javascript
JavaScript 性能提升之路(推荐)
2019/04/10 Javascript
JS实现根据详细地址获取经纬度功能示例
2019/04/16 Javascript
Python中的defaultdict模块和namedtuple模块的简单入门指南
2015/04/01 Python
在Python中编写数据库模块的教程
2015/04/29 Python
python实现简单点对点(p2p)聊天
2017/09/13 Python
完美解决Pycharm无法导入包的问题 Unresolved reference
2018/05/18 Python
Python 使用 environs 库定义环境变量的方法
2020/02/25 Python
python 数据分析实现长宽格式的转换
2020/05/18 Python
python爬取代理IP并进行有效的IP测试实现
2020/10/09 Python
python“静态”变量、实例变量与本地变量的声明示例
2020/11/13 Python
美国中小型企业领先的办公家具供应商:Office Designs
2016/11/26 全球购物
煤矿机修工岗位职责
2014/02/07 职场文书
小学生保护环境倡议书
2014/05/15 职场文书
房地产推广策划方案
2014/05/19 职场文书
会议欢迎标语
2014/06/30 职场文书
小学向国旗敬礼活动方案
2014/09/27 职场文书
员工教育培训协议书
2014/09/27 职场文书
税务干部个人整改措施思想汇报
2014/10/10 职场文书
2015年医药代表工作总结
2015/04/25 职场文书
春晚观后感
2015/06/11 职场文书
PYTHON使用Matplotlib去实现各种条形图的绘制
2022/03/22 Python