SGMLParser是sgmllib的一个类,使用的时候我们只需要重载这个类,并在子类中对html文件做具体处理即可。用自己的方法覆盖原有的方法,这样我们可以从html网页文件中轻松取到想要的数据,然后写进自己定义的数据结构中,便于在前端使用这些数据。
SGMLParser 可以把 HTML 分解成有用的片段, 比如开始标记start_tagname(self, attrs)和结束标记end_tagname(self)。
tagname是标签名称,比如当遇到<table>
标签,就会调用start_table
,遇到</table>
标签,就会调用 end_table
,attrs时标签的参数(属性),以列表[(attribute, value), (attribute, value), …]的形式传回。我们需要哪些标签中的数据内容就在SGMLParser子类中重载这些标签对应的函数(方法)。
SGMLParser是python2.x版本自带的模块,python3.x后都集成在模块htmlParser中,不过使用方法大同小异。 我使用的centos6.4系统,自带的python2.6版本,因此使用了SGMLParser。
可用处理函数:
- *开始标记 (Start tag)
开始一个块的 HTML 标记,像<html>
,<head>
,<body>
或<table>
等,或是一个独一的标记,<br>
或<img>
等。当它找到一个开始标记 tagname,SGMLParser 将查找名为 start_tagname 的方法。如果找到了,SGMLParser 会使用这个标记的属性列表来调用这个方法;否则,它用这个标记的名字和属性列表来调用 unknown_starttag 方法。 - 结束标记 (End tag)
结束一个块的 HTML 标记,像</html>
,</head>
,</body>
或</table>
等。当找到一个结束标记时,SGMLParser 将查找名为 end_tagname 的方法。如果找到,SGMLParser 调用这个方法,否则它使用标记的名字来调用 unknown_endtag 。 - 注释 (Comment)
HTML 注释, 包括在<!-- ... -->
之间。当找到,SGMLParser 用注释内容来调用 handle_comment。 - 实体引用 (Entity reference)
HTML 实体,如©
。当找到,SGMLParser 使用 HTML 实体的名字来调用 handle_entityref 。 - 处理指令 (Processing instruction)
HTML 处理指令,包括在<? ... >
之间。当找到,SGMLParser 用处理指令内容来调用 handle_pi。 - 声明 (Declaration)
HTML 声明,如 DOCTYPE,包括在<! ... >
之间。当找到,SGMLParser 用声明内容来调用 handle_decl。 - 文本数据 (Text data)
文本块。不满足其它 7 种类别的任何东西。当找到,SGMLParser 用文本来调用 handle_data。*
实例如下:
1.取厂商一每张表的标题和标题id。
2.表格源码:
<h4 id="tb-0" >姓名1</h4>
<table class="mytable">
<tr>
<td>序号</td>
<td>姓名</td>
<td>性别</td>
<td>身高</td>
<td>体重</td>
</tr>
<tr>
<td>1</td>
<td>花花</td>
<td>男</td>
<td>180</td>
<td>54kg</td>
</tr>
<tr>
<td>2</td>
<td>吉吉</td>
<td>女</td>
<td>26</td>
<td>55kg</td>
</tr>
<tr>
<td>3</td>
<td>呼呼</td>
<td>男</td>
<td>170</td>
<td>66kg</td>
</tr>
</table>
<h4 id="tb-1" >姓名2</h4>
<table class="mytable">
<tr>
<td>序号</td>
<td>姓名</td>
<td>性别</td>
<td>身高</td>
<td>体重</td>
</tr>
<tr>
<td>1</td>
<td>花花</td>
<td>男</td>
<td>180</td>
<td>54kg</td>
</tr>
<tr>
<td>2</td>
<td>吉吉</td>
<td>女</td>
<td>26</td>
<td>55kg</td>
</tr>
<tr>
<td>3</td>
<td>呼呼</td>
<td>男</td>
<td>170</td>
<td>66kg</td>
</tr>
</table>
3.重载SGMLParser类
from sgmllib import SGMLParser
class AppData(SGMLParser):
def reset(self):
SGMLParser.reset(self)
#初始化 td顺序、表id
#self.found_td=0
#self.found_table=0
#self.is_tr=0
#self.is_table = False
self.is_h4 = False
self.tableDict={}
'''
def start_table(self,attrs):
#遇到<table>标签时设置状态
self.is_table = True
self.found_table+=1
def end_table(self):
#遇到</table>标签时设置状态
self.is_table = False
'''
def start_h4(self,attrs):
#遇到h4标签,状态变为真
self.is_h4 = True
self.is_tr=0
self.tableId=attrs[0][1]
#id补全两位,便于排序
s = int(self.tableId[3:])
self.tableId = 'tb-%02d'%s
#排除id不是td开头的表id
if -1!=self.tableId.find('tb-'):
self.flag=True
else:
self.flag=False
def end_h4(self):
self.is_h4 = False
'''
def start_tr(self,attrs):
##遇到一个tr标签,found_tr加1
self.is_tr+=1
def end_tr(self):
self.found_td=0
def start_td(self,attrs):
#遇到一个td标签,found_td加1
self.found_td+=1
#遇到td标签设置rowspan属性为true。
#遍历td标签
for rowspanTag,rowspanValue in attrs:
#确定进入了<td rowspan="">
if rowspanTag == 'rowspan' and self.is_tr > 1:
self.is_rowspan = True
'''
def handle_data(self,text):
#创建表结构字典
if self.is_h4==True and self.flag==True:
if self.tableId not in tableDict:
#Tableid补全为两位,用于排序
s = int(self.tableId[3:])
tableId = 'td-%02d'%s
tableDict[tableId] = text.strip()
return self.tableDict,self.tableId
#注意不能return全局变量。
方法与思路:
遇到状态变化的标签,到标签对应的函数处设置状态标志,根据状态 标志判断。
上面只是一部分测试代码,实际情况要比这复杂些,不过都是按照这个思路来取数据的。
实际我要去从多家厂商提供的文件中取数据,当然不用多次写相同的代码,为此专门写了一个实例化类的函数。
如下:
def parserText(appfilename):
#解析AppData.html文件
appfileObj=open(appfilename)
fileText=appfileObj.read()
AppFile=AppData()
AppFile.feed(fileText)
nameDict,idDict=AppFile.handle_data(fileText)
appfileObj.close()
return nameDict,idDict
使用所取数据时直接调用上面的函数即可。
- feed():解析函数,多html文件进行解析。
每天进步一点点,开心一点点,快乐一点点。