【问题标题】:How to use Cleaner, lxml.html without returning div tag?如何在不返回 div 标签的情况下使用 Cleaner、lxml.html?
【发布时间】:2014-02-20 15:45:10
【问题描述】:

我有这个代码:

evil = "<script>malignus script</script><b>bold text</b><i>italic text</i>"
cleaner = Cleaner(remove_unknown_tags=False, allow_tags=['p', 'br', 'b'],
                  page_structure=True)
print cleaner.clean_html(evil)

我希望得到这个:

<b>bold text</b>italic text

但我却得到了这个:

<div><b>bold text</b>italic text</div>

是否有移除div标签包装的属性?

【问题讨论】:

    标签: python lxml.html


    【解决方案1】:

    lxml 期望您的 html 具有树结构,即单个根节点。如果没有,则添加它。

    【讨论】:

    • &lt;div&gt; 标签可以很容易地从返回的字符串中删除:cleanedText[5:-6]
    • 它并不总是&lt;div&gt;,如果你传递一个没有任何标签的纯字符串,cleaner.clean_html(s) 会将它包装到&lt;p&gt; 标签中。
    • 另外,您可能需要将它与page_structure=False 一起使用。
    • 这不能回答问题
    【解决方案2】:

    Cleaner 总是将结果包装在一个元素中。一个好的解决方案是手动解析 HTML 并将生成的文档对象发送给清洁器 - 然后结果也是一个文档对象,您可以使用 text_content 从根中提取文本。

    from lxml.html import document_fromstring
    from lxml.html.clean import Cleaner
    evil = "<script>malignus script</script><b>bold text</b><i>italic 
    text</i>"
    doc = document_fromstring(evil)
    cleaner = Cleaner(remove_unknown_tags=False, allow_tags=['p', 'br', 'b'],
                  page_structure=True)
    print cleaner.clean_html(doc).text_content()
    

    这也可以通过one liner 来完成

    【讨论】:

    • 在这个例子中,如果str&lt;b&gt;test&lt;/b&gt;,则有效的&lt;b&gt; 标签会被.text_content() 剥离
    • @Routhinator 哎呀。谢谢,我改一下
    【解决方案3】:

    这是我想出的。

    import lxml
    from lxml.html.clean import Cleaner
    
    def clean_html(html):
        if html:
            is_wrap_in_div = check_is_wrap_in_div(html)
    
            cleaner = Cleaner()
            html = cleaner.clean_html(html)
    
            if not is_wrap_in_div:
                html = remove_root_div(html)
    
        return html
    
    
    def check_is_wrap_in_div(html):
        is_wrapped = False
        try:
            tree = lxml.etree.fromstring(html)
            if tree.tag == 'div':
                return True
        except lxml.etree.XMLSyntaxError:
            pass
    
        return is_wrapped
    
    
    def remove_root_div(html):
        root_div_regex = r'^(\s*<div[\s\S]*?>)([\s\S]*)(<\/div>[\s\S]*?)$'
        return re.sub(root_div_regex, r'\2', html)
    
    # use it as
    cleaned_html = clean_html(evil_html)
    

    和单元测试

    class TestBase(unittest.TestCase):
        def test_check_is_wrap_in_div(self):
            with self.subTest('test html wrap in div'):
                self.assertTrue(
                    utils.check_is_wrap_in_div('<div></div>'),
                )
                self.assertTrue(
                    utils.check_is_wrap_in_div("""
                        <div>
                            <p>Hello</p>
                            <p>Test</p>
                        </div>
                    """)
                )
                self.assertTrue(
                    utils.check_is_wrap_in_div("""
                        <div class="test" style="color: blue;">
                            <p>Hello</p>
                            <p>Test</p>
                        </div>
                    """)
                )
                self.assertTrue(
                    utils.check_is_wrap_in_div("""
                        <div
                            class="test"
                            style="color: blue;"
                        >
                            <p>Hello</p>
                            <p>Test</p>
                        </div>
                    """)
                )
                self.assertTrue(
                    utils.check_is_wrap_in_div("""
                        <div
                            class="test"
                            style="color: blue;">
                            <p>Hello</p>
                            <p>Test</p>
                        </div>
                    """)
                )
                self.assertTrue(
                    utils.check_is_wrap_in_div("""
                        <div
                            class="test"
                            style="color: blue;">
                            <div>
                                <div>
                                    <p>Hello</p>
                                    <p>Test</p>
                                </div>
                            </div>
                            <div>
                                <p>Hi</p>
                            </div>
                        </div>
                    """)
                )
                self.assertTrue(
                    utils.check_is_wrap_in_div("""
                        <div
                            class="test"
                            style="color: blue;">
                            <div>
                                <p>Hello</p>
                                <p>Test</p>
                            </div>
                        </div>
                    """)
                )
    
            with self.subTest('test html not wrap in div'):
                html_list = [
                    """
                        <body>
                            <div
                                class="test"
                                style="color: blue;">
                                <p>hello</p>
                            </div>
                        </body>
                    """,
                    """
                        <p>HELLO</p>
                        <p>TEST</p>
                    """,
                    """
                        <section>
                            <div>
                                <p>hello</p>
                            </div>
                        </section>
                    """,
                    '<p>HELLO</p><p>TEST</p>',
                    """
                        <body>
                            <div class="HELO">
                                <p>hello</p>
                            </div>
                        </body>
                    """,
                    """
                        <body>
                            <div
                                class="test"
                                style="color: blue;"
                            >
                                <p>hello</p>
                            </div>
                        </body>
                    """,
                    """
                        <body>
                            <div
                                class="test"
                                style="color: blue;">
                                <p>hello</p>
                            </div>
                        </body>
                    """,
                    """
                        <p>Hello</p>
                        <p>World</p>
                        <div class="testing">
                            Hello
                        </div>
                    """,
                    """
                        <div>
                            <p>Hello</p>
                            <p>World</p>
                            <p>Hello</p>
                            <p>World</p>
                        </div>
                        <div> </div>
                    """,
                    """
                        <div>
                            <p>Hello</p>
                            <p>World</p>
                            <p>Hello</p>
                            <p>World</p>
                        </div>
                        <div> </div>
                    """,
                    """
                        <div>
                            <div>
                                <p>Hello</p>
                                <p>World</p>
                                <p>Hello</p>
                                <p>World</p>
                            </div>
                        </div>
                        <span>
                            <div> </div>
                        </span>
                    """,
                ]
                for html in html_list:
                    self.assertFalse(
                        utils.check_is_wrap_in_div(html),
                    )
    
        def test_remove_root_div(self):
            with self.subTest('test remove root html'):
                self.assertEqual(
                    utils.remove_root_div('<div></div>'),
                    '',
                )
                self.assertEqual(
                    utils.remove_root_div(
                        """
                            <div>
                                <p>Hello</p>
                                <p>Test</p>
                            </div>
                        """
                    ).strip(),
                    """
                                <p>Hello</p>
                                <p>Test</p>
                    """.strip(),
                )
                self.assertEqual(
                    utils.remove_root_div(
                        """
                            <div class="test" style="color: blue;">
                                <p>Hello</p>
                                <p>Test</p>
                            </div>
                        """
                    ).strip(),
                    """
                                <p>Hello</p>
                                <p>Test</p>
                    """.strip(),
                )
                self.assertEqual(
                    utils.remove_root_div(
                        """
                            <div
                                class="test"
                                style="color: blue;"
                            >
                                <p>Hello</p>
                                <p>Test</p>
                            </div>
                        """
                    ).strip(),
                    """
                                <p>Hello</p>
                                <p>Test</p>
                    """.strip(),
                )
                self.assertEqual(
                    utils.remove_root_div(
                        """
                            <div
                                class="test"
                                style="color: blue;">
                                <p>Hello</p>
                                <p>Test</p>
                            </div>
                        """
                    ).strip(),
                    """
                                <p>Hello</p>
                                <p>Test</p>
                    """.strip(),
                )
                self.assertEqual(
                    utils.remove_root_div(
                        """
                            <div
                                class="test"
                                style="color: blue;">
                                <div>
                                    <p>Hello</p>
                                    <p>Test</p>
                                </div>
                            </div>
                        """
                    ).strip(),
                    """
                                <div>
                                    <p>Hello</p>
                                    <p>Test</p>
                                </div>
                    """.strip(),
                )
                self.assertEqual(
                    utils.remove_root_div(
                        """<div
                            class="test"
                            style="color: blue;">
                                <div>
                                    <p>Hello</p>
                                    <p>Test</p>
                                </div>
                            </div>
                        """
                    ).strip(),
                    """
                                <div>
                                    <p>Hello</p>
                                    <p>Test</p>
                                </div>
                    """.strip(),
                )
    
            with self.subTest('test not root html'):
                html_list = [
                    """
                        <body>
                            <div
                                class="test"
                                style="color: blue;">
                                <p>hello</p>
                            </div>
                        </body>
                    """,
                    """
                        <p>HELLO</p>
                        <p>TEST</p>
                    """,
                    """
                        <section>
                            <div>
                                <p>hello</p>
                            </div>
                        </section>
                    """,
                    '<p>HELLO</p><p>TEST</p>',
                    """
                        <body>
                            <div class="HELO">
                                <p>hello</p>
                            </div>
                        </body>
                    """,
                    """
                        <body>
                            <div
                                class="test"
                                style="color: blue;"
                            >
                                <p>hello</p>
                            </div>
                        </body>
                    """,
                    """
                        <body>
                            <div
                                class="test"
                                style="color: blue;">
                                <p>hello</p>
                            </div>
                        </body>
                    """,
                ]
                for html in html_list:
                    self.assertEqual(
                        utils.remove_root_div(html),
                        html,
                    )
    
    

    【讨论】:

      【解决方案4】:

      将 HTML 字符串包装在 &lt;div&gt;...&lt;/div&gt; 中,并使用正则表达式去除 Cleaner 附加的前导 &lt;div&gt; 和尾随 &lt;/div&gt;&lt;/body&gt;&lt;/html&gt;\n

      #!/usr/bin/python3
      
      from lxml.html.clean import Cleaner
      import re
      
      evil = "<script>malignus script</script><b>bold text</b><i>italic text</i>"
      evil = "<div>" + evil + "</div>"
      
      cleaner = Cleaner(remove_unknown_tags=False, allow_tags=['p', 'br', 'b'])
      
      htmlstr = cleaner.clean_html(evil)
      htmlstr = re.sub(r'^<div>', '', htmlstr)
      htmlstr = re.sub(r'</div></body></html>\n$', '', htmlstr)
      print(htmlstr)
      

      【讨论】:

        猜你喜欢
        • 2017-04-29
        • 1970-01-01
        • 2012-09-11
        • 1970-01-01
        • 1970-01-01
        • 2014-06-08
        • 1970-01-01
        • 2018-05-22
        • 2010-10-26
        相关资源
        最近更新 更多