htmlparser 获取某a标签地址_使用HTMLParser解析SGML文件

aa1c7ff45020225d2e329de43a265a08.png

一.简介

在做FASPell复现时候需要多搜集一些训练语料。我把目光转向了SIGHAN举行的CSC比赛当中,其中SIGHAN14和SIGHAN15提供了共5000条训练语句,而且他们的格式一样,使用了相同的SGML语言来标记。

二.提醒

网上较多的是使用sgmllib包中的SGMLParser来进行SGML文件的解析,但由于sgmillib只在Python2中可用,且sgmllib包的下载也成问题,因此最后选择使用HTMLParser。

三.HTMLParser使用

HtmlParser是一个类,在使用时一般继承它然后重载它的方法,来达到解析所需数据的目的。

1.常用属性

lasttag,保存上一个解析的标签名,是字符串。

2.常用方法

handle_starttag(tag, attrs) ,处理开始标签,比如<div>这里的attrs获取到的是属性列表,属性以元组的方式展示handle_endtag(tag) ,处理结束标签,比如</div>。

handle_startendtag(tag, attrs) ,处理自己结束的标签,如<img />。

handle_data(data) ,处理数据,标签之间的文本。

handle_comment(data) ,处理注释,<!-- -->之间的文本。

3.基本使用

官方代码示例

from html.parser import HTMLParser
 
class MyHTMLParser(HTMLParser):
    def handle_starttag(self, tag, attrs):
        print("Encountered a start tag:", tag)
 
    def handle_endtag(self, tag):
        print("Encountered an end tag :", tag)
 
    def handle_data(self, data):
        print("Encountered some data  :", data)
 
parser = MyHTMLParser()
parser.feed('<html><head><title>Test</title></head>'
            '<body><h1>Parse me!</h1></body></html>')

输出为

Encountered a start tag: html
Encountered a start tag: head
Encountered a start tag: title
Encountered some data  : Test
Encountered an end tag : title
Encountered an end tag : head
Encountered a start tag: body
Encountered a start tag: h1
Encountered some data  : Parse me!
Encountered an end tag : h1
Encountered an end tag : body
Encountered an end tag : html

4.实用案例

以下的实用案例均在上面的代码中修改对应函数,每个实例都是单独的。

  解析的sgml文件如下:

<ESSAY title="给卫生局的信-有机蔬菜的食品安全">
<TEXT>
<PASSAGE id="B2-1443-1">我希望以他们的安全保証书来解决这个问题。不能提出安全保証书的话,应该停止营业。</PASSAGE>
</TEXT>
<MISTAKE id="B2-1443-1" location="11">
<WRONG>保証书</WRONG>
<CORRECTION>保证书</CORRECTION>
</MISTAKE>
</ESSAY>

1.获取属性的函数,是个静态函数,新增的。直接定义在类中,返回属性名对应的属性

def _attr(attrlist, attrname):
 for attr in attrlist:
     if attr[0] == attrname:
         return attr[1]
 return None

2. 获取所有WRONG标签的文本,最简单方法只修改handle_data

def handle_data(self, data):
 # 此处标签不区分大小写,统一用小写字母即可,大写字母会报错
 if self.lasttag == 'wrong':
     print("Encountered WRONG data  :", data)

3. 获取PASSAGE编号(id)为B2-1443-1的PASSAGE标签的文本。使用了案例1,增加一个实例属性作为标志,选取需要的标签

def __init__(self):
 HTMLParser.__init__(self)
 self.flag = False
def handle_starttag(self, tag, attrs):
 if tag == 'passage' and _attr(attrs, 'id') == 'B2-1443-1':
     self.flag = True  
def handle_data(self, data):
 if self.flag == True:
     print("Encountered PASSAGE OF B2-1443-1 data  :", data)

4. 获取MISTAKE标签的属性列表

def handle_starttag(self, tag, attrs):
 if tag == 'mistake':
     print("Encountered MISTAKE attrs  :", attrs) 

5. 获取PASSAGE标签的id属性

def handle_starttag(self, tag, attrs):
 if tag == 'passage' and _attr(attrs, 'id'):
     print("Encountered p class  :", _attr(attrs, 'id'))

6. 获取TEXT标签下的PASSAGE标签的文本

def __init__(self):
 HTMLParser.__init__(self)
 self.in_text = False
def handle_starttag(self, tag, attrs):
 if tag == 'text':
     self.in_text = True
def handle_data(self, data):
 if self.in_text == True and self.lasttag == 'passage':
     print("Encountered PASSAGE data  :", data)

四.完整代码

这是用来处理SIGHAN15中SGML数据的完整代码,主要是解析SGML文件将他们转化成FASPell中使用的训练数据格式。

待处理sgml文件格式

"""
<ESSAY title="给卫生局的信-有机蔬菜的食品安全">
<TEXT>
<PASSAGE id="B2-1443-1">我希望以他们的安全保証书来解决这个问题。不能提出安全保证书的话,应该停止营业。</PASSAGE>
</TEXT>
<MISTAKE id="B2-1443-1" location="11">
<WRONG>保証书</WRONG>
<CORRECTION>保证书</CORRECTION>
</MISTAKE>
</ESSAY>
"""

目标格式

num    wrong_string    correct_string
1 我希望以他们的安全保証书来解决这个问题。不能提出安全保证书的话,应该停止营业。    我希望以他们的安全保证书来解决这个问题。不能提出安全保证书的话,应该停止营业。 

代码块

from html.parser import HTMLParser
import re

def attr(attrlist, attrname):
    for attr in attrlist:
        if attr[0] == attrname:
            return attr[1]
    return None

class MyHTMLParser(HTMLParser):
 
    def __init__(self):
        HTMLParser.__init__(self)
        self.in_text = False
        self.in_mistake = False
        self.passage = {}
        self.wrong = {}
        self.correction = {}
        self.listid = []
        self.id = ""
 
    def handle_starttag(self, tag, attrs):
        if tag == 'text':
            self.in_text = True
        if tag == 'passage' and attr(attrs, 'id'):
            self.id = attr(attrs, 'id')
            if self.passage.get(self.id) == None:
                 self.passage[self.id] = []
        if tag == 'mistake':
            self.in_mistake = True
        if tag == 'mistake' and attr(attrs, 'id'):
            self.id = attr(attrs, 'id')
            if self.wrong.get(self.id) == None:
                self.wrong[self.id] = []
            if self.correction.get(self.id) == None:
                self.correction[self.id] = [] 
 
    def handle_data(self, data):
        if self.in_text == True and self.lasttag == 'passage':
            if len(str(data)) >= 2:
                self.passage[self.id].append(data)
        if self.in_mistake == True and self.lasttag == 'wrong':
            if len(str(data)) >= 2 and str(data) not in self.wrong[self.id]:
                self.wrong[self.id].append(data)
        if self.in_mistake == True and self.lasttag == 'correction':
            if len(str(data)) >= 2 and str(data) not in self.correction[self.id]:
                self.correction[self.id].append(data)
            print(self.correction)
 
    def handle_endtag(self, tag):
        if tag == 'text':
            self.in_text = False
            self.id = ""
 
        if tag == 'mistake':
            self.in_mistake = False
            self.id = ""

def write_to_file(correction,wrong,passage):
    with open('median_file.txt','a',encoding='utf-8') as file:
        for k,v in passage.items():
            origin_string = str(v[0])
            wrong_list = []
            correct_list = []
            if k in wrong and k in correction:
                wrong_list.extend(wrong[k])
                correct_list.extend(correction[k])
            count = len(wrong_list)
            if count == 0:
                continue
            if count == len(correct_list):
                tmp_string = origin_string
                for i in range(count):
                    corr_string = re.sub(wrong_list[i],correct_list[i],tmp_string)
                    tmp_string = corr_string
                num = 0
                if len(corr_string) != len(origin_string):
                    continue
                for i in range(len(corr_string)):
                    if corr_string[i] != origin_string[i]:
                        num += 1
                file.write('{}t{}t{}n'.format(num,origin_string,corr_string))

if __name__ == "__main__":
    files = open('sighan15.sgml','r', encoding='utf-8')
    myhtmlparser = MyHTMLParser()
    myhtmlparser.feed(files.read())
    write_to_file(myhtmlparser.correction,myhtmlparser.wrong,myhtmlparser.passage)

五. 参考

1.Python爬虫常用之HtmlParser - Masako - 博客园

2.https://docs.python.org/3/library/html.parser.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值