стрип-теги питона - PullRequest
       3

стрип-теги питона

8 голосов
/ 06 апреля 2010

я хочу следующую функциональность.

input : this is test <b> bold text </b> normal text
expected output: this is test normal text

т.е. удалить содержимое указанного тега

Ответы [ 9 ]

9 голосов
/ 06 апреля 2010

Решение с использованием BeautifulSoup:

from BeautifulSoup import BeautifulSoup
def removeTag(soup, tagname):
    for tag in soup.findAll(tagname):
        contents = tag.contents
        parent = tag.parent
        tag.extract()

s = BeautifulSoup("abcd <b> btag </b> hello <d>dtag</d>")

removeTag(s,"b")
print s
removeTag(s, "d")
print s

возвращается:

>>>
abcd  hello <d>dtag</d>
abcd  hello
5 голосов
/ 06 апреля 2010

Если вы не возражаете против Python (хотя регулярные выражения довольно общие), вы можете черпать вдохновение из фильтра strip_tags Джанго .

Воспроизводится здесь для полноты -

def strip_tags(value):
    """Returns the given HTML with all tags stripped."""
    return re.sub(r'<[^>]*?>', '', force_unicode(value))

РЕДАКТИРОВАТЬ: Если вы используете это или любое другое решение регулярных выражений, имейте в виду, что оно пропускает тщательно разработанный HTML (см. Комментарий), а также комментарии HTML и, следовательно, не должно использоваться с ненадежным вводом. Вместо этого попробуйте использовать некоторые из ответов beautifulsoup, html5lib или lxml для ненадежного ввода.

5 голосов
/ 06 апреля 2010

С BeautifulSoup:

from BeautifulSoup import BeautifulSoup    
''.join(BeautifulSoup(page).findAll(text=True))

Найдено на http://www.ghastlyfop.com/blog/2008/12/strip-html-tags-from-string-python.html

2 голосов
/ 06 апреля 2010

Похоже, вы хотите HTMLParser. (html.parser в Python 3.)

from HTMLParser import HTMLParser
from sys import stdout
class Filter(HTMLParser):
    def __init__(self, ignored_tags):
        super(Filter, self).__init__()
        self.ignorelevel = 0
        self. ignored_tags = ignored_tags
    def handle_starttag(self, tag, attrs):
        if self.ignorelevel > 0:
            self.ignorelevel += 1
        elif tag in self.ignored_tags:
            self.ignorelevel = 1
        else:
            # One of these two.  Test and see.
            stdout.write(self.get_starttag_text())
            #stdout.write('<' + self.get_starttag_text() + '>')
    def handle_startendtag(self, tag, attrs):
        if self.ignorelevel == 0 and tag not in self.ignored_tags:
            # One of these two.  Test and see.
            stdout.write(self.get_starttag_text())
            #stdout.write('<' + self.get_starttag_text() + '/>')
    def handle_endtag(self, tag):
        if self.ignorelevel > 0:
            self.ignorelevel -= 1
            if self.ignorelevel > 0:
                return
        stdout.write('</' + tag + '>')
    def handle_data(self, data):
        stdout.write(data)
    def handle_charref(self, name):
        stdout.write('&#' + name + ';')
    def handle_entityref(self, name):
        stdout.write('&' + name + ';')
    def handle_comment(self, data):
        stdout.write('<!-- ' + data + ' -->')
    def handle_decl(self, data):
        stdout.write('<!' + data + '>')
    def handle_pi(self, data):
        stdout.write('<?' + data + '>')
2 голосов
/ 06 апреля 2010

Попробуйте с:

import re
input = 'this is test <b> bold text </b> normal text'
output = re.compile(r'<[^<]*?/?>').sub('', input)
print output
0 голосов
/ 07 декабря 2014

Используйте модуль webob.exc:

from webob.exc import strip_tags

А затем используйте его:

print strip_tags('a<br/>b')
>> ab
0 голосов
/ 06 апреля 2010

Это рабочий код, взятый из моего проекта Supybot , поэтому он довольно хорошо протестирован:

class HtmlToText(sgmllib.SGMLParser):
    """Taken from some eff-bot code on c.l.p."""
    entitydefs = htmlentitydefs.entitydefs.copy()
    entitydefs['nbsp'] = ' '
    def __init__(self, tagReplace=' '):
        self.data = []
        self.tagReplace = tagReplace
        sgmllib.SGMLParser.__init__(self)

    def unknown_starttag(self, tag, attr):
        self.data.append(self.tagReplace)

    def unknown_endtag(self, tag):
        self.data.append(self.tagReplace)

    def handle_data(self, data):
        self.data.append(data)

    def getText(self):
        text = ''.join(self.data).strip()
        return normalizeWhitespace(text)

def htmlToText(s, tagReplace=' '):
    """Turns HTML into text.  tagReplace is a string to replace HTML tags with.
    """
    x = HtmlToText(tagReplace)
    x.feed(s)
    return x.getText()

Как отмечает документация, она возникла у Фредрика Лунда, а не у меня. Как говорится, великие авторы воруют:)

0 голосов
/ 06 апреля 2010

Насколько я могу судить, ответ Сэма должен сделать то, что он хотел, но он может заплатить, чтобы убедиться, что любые оставшиеся символы <> заменены на <и> соответственно, чтобы предотвратить неправильное использование / недействительный HTML.

Этот подход имеет то преимущество, что он может принимать невероятно искаженные ссылки / теги HTML.BeautifulSoup также довольно хорошо обрабатывает некорректные теги, но html5lib, sgmllib и htmllib могут подавить неверный код, даже больше, чем другие, если я правильно помню.

Следующий код также проверяет и ссылки HTML:

import re
from htmlentitydefs import name2codepoint, codepoint2name

S = '1234567890ABCDEF'
DHex = {}
for i in S:
    DHex[i.lower()] = None
    DHex[i.upper()] = None

def IsHex(S):
    if not S: return False
    for i in S: 
        if i not in DHex:
            return False
    return True

def UnEscape(S, LReEscape=None):
    # Converts HTML character references into a unicode string to allow manipulation
    #
    # If LUnEscape is provided, then the positions of the escaped characters will be 
    # added to allow turning the result back into HTML with ReEscape below, validating 
    # the references and escaping all the rest
    # 
    # This is needed to prevent browsers from stripping out e.g. &#32; (spaces) etc
    re = LReEscape != None

    LRtn = []
    L = S.split('&')
    xx = 0
    yy = 0
    for iS in L:
        if xx:
            LSplit = iS.split(';')
            if LSplit[0].lower() in name2codepoint:
                # A character reference, e.g. '&amp;'
                a = unichr(name2codepoint[LSplit[0].lower()])
                LRtn.append(a+';'.join(LSplit[1:]))
                if re: LReEscape.append((yy, a))

            elif LSplit[0] and LSplit[0][0] == '#' and LSplit[0][1:].isdigit():
                # A character number e.g. '&#52;'
                a = unichr(int(LSplit[0][1:]))
                LRtn.append(a+';'.join(LSplit[1:]))
                if re: LReEscape.append((yy, a))

            elif LSplit[0] and LSplit[0][0] == '#' and LSplit[0][1:2].lower() == 'x' and IsHex(LSplit[0][2:]):
                # A hexadecimal encoded character
                a = unichr(int(LSplit[0][2:].lower(), 16)) # Hex -> base 16
                LRtn.append(a+';'.join(LSplit[1:]))
                if re: LReEscape.append((yy, a))

            else: LRtn.append('&%s' % ';'.join(LSplit))
        else: LRtn.append(iS)
        xx += 1
        yy += len(LRtn[-1])
    return ''.join(LRtn)

def ReEscape(LReEscape, S, EscFn):
    # Re-escapes the output of UnEscape to HTML, ensuring e.g. &#32; 
    # is turned back again and isn't stripped at a browser level
    L = []
    prev = 0
    for x, c in LReEscape:
        if x != prev:
            L.append(EscFn(S[prev:x]))

        o = ord(c)
        if o in codepoint2name:
            L.append('&%s;' % codepoint2name[o])
        else: L.append('&#%s;' % o)
        prev = x+len(c)
    L.append(EscFn(S[prev:]))
    return ''.join(L)

def escape(value):
    # Escape left over <>& tags
    value = value.replace('&', '&amp;')
    value = value.replace('>', '&gt;')
    value = value.replace('<', '&lt;')
    return value

def strip_tags(value):
    # Strip HTML tags
    value = re.sub(r'<[^>]*?>', '', value)
    print 'No Tags:', value

    # Validate & references
    LReEscape = []
    value = UnEscape(value, LReEscape)
    value = ReEscape(LReEscape, value, EscFn=escape)
    print 'References Validated:', value
    return value

if __name__ == '__main__':
    # Outputs:
    #  No Tags: this is test  bold text  normal text >< &blah &amp; &amp
    #  References Validated: this is test  bold text  normal text &gt;&lt; &amp;blah &amp; &amp;
    strip_tags('this is test <b> bold text </b> normal text >< &blah &amp; &amp')
0 голосов
/ 06 апреля 2010

Я бы использовал http://code.google.com/p/html5lib/, если вы хотите включить некоторые безопасные теги.

См. Раздел «Sanitizing Tokenizer» по адресу http://code.google.com/p/html5lib/wiki/UserDocumentation.

Не забудьте проверить наличие уязвимостей, еслиэто важный сервис: http://ha.ckers.org/xss.html.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...