使用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基本数据类型详细介绍
Mar 11 Python
Python脚本实现下载合并SAE日志
Feb 10 Python
python通过字典dict判断指定键值是否存在的方法
Mar 21 Python
通过Python 接口使用OpenCV的方法
Apr 02 Python
python对离散变量的one-hot编码方法
Jul 11 Python
Python Requests库基本用法示例
Aug 20 Python
Python 获取中文字拼音首个字母的方法
Nov 28 Python
使用pycharm设置控制台不换行的操作方法
Jan 19 Python
如何用C代码给Python写扩展库(Cython)
May 17 Python
使用selenium和pyquery爬取京东商品列表过程解析
Aug 15 Python
Python中bisect的使用方法
Dec 31 Python
scrapy爬虫:scrapy.FormRequest中formdata参数详解
Apr 30 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 eval函数用法总结
2012/10/31 PHP
phplot生成图片类用法详解
2015/01/06 PHP
PHP Post获取不到非表单数据的问题解决办法
2018/02/27 PHP
JavaScript中标识符提升问题
2015/06/11 Javascript
Javascript下拉刷新的简单实现
2017/02/14 Javascript
Angularjs实现下拉框联动的示例代码
2017/08/22 Javascript
浅谈Vue2.0中v-for迭代语法的变化(key、index)
2018/03/06 Javascript
react 国际化的实现代码示例
2018/09/14 Javascript
详解微信小程序自定义组件的实现及数据交互
2019/07/22 Javascript
在Vue中使用this.$store或者是$route一直报错的解决
2019/11/08 Javascript
[02:16]卖萌的僵尸 DOTA2神话信使飞僵小宝来袭
2014/03/24 DOTA
跟老齐学Python之不要红头文件(2)
2014/09/28 Python
Python解惑之True和False详解
2017/04/24 Python
Python实现自动登录百度空间的方法
2017/06/10 Python
python 读取摄像头数据并保存的实例
2018/08/03 Python
Python中collections模块的基本使用教程
2018/12/07 Python
python实现flappy bird游戏
2018/12/24 Python
python pyinstaller 加载ui路径方法
2019/06/10 Python
Pytorch实现GoogLeNet的方法
2019/08/18 Python
PyTorch的SoftMax交叉熵损失和梯度用法
2020/01/15 Python
Python object类中的特殊方法代码讲解
2020/03/06 Python
numpy的Fancy Indexing和array比较详解
2020/06/11 Python
Python实现像awk一样分割字符串
2020/09/15 Python
CSS3绘制有活力的链接下划线
2016/07/14 HTML / CSS
Exoticca英国:以最优惠的价格提供豪华异国情调旅行
2018/10/18 全球购物
WebSphere 应用服务器都支持哪些认证
2013/12/26 面试题
经典大学生求职信范文
2014/01/06 职场文书
消防安全标语
2014/06/07 职场文书
解除聘用合同证明书范本
2014/09/11 职场文书
公司委托书范本5篇
2014/09/20 职场文书
幼儿园小班个人工作总结
2015/02/12 职场文书
我的兄弟姐妹观后感
2015/06/15 职场文书
2016秋季幼儿园开学寄语
2015/12/03 职场文书
校园安全教育心得体会
2016/01/15 职场文书
尝试使用Python爬取城市租房信息
2022/04/12 Python
JavaScript架构搭建前端监控如何采集异常数据
2022/06/25 Javascript