python:SGMLParser-巧妙从html文件中取到所需数据

版权声明:转载请标明出处 https://blog.csdn.net/w1418899532/article/details/84378916

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 实体,如 &copy;。当找到,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文件进行解析。

每天进步一点点,开心一点点,快乐一点点。

猜你喜欢

转载自blog.csdn.net/w1418899532/article/details/84378916