使用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 相关文章推荐
tensorflow学习笔记之简单的神经网络训练和测试
Apr 15 Python
详谈Pandas中iloc和loc以及ix的区别
Jun 08 Python
python的常用模块之collections模块详解
Dec 06 Python
用Python实现大文本文件切割的方法
Jan 12 Python
使用Python制作一个打字训练小工具
Oct 01 Python
pytorch使用 to 进行类型转换方式
Jan 08 Python
Pytorch 计算误判率,计算准确率,计算召回率的例子
Jan 18 Python
TensorFlow——Checkpoint为模型添加检查点的实例
Jan 21 Python
python实现交并比IOU教程
Apr 16 Python
Python爬虫入门教程02之笔趣阁小说爬取
Jan 24 Python
python+playwright微软自动化工具的使用
Feb 02 Python
详解Python中__new__方法的作用
Mar 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
什么是短波收听SWL
2021/03/01 无线电
PHP获取MAC地址的函数代码
2011/09/11 PHP
PHP实现简单数字分页效果
2015/07/26 PHP
PHP缓存工具XCache安装与使用方法详解
2018/04/09 PHP
PHP+Ajax简单get验证操作示例
2019/03/02 PHP
a标签的css样式四个状态
2021/03/09 HTML / CSS
Avengerls vs KG BO3 第一场2.18
2021/03/10 DOTA
javascript 出生日期和身份证判断大全
2008/11/13 Javascript
Javascript 判断函数类型完美解决方案
2009/09/02 Javascript
js中判断控件是否存在
2010/08/25 Javascript
js中匿名函数的N种写法
2010/09/08 Javascript
淘宝搜索框效果实现分析
2011/03/05 Javascript
精心挑选的12款优秀的基于jQuery的手风琴效果插件和教程
2012/08/22 Javascript
将json当数据库一样操作的javascript lib
2013/10/28 Javascript
jQuey将序列化对象在前台显示地实现代码(方法总结)
2016/12/13 Javascript
javascript 封装Date日期类实例详解
2017/05/28 Javascript
Angularjs添加排序查询功能的实例代码
2017/10/24 Javascript
详解Vue2.0组件的继承与扩展
2018/11/23 Javascript
vue 实现路由跳转时更改页面title
2019/11/05 Javascript
JavaScript 实现HTML DOM增删改查操作的常见方法详解
2020/01/04 Javascript
[00:36]DOTA2勇士令状莱恩声望物品——冥晶之厄展示
2018/05/25 DOTA
ssh批量登录并执行命令的python实现代码
2012/05/25 Python
改进Django中的表单的简单方法
2015/07/17 Python
浅析python递归函数和河内塔问题
2017/04/18 Python
Apache如何部署django项目
2017/05/21 Python
python实现一个简单的udp通信的示例代码
2019/02/01 Python
python多进程使用函数封装实例
2020/05/02 Python
Python的Tqdm模块实现进度条配置
2021/02/24 Python
Canvas 文字碰撞检测并抽稀的方法
2019/05/27 HTML / CSS
英国女装网上商店:I Saw It First
2018/10/18 全球购物
Hurley官方网站:扎根于海滩生活方式的全球青年文化品牌
2020/05/18 全球购物
《老王》教学反思
2014/02/23 职场文书
庆六一文艺汇演活动方案
2014/08/26 职场文书
仓库保管员岗位职责
2015/02/09 职场文书
获奖感言怎么写
2015/07/31 职场文书
项目中Nginx多级代理是如何获取客户端的真实IP地址
2022/05/30 Servers