使用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科学计算之Pandas详解
Jan 15 Python
Python学习小技巧之利用字典的默认行为
May 20 Python
Python实现螺旋矩阵的填充算法示例
Dec 28 Python
python获取网页中所有图片并筛选指定分辨率的方法
Mar 31 Python
Django实战之用户认证(用户登录与注销)
Jul 16 Python
flask框架自定义过滤器示例【markdown文件读取和展示功能】
Nov 08 Python
Python 中判断列表是否为空的方法
Nov 24 Python
如何将 awk 脚本移植到 Python
Dec 09 Python
Python class的继承方法代码实例
Feb 14 Python
基于Python实现视频的人脸融合功能
Jun 12 Python
Elasticsearch py客户端库安装及使用方法解析
Sep 14 Python
python爬虫scrapy基本使用超详细教程
Feb 20 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
PHP array_flip() 删除重复数组元素专用函数
2010/05/16 PHP
thinkPHP和onethink微信支付插件分享
2019/08/11 PHP
jQuery+CSS实现菜单滑动伸展收缩(仿淘宝)
2013/03/22 Javascript
查询json的数据结构的8种方式简介
2014/03/10 Javascript
JavaScript中输出标签的方法
2014/08/27 Javascript
JavaScript错误处理
2015/02/03 Javascript
js数组常见操作及数组与字符串相互转化实例详解
2015/11/10 Javascript
window.location.reload 刷新使用分析(去对话框)
2015/11/11 Javascript
KnockoutJS 3.X API 第四章之表单textInput、hasFocus、checked绑定
2016/10/11 Javascript
localStorage的黑科技-js和css缓存机制
2017/02/06 Javascript
zTree获取当前节点的下一级子节点数实例
2017/09/05 Javascript
Vue.js用法详解
2017/11/13 Javascript
JS实现的贪吃蛇游戏完整实例
2019/01/18 Javascript
详解vue的数据劫持以及操作数组的坑
2019/04/18 Javascript
JQuery获取可视区尺寸和文档尺寸及制作悬浮菜单示例
2019/05/14 jQuery
在layui中对table中的数据进行判断(0、1)转换为提示信息的方法
2019/09/28 Javascript
vue点击Dashboard不同内容 跳转到同一表格的实例
2020/11/13 Javascript
Webpack3+React16代码分割的实现
2021/03/03 Javascript
[03:16]DOTA2完美大师赛小组赛精彩集锦
2017/11/22 DOTA
推荐11个实用Python库
2015/01/23 Python
老生常谈python函数参数的区别(必看篇)
2017/05/29 Python
Python中.join()和os.path.join()两个函数的用法详解
2018/06/11 Python
python基础学习之如何对元组各个元素进行命名详解
2018/07/12 Python
Python 正则表达式爬虫使用案例解析
2019/09/23 Python
python进程间通信Queue工作过程详解
2019/11/01 Python
详解python tkinter 图片插入问题
2020/09/03 Python
matplotlib 范围选区(SpanSelector)的使用
2021/02/24 Python
50个强大璀璨的CSS3/JS技术运用实例
2010/02/27 HTML / CSS
让IE6、IE7、IE8支持CSS3的脚本
2010/07/20 HTML / CSS
成人大专生实习期的自我评价
2013/10/02 职场文书
病人家属写给医院的感谢信
2015/01/23 职场文书
晚会开幕词
2015/01/28 职场文书
简爱电影观后感
2015/06/10 职场文书
关于环保的宣传稿
2015/07/23 职场文书
Oracle删除归档日志及添加定时任务
2022/06/28 Oracle
一文解答什么是MySQL的回表
2022/08/05 MySQL