beautifulsoup在字符串中添加标签

时间:2015-12-03 10:04:55

标签: python html beautifulsoup

在某些html的文本部分中遇到文字www.domain.comhttp://domain.com/etc/的任何浏览器都会自动将其转换为<a href="http://www.domain.com">www.domain.com</a><a href="http://domain.com/etc/">http://domain.com/etc/</a>标记。我必须清理并验证这样的文本并自动替换,但问题是我无法在元素的string中插入新标记。

#!/usr/bin/python
# -*- coding: utf8
import re
from bs4 import BeautifulSoup as bs

def html_content_to_soup(data):
    soup = bs(data, "html5lib")
    soup.html.unwrap()
    soup.head.unwrap()
    soup.body.unwrap()
    return soup

def create_tag(soup):
    def resubfunction(m):
        url = m.group(0)

        if not url.startswith("http://") and not url.startswith("https://"):
            _url = "http://%s" % url
        else:
            _url = url

        tag = soup.new_tag('a', href=_url)
        tag.string = url.replace(".", "[.]")
        return tag.prettify(formatter=None)
    return resubfunction

def replace_vulnerable_text(soup, data):
    ex = r"(?i)\b((?:https?:(?:/{1,3}|[a-z0-9%])|[a-z0-9.\-]+[.](?:com|net|org|edu|gov|mil|aero|asia|biz|cat|coop|info|int|jobs|mobi|museum|name|post|pro|tel|travel|xxx|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cs|cu|cv|cx|cy|cz|dd|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|Ja|sk|sl|sm|sn|so|sr|ss|st|su|sv|sx|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw)/)(?:[^\s()<>{}\[\]]+|\([^\s()]*?\([^\s()]+\)[^\s()]*?\)|\([^\s]+?\))+(?:\([^\s()]*?\([^\s()]+\)[^\s()]*?\)|\([^\s]+?\)|[^\s\`!()\[\]{};:\'\".,<>?ÂŤÂťââââ])|(?:(?<!@)[a-z0-9]+(?:[.\-][a-z0-9]+)*[.](?:com|net|org|edu|gov|mil|aero|asia|biz|cat|coop|info|int|jobs|mobi|museum|name|post|pro|tel|travel|xxx|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cs|cu|cv|cx|cy|cz|dd|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|Ja|sk|sl|sm|sn|so|sr|ss|st|su|sv|sx|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw)\b/?(?!@)))"
    return re.sub(ex, create_tag(soup), data)

if __name__ == "__main__":
    html = """<html><body>The website bbc.co.uk is down</body></html>"""
    soup = bs(html, "html5")
    for elem in soup.find_all(text=True):
        if elem.string is not None:
            elem.replace_with( html_content_to_soup(replace_vulnerable_text(soup, elem.string)))

    print unicode(soup)

而不是预期的

<html><body>The website <a href="http://bbc.co.uk">bbc[.]co[.]uk</a> is down</body></html>

我正在

<html><head></head><body>The website &lt;a href="http://bbc.co.uk"&gt; bbc[.]co[.]uk &lt;/a&gt; is down</body></html>

html标签正在转义。任何正确方向的指针?我不知道如何处理这个问题。

编辑:用正确答案编辑原始问题。

2 个答案:

答案 0 :(得分:0)

{{1}}

它会为您提供所需的输出。

答案 1 :(得分:0)

我需要一个能从任意html返回汤的函数:

def html_content_to_soup(data):
    soup = bs(data, "html5lib")
    soup.html.unwrap()
    soup.head.unwrap()
    soup.body.unwrap()
    return soup

之后,我们得到:

elem.replace_with( html_content_to_soup(replace_vulnerable_text(soup, elem.string)) )

这会产生所需的内容:

<html><head></head><body>The website <a href="http://bbc.co.uk">bbc[.]co[.]uk</a> is down</body></html>