• 自己动手实现html去标签和文本提取


    随意观看


    工具准备

    • python3.6
    • 正则表达式(别的语言思路一样,容易借鉴)

    python正则表达式:flags的应用

    这里主要介绍一下re.compile(pattern[, flags])里面的flags用法

    标识符 作用
    re.I 忽略大小写
    re.L 表示特殊字符集 w, W, , B, s, S 依赖于当前环境
    re.M 多行模式
    re.S ' . '并且包括换行符在内的任意字符(注意:' . '不包括换行符)
    re.U 表示特殊字符集 w, W, , B, d, D, s, S 依赖于 Unicode 字符属性数据库

    特别强调re.Ire.S的用法

    1. 众所周知,html标签是大小写不敏感的,所以我们需要re.I
    2. 其次html中<style>..</style><sript>..</scipt>等一些标签里面是包含换行符的。而我们为了保留原来文本的特点包括换行符,所以需要re.S.可以匹配换行符

    清洗全角和半角字符

    实现字符的清洗工作,否则,jieba词库会将全角数字全部分开。而且,清洗后的半角文本更适合观看

    小姿势

    中文文字永远是全角,只有英文字母、数字键、符号键才有全角半角的概念,一个字母或数字占一个汉字的位置叫全角,占半个汉字的位置叫半角

    全角半角转换说明

    1. 全角字符unicode编码从65281~65374 (十六进制 0xFF01 ~ 0xFF5E)
    2. 半角字符unicode编码从33~126 (十六进制 0x21~ 0x7E)
    3. 空格比较特殊,全角为 12288(0x3000),半角为 32(0x20)

    代码实现

    def Q2B(_char):#全角转半角
        if 65281<=ord(_char)<=65374:
            _char = chr(ord(_char)-65248)
        elif ord(_char)==12288:
            _char = chr(32)
        return _char
    
    def isQ(Char):
        return True if (65281<=ord(Char)<=65374 or ord(Char)==12288) else False
    
    def B2Q(_char):#半角转全角
        if 33<=ord(_char)<=126:
            _char = chr(ord(_char)+65248)
        elif ord(_char)==32:
            _char = chr(12288)
        return _char
    
    def isB(Char):
        return True if (33<=ord(Char)<=126 or ord(Char)==32) else False
    

    网页字符实体

    标准的html代码中的文本内容是不会出现'<'/' '等这些字符的。现在很多工具都会将网页文本内容处理成标准形式再发布。我们这里讨论的就是标准的html代码及文本内容

    html字符实体查询地址

    为了方便讨论,我们这里取了几个常用的作为示范,并且构造以下dict

    html_char = {}
    html_char['&quot;'] = html_char['&#34;']='"'
    html_char['&apos;'] = html_char['&#39;'] = "'"
    html_char['&amp;'] = html_char['&#38;'] = '&'
    html_char['&lt;'] = html_char['&#60;'] = '<'
    html_char['&gt;'] = html_char['&#62;'] = '>'
    html_char['&nbsp;'] = html_char['&#160;']= ' '
    

    Code实现

    难点重点就在这里,做了很多准备工作,幸好python比较方便,其他语言的玩家可以借鉴一下思路

    正则Code实现去标签[1]

        ...
        #CDATA 部分由 "<![CDATA[" 开始,由 "]]>" 结束:
        cdata_rule = re.compile(r'<![CDATA[.*]]>',re.I | re.S)
    
        #去除脚本(随时会出现)
        script_rule = re.compile(r'<script.*?</script>',re.I | re.S)
    
        #取出<head>..</head>和中间的内容,style也在里面,不需要再写了
        head_rule = re.compile(r'<head.*?/head>',re.I | re.S)
    
        #为了以防一些文本不是全部截取html代码,还是写一下以防万一
        style_rule = re.compile(r'<style.*?/style>',re.I | re.S)
    
        #处理注释
        comment_rule = re.compile(r'<!.*?>',re.I | re.S)
        
        #处理换行
        br_rule = re.compile(r'<brs*?/{0,1}>',re.I)
    
        #html标签
        html_rule = re.compile(r'<.*?/{0,1}>',re.I)
        ...
    

    正则Code实现去字符实体

        ...
        global html_char
        letter_char = re.compile(r'&[a-z]+;',re.I)
        for char in letter_char.findall(raw):
            raw = re.sub(char,html_char[char],raw)
    
        number_char = re.compile(r'&#d+;',re.I)
        for char in number_char.findall(raw):
            raw = re.sub(char,html_char[char],raw)
        ...
    

    全部代码(含测试文本)

    import re
    
    html_char = {}
    html_char['&quot;'] = html_char['&#34;']='"'
    html_char['&apos;'] = html_char['&#39;'] = "'"
    html_char['&amp;'] = html_char['&#38;'] = '&'
    html_char['&lt;'] = html_char['&#60;'] = '<'
    html_char['&gt;'] = html_char['&#62;'] = '>'
    html_char['&nbsp;'] = html_char['&#160;']= ' '
    
    def Q2B(_char):#全角转半角
        if 65281<=ord(_char)<=65374:
            _char = chr(ord(_char)-65248)
        elif ord(_char)==12288:
            _char = chr(32)
        return _char
    
    def isQ(Char):
        return True if (65281<=ord(Char)<=65374 or ord(Char)==12288) else False
    
    def B2Q(_char):#半角转全角
        if 33<=ord(_char)<=126:
            _char = chr(ord(_char)+65248)
        elif ord(_char)==32:
            _char = chr(12288)
        return _char
    
    def isB(Char):
        return True if (33<=ord(Char)<=126 or ord(Char)==32) else False
    
    #定义一个装饰器,可有可无
    def log(clean_html):
        def info(*args, **kw):
            print("The text after processing:")
            return clean_html(*args, **kw)
        return info
    
    @log
    def clean_html(html_str,special_char=None,to_char=None):
    
        #这里留个接口,处理特殊字符串
        if special_char:
            special_rule = re.compile('|'.join(set(special_char)))
            if not to_char:
                to_char = ''
    
        #CDATA 部分由 "<![CDATA[" 开始,由 "]]>" 结束:
        cdata_rule = re.compile(r'<![CDATA[.*]]>',re.I | re.S)
    
        #去除脚本(随时会出现)
        script_rule = re.compile(r'<script.*?</script>',re.I | re.S)
    
        #取出<head>..</head>和中间的内容,style也在里面,不需要再写了
        head_rule = re.compile(r'<head.*?/head>',re.I | re.S)
    
        #为了以防一些文本不是全部截取html代码,还是写一下以防万一
        style_rule = re.compile(r'<style.*?/style>',re.I | re.S)
    
        #处理注释
        comment_rule = re.compile(r'<!.*?>',re.I | re.S)
        
        #处理换行
        br_rule = re.compile(r'<brs*?/{0,1}>',re.I)
    
        #html标签
        html_rule = re.compile(r'<.*?/{0,1}>',re.I)
    
        if special_char:
            raw = special_rule.sub(to_char,html_str)
        else:
            raw = html_str
    
        raw = cdata_rule.sub('',raw)
        raw = script_rule.sub('',raw)
        raw = head_rule.sub('',raw)
        raw = style_rule.sub('',raw)
        raw = comment_rule.sub('',raw)
        raw = br_rule.sub('
    ',raw)
        raw = html_rule.sub('',raw)
    
        global html_char
        letter_char = re.compile(r'&[a-z]+;',re.I)
        for char in letter_char.findall(raw):
            raw = re.sub(char,html_char[char],raw)
    
        number_char = re.compile(r'&#d+;',re.I)
        for char in number_char.findall(raw):
            raw = re.sub(char,html_char[char],raw)
    
        raw_list = list(raw)
        for i in range(len(raw_list)):
            if isQ(raw_list[i]):
                raw_list[i] = Q2B(raw_list[i])
        raw = ''.join(raw_list)
        
        return raw
    
    def test():
        test_html = """
            
        <div id="sidebar">
    
        <div id="tools">
        <h5 id="tools_example"><a href="/example/xmle_examples.asp">&nbsp;XML 实例,特殊字符:15(处理之后应该没有了)</a></h5>
        <h5 id="tools_quiz"><a href="/xml/xml_quiz.asp">&#60;XML 测验&gt;</a></h5>
        <h3>&#39;vevev&#39;</h3>
        </div>
    
        <div id="ad">
        <script type="text/javascript"><!--
        google_ad_client = "ca-pub-3381531532877742";
        /* sidebar-160x600 */
        google_ad_slot = "3772569310";
        google_ad_width = 160;
        google_ad_height = 600;
        //-->
        </script>
        <script type="text/javascript"
        src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
        </script>
        </div>
    
        </div>
        """
    
        print(clean_html(test_html,'】15'))
    
    if __name__=='__main__':
        test()
    

    进一步

    其他脚本引用

    在python的其他程序中,可以直接from clean_html import clean_html进行方便的调用(假设这个脚本名字为clean_html.py)

    完善

    1. 补充字符实体(可以用爬虫爬下来,有空弄一下)
    2. html标签可能因为前端框架不同而有所差异(虽然不大)。但是都有规律,如<Vue>..</Vue>等,有规律,正则表达式就容易构建了

    1. 代码备注以标明作用 ↩︎

  • 相关阅读:
    bzoj1455-罗马游戏
    bzoj1206-[HNOI2005]虚拟内存
    bzoj2762-[JLOI2011]不等式组
    bzoj2729-[HNOI2012]排队
    [模板] 高精度加/减/乘
    bzoj1013-[JSOI2008]球形空间产生器
    bzoj1002-[FJOI2007]轮状病毒
    什么是Redis缓存穿透、缓存雪崩和缓存击穿
    CentOS 7 中英文桌面安装步骤详细图解
    Redis数据操作
  • 原文地址:https://www.cnblogs.com/AsuraDong/p/clean_html.html
Copyright © 2020-2023  润新知