파이썬에서 문자열에서 HTML 제거


269
from mechanize import Browser
br = Browser()
br.open('http://somewebpage')
html = br.response().readlines()
for line in html:
  print line

HTML 파일에 줄을 인쇄 할 때 서식 자체가 아닌 각 HTML 요소의 내용 만 표시하는 방법을 찾으려고합니다. 이 발견 '<a href="whatever.com">some text</a>'되면 '일부 텍스트'만 인쇄하고 '<b>hello</b>''hello'등을 인쇄합니다. 어떻게하면 좋을까요?


16
중요한 요소는 HTML 엔티티 (예 :)를 처리하는 방법 &amp;입니다. 1) 태그와 함께 태그를 제거하고 (일반 텍스트와 동일하므로 바람직하지 않으며 불필요) 2) 태그를 변경하지 않은 채로 두십시오 (스트리핑 된 텍스트가 HTML 컨텍스트로 다시 돌아가는 경우 적합한 솔루션). ) 텍스트를 일반 텍스트로 디코딩합니다 (스트리핑 된 텍스트가 데이터베이스 또는 HTML이 아닌 다른 컨텍스트로 이동하거나 웹 프레임 워크에서 자동으로 텍스트 HTML 이스케이프를 수행하는 경우).
— Søren Løvborg

2
@ SørenLøvborg 지점 2) : stackoverflow.com/questions/753052/…
— Robert Robert

2
2014 년 3 월까지 Django 프로젝트에서 사용 된 최고의 답변은 사이트 간 스크립팅에 대해 안전하지 않은 것으로 밝혀 졌습니다.이를 통해 이에 대한 예제를 보려면 해당 링크를 참조하십시오. Bleach.clean (), Markupsafe의 striptags 또는 RECENT Django의 strip_tags를 사용하는 것이 좋습니다.
— rescdsk

답변:


419

필자는 파이썬 stdlib 만 필요하기 때문에 항상이 함수를 사용하여 HTML 태그를 제거했습니다.

파이썬 3의 경우 :

from io import StringIO
from html.parser import HTMLParser

class MLStripper(HTMLParser):
    def __init__(self):
        super().__init__()
        self.reset()
        self.strict = False
        self.convert_charrefs= True
        self.text = StringIO()
    def handle_data(self, d):
        self.text.write(d)
    def get_data(self):
        return self.text.getvalue()

def strip_tags(html):
    s = MLStripper()
    s.feed(html)
    return s.get_data()

파이썬 2의 경우 :

from HTMLParser import HTMLParser
from StringIO import StringIO

class MLStripper(HTMLParser):
    def __init__(self):
        self.reset()
        self.text = StringIO()
    def handle_data(self, d):
        self.text.write(d)
    def get_data(self):
        return self.text.getvalue()

def strip_tags(html):
    s = MLStripper()
    s.feed(html)
    return s.get_data()

3
2 년 이상 후에도 같은 문제에 직면하게되었으며 이는 훨씬 더 우아한 해결책입니다. 내가 만든 변경 사항만이 self.fed를 목록에 포함시키지 않고 목록으로 반환하는 것이므로 요소 내용을 살펴볼 수있었습니다.
— 방향

47
&amp;이는 태그뿐만 아니라 HTML 엔터티 (예 :)를 제거 합니다.
— Søren Løvborg

30
@surya 나는 당신이 이것을 보았을 것입니다
— tkone

8
큰 답변 주셔서 감사합니다. 최신 버전의 Python (3.2+)을 사용하는 사용자에게주의 할 점은 부모 클래스의 __init__함수 를 호출해야한다는 것 입니다. 여기 참조 : stackoverflow.com/questions/11061058/...를 .
— pseudoramble

10
html 엔티티 (유니 코드로 변환)를 유지하기 위해 두 줄을 추가했습니다 : parser = HTMLParser()및 html = parser.unescape(html)strip_tags 함수의 시작 부분에.
— James Doepp-pihentagyu

156

나는 그것이 놓칠 사건에 대해 많이 생각하지 않았지만 간단한 정규 표현식을 수행 할 수 있습니다.

re.sub('<[^<]+?>', '', text)

정규 표현식을 이해하지 못하는 사람들을 위해 <...>내부 컨텐츠 +가 아닌 하나 이상의 문자 로 구성된 string을 검색 합니다 <. ?수단은 그것을 찾을 수있는 작은 문자열과 일치하는 것이다. 예를 들어 주어진를 들어 <p>Hello</p>, 그것은 일치 <'p>와 </p>별도로 ?. 그것이 없으면 전체 문자열과 일치합니다 <..Hello..>.

비 태그 <가 html (예 :)로 표시 되면 어쨌든 2 < 3이스케이프 시퀀스로 작성해야 &...하므로 ^<불필요 할 수 있습니다.


10
이것은 Django의 strip_tags 가 수행 하는 방식과 거의 동일합니다 .
— Bluu

10
이렇게 &amp;하면 출력에서 HTML 엔터티 (예 :)가 변경되지 않습니다.
— Søren Løvborg

35
<script <script >> alert ( "Hi!") << / script> / script>

19
이 방법으로하지 마십시오! @Julio Garcia가 말했듯이 안전하지 않습니다!
— rescdsk

18
사람들은 HTML 스트리핑과 HTML 위생을 혼동하지 마십시오. 예. 고장 또는 악의적 인 입력의 경우이 답변에 HTML 태그가 포함 된 출력이 생성 될 수 있습니다. 여전히 HTML 태그를 제거하는 완벽한 방법입니다. 그러나 HTML 태그를 제거하는 것은 올바른 HTML 삭제를위한 올바른 대체 방법이 아닙니다. 규칙은 어렵지 않다 : 때마다 당신은 HTML 출력에 일반 텍스트 문자열을 삽입, 당신이해야 항상 HTML (사용하여 탈출 cgi.escape(s, True)이 HTML을 포함하지 않는 것을 당신이 "알고있는"경우에도) (예를 들어, 당신은 HTML 콘텐츠를 제거하기 때문에) . 그러나 이것은 OP가 요구 한 것이 아닙니다.
— Søren Løvborg

76

BeautifulSoup get_text()기능을 사용할 수 있습니다 .

from bs4 import BeautifulSoup

html_str = '''
<td><a href="http://www.fakewebsite.com">Please can you strip me?</a>
<br/><a href="http://www.fakewebsite.com">I am waiting....</a>
</td>
'''
soup = BeautifulSoup(html_str)

print(soup.get_text()) 
#or via attribute of Soup Object: print(soup.text)

출력을 재현 할 수 있도록 구문 분석기 를 명시 적으로 지정하는 것이 좋습니다 ( 예 BeautifulSoup(html_str, features="html.parser"):).


32

짧은 버전!

import re, cgi
tag_re = re.compile(r'(<!--.*?-->|<[^>]*>)')

# Remove well-formed tags, fixing mistakes by legitimate users
no_tags = tag_re.sub('', user_input)

# Clean up anything else by escaping
ready_for_web = cgi.escape(no_tags)

정규식 소스 : MarkupSafe . 그들의 버전은 HTML 엔터티도 처리하지만이 빠른 엔터티는 그렇지 않습니다.

왜 태그를 제거하고 그대로 둘 수 없습니까?

떠 다니지 <i>italicizing</i>않고 사람들을 사물 로부터 지키는 것이 한 가지 i입니다. 그러나 임의의 입력을 취하고 완전히 무해하게 만드는 것은 또 다른 방법입니다. 이 페이지의 대부분의 기술은 닫히지 않은 주석 ( <!--) 및 태그 ( blah <<<><blah)의 일부가 아닌 꺾쇠 괄호와 같은 것을 그대로 둡니다 . HTMLParser 버전은 닫지 않은 주석 안에 있으면 완전한 태그를 그대로 둘 수도 있습니다.

템플릿이 {{ firstname }} {{ lastname }}어떻게 되나요? firstname = '<a'그리고 lastname = 'href="http://evil.com/">'될 것입니다이 페이지의 모든 태그 스트리퍼에 의해 통해하자 (@Medeiros 제외!), 그들은 자신에 완료되지 태그이기 때문에. 일반적인 HTML 태그를 제거하는 것만으로는 충분하지 않습니다.

strip_tags이 질문에 대한 최상위 답변의 개선 된 (다음 제목 참조) 버전 인 Django 's 는 다음 경고를 제공합니다.

결과 문자열이 HTML에 안전하다는 보장은 없습니다. 따라서 strip_tags통화 결과를 먼저 이스케이프 처리하지 않고 표시 하지 마십시오 ( 예 :) escape().

그들의 충고를 따르십시오!

HTMLParser로 태그를 제거하려면 여러 번 실행해야합니다.

이 질문에 대한 최고 답변을 우회하는 것은 쉽습니다.

이 문자열을보십시오 ( source and discussion ) :

<img<!-- --> src=x onerror=alert(1);//><!-- -->

HTMLParser가 처음 볼 때, <img...>이 태그 임을 알 수 없습니다 . 그것은 깨져서 HTMLParser는 그것을 제거하지 않습니다. 그것은 밖으로 데리고 <!-- comments -->, 당신을 떠나

<img src=x onerror=alert(1);//>

이 문제는 2014 년 3 월 Django 프로젝트에 공개되었습니다. 그들의 문제 strip_tags는 본질적으로이 질문에 대한 최고 답변과 동일합니다. 새 버전은 기본적으로 다시 실행해도 문자열이 변경되지 않을 때까지 루프에서 실행됩니다.

# _strip_once runs HTMLParser once, pulling out just the text of all the nodes.

def strip_tags(value):
    """Returns the given HTML with all tags stripped."""
    # Note: in typical case this loop executes _strip_once once. Loop condition
    # is redundant, but helps to reduce number of executions of _strip_once.
    while '<' in value and '>' in value:
        new_value = _strip_once(value)
        if len(new_value) >= len(value):
            # _strip_once was not able to detect more tags
            break
        value = new_value
    return value

물론 항상의 결과를 벗어나면 문제가되지 않습니다 strip_tags().

2015 년 3 월 19 일 업데이트 : 1.4.20, 1.6.11, 1.7.7 및 1.8c1 이전의 Django 버전에 버그가있었습니다. 이 버전들은 strip_tags () 함수에 무한 루프를 입력 할 수 있습니다. 고정 버전은 위에서 재현되었습니다. 자세한 내용은 여기를 참조하십시오 .

복사하거나 사용하기에 좋은 것들

내 예제 코드는 HTML 엔터티를 처리하지 않습니다. Django 및 MarkupSafe 패키지 버전이 있습니다.

내 예제 코드는 교차 사이트 스크립팅 방지를 위해 뛰어난 MarkupSafe 라이브러리 에서 가져 왔습니다 . 편리하고 빠릅니다 (C 속도를 기본 Python 버전으로 향상). 그것은에 포함 된 구글 앱 엔진 , 그리고에 의해 사용 Jinja2 (2.7 이상) , 마코, 철탑, 그리고 더. Django 1.7의 Django 템플릿과 쉽게 작동합니다.

Django의 strip_tags 및 최신 버전의 다른 html 유틸리티 는 좋지만 MarkupSafe보다 편리하지 않습니다. 그것들은 꽤 독립적이며이 파일 에서 필요한 것을 복사 할 수 있습니다 .

거의 모든 태그 를 제거해야하는 경우 Bleach 라이브러리가 적합합니다. "사용자가 이탤릭체를 사용할 수 있지만 iframe을 만들 수는 없습니다"와 같은 규칙을 적용 할 수 있습니다.

태그 스트리퍼의 속성을 이해하십시오! 퍼지 테스트를 실행하십시오! 이 답변에 대한 연구를 수행하는 데 사용한 코드는 다음과 같습니다 .

sheepish note- 질문 자체는 콘솔로 인쇄하는 것에 관한 것이지만 이것이 "python strip html from string"에 대한 Google의 최고 결과이므로,이 답변이 웹에 대해 99 % 인 이유입니다.


내 "alternate last line"예제 코드는 html 엔티티를 처리하지 않습니다. 얼마나 나쁜가요?
— rescdsk

나는 특별한 태그가없는 작은 HTML 덩어리 만 구문 분석하고 있으며 짧은 버전은 잘 작동합니다. 공유해 주셔서 감사합니다!
— tbolender

31

태그를 제거 하고 HTML 엔터티를 일반 텍스트로 디코딩 하는 방법이 필요했습니다 . 다음 솔루션은 Eloff의 답변을 기반으로합니다 (엔터티를 제거하기 때문에 사용할 수 없었습니다).

from HTMLParser import HTMLParser
import htmlentitydefs

class HTMLTextExtractor(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.result = [ ]

    def handle_data(self, d):
        self.result.append(d)

    def handle_charref(self, number):
        codepoint = int(number[1:], 16) if number[0] in (u'x', u'X') else int(number)
        self.result.append(unichr(codepoint))

    def handle_entityref(self, name):
        codepoint = htmlentitydefs.name2codepoint[name]
        self.result.append(unichr(codepoint))

    def get_text(self):
        return u''.join(self.result)

def html_to_text(html):
    s = HTMLTextExtractor()
    s.feed(html)
    return s.get_text()

빠른 테스트 :

html = u'<a href="#">Demo <em>(&not; \u0394&#x03b7;&#956;&#x03CE;)</em></a>'
print repr(html_to_text(html))

결과:

u'Demo (\xac \u0394\u03b7\u03bc\u03ce)'

오류 처리:

  • 잘못된 HTML 구조로 인해 HTMLParseError 가 발생할 수 있습니다 .
  • 잘못된 명명 된 HTML 엔터티 (예 : &#apos;XML 및 XHTML에서는 유효하지만 일반 HTML에서는 유효하지 않음)는 ValueError예외를 발생시킵니다.
  • Python에서 허용하는 유니 코드 범위 밖의 코드 포인트를 지정하는 숫자 HTML 엔터티 (예 : 일부 시스템에서는 Basic Multilingual Plane 외부의 문자 )에서 ValueError예외 가 발생합니다 .

보안 참고 사항 : HTML 제거 (HTML을 일반 텍스트로 변환)와 HTML 살균 (일반 텍스트를 HTML로 변환)과 혼동하지 마십시오. 이 답변은 HTML을 제거하고 엔터티를 일반 텍스트로 디코딩하므로 결과를 HTML 컨텍스트에서 안전하게 사용할 수 없습니다.

예 : &lt;script&gt;alert("Hello");&lt;/script&gt;로 변환됩니다 <script>alert("Hello");</script>. 이는 100 % 올바른 동작이지만 결과 일반 텍스트를 HTML 페이지에 그대로 삽입하면 충분하지 않습니다.

규칙은 어렵지 않다 : 때마다 당신은 HTML 출력에 일반 텍스트 문자열을 삽입, 당신이해야 항상 HTML (사용하여 탈출 cgi.escape(s, True)이 HTML을 포함하지 않는 것을 당신이 "알고있는"경우에도) (예를 들어, 당신은 HTML 콘텐츠를 제거하기 때문에) .

그러나 OP는 콘솔에 결과를 인쇄하도록 요청했으며이 경우 HTML 이스케이프가 필요하지 않습니다.

파이썬 3.4+ 버전 : (doctest와 함께!)

import html.parser

class HTMLTextExtractor(html.parser.HTMLParser):
    def __init__(self):
        super(HTMLTextExtractor, self).__init__()
        self.result = [ ]

    def handle_data(self, d):
        self.result.append(d)

    def get_text(self):
        return ''.join(self.result)

def html_to_text(html):
    """Converts HTML to plain text (stripping tags and converting entities).
    >>> html_to_text('<a href="#">Demo<!--...--> <em>(&not; \u0394&#x03b7;&#956;&#x03CE;)</em></a>')
    'Demo (\xac \u0394\u03b7\u03bc\u03ce)'

    "Plain text" doesn't mean result can safely be used as-is in HTML.
    >>> html_to_text('&lt;script&gt;alert("Hello");&lt;/script&gt;')
    '<script>alert("Hello");</script>'

    Always use html.escape to sanitize text before using in an HTML context!

    HTMLParser will do its best to make sense of invalid HTML.
    >>> html_to_text('x < y &lt z <!--b')
    'x < y < z '

    Unrecognized named entities are included as-is. '&apos;' is recognized,
    despite being XML only.
    >>> html_to_text('&nosuchentity; &apos; ')
    "&nosuchentity; ' "
    """
    s = HTMLTextExtractor()
    s.feed(html)
    return s.get_text()

HTMLParser는 Python 3에서 개선되었습니다 (코드가 적고 오류 처리가 향상됨).


18

간단한 방법이 있습니다.

def remove_html_markup(s):
    tag = False
    quote = False
    out = ""

    for c in s:
            if c == '<' and not quote:
                tag = True
            elif c == '>' and not quote:
                tag = False
            elif (c == '"' or c == "'") and tag:
                quote = not quote
            elif not tag:
                out = out + c

    return out

아이디어는 여기에 설명되어 있습니다 : http://youtu.be/2tu9LTDujbw

여기에서 작동하는 것을 볼 수 있습니다 : http://youtu.be/HPkNPcYed9M?t=35s

추신-수업에 관심이 있다면 (python을 사용한 스마트 디버깅에 대해) http://www.udacity.com/overview/Course/cs259/CourseRev/1 링크를 제공합니다 . 무료입니다!

천만에요! :)


2
이 답변이 왜 다운 보트인지 궁금합니다. lib없이 문제를 해결하는 간단한 방법입니다. 순수한 파이썬과 링크로 표시된 것처럼 작동합니다.
— Medeiros 2013 년

2
아마도 사람들은 안전을 위해 라이브러리를 선호 할 것입니다. 나는 코드를 테스트하고 전달했으며 항상 lib를 사용하고 버그가 나타날 때까지 괜찮다고 가정하는 것보다 작은 코드를 선호합니다. 나에게 그것은 내가 찾고 있었고 다시 한 번 감사드립니다. 다운 보트와 관련하여 그 사고 방식에 빠지지 마십시오. 여기 사람들은 투표가 아니라 질에 관심을 가져야합니다. 최근 SO는 모두가 지식이 아닌 요점을 원하는 곳이되었습니다.
— Jimmy Kane

2
이 솔루션의 문제점은 오류 처리입니다. 예를 들어 <b class="o'>x</b>입력 기능 출력으로 제공 하는 경우 x. 그러나 실제로이 입력은 유효하지 않습니다. 그것이 사람들이 lib를 선호하는 이유라고 생각합니다.
— laltin

1
해당 입력에서도 작동합니다. 방금 테스트했습니다. 해당 라이브러리 내에서 비슷한 코드를 찾을 수 있습니다. 그것은 매우 파이썬 적이 지 않습니다. C 또는 Java 코드처럼 보입니다. 효율적이고 다른 언어로 쉽게 이식 할 수 있다고 생각합니다.
— Medeiros

1
단순하고 Pythonic이며 논의 된 다른 방법보다 잘 작동하는 것 같습니다. 잘못 구성된 HTML에는 작동하지 않지만 극복 할 수는 없습니다.
— denson

16

HTML 엔티티 (예 &amp;:) 를 유지해야하는 경우 Eloff의 답변 에 "handle_entityref"메소드를 추가했습니다 .

from HTMLParser import HTMLParser

class MLStripper(HTMLParser):
    def __init__(self):
        self.reset()
        self.fed = []
    def handle_data(self, d):
        self.fed.append(d)
    def handle_entityref(self, name):
        self.fed.append('&%s;' % name)
    def get_data(self):
        return ''.join(self.fed)

def html_to_text(html):
    s = MLStripper()
    s.feed(html)
    return s.get_data()

13

모든 HTML 태그를 제거하려면 내가 찾은 가장 쉬운 방법은 BeautifulSoup을 사용하는 것입니다.

from bs4 import BeautifulSoup  # Or from BeautifulSoup import BeautifulSoup

def stripHtmlTags(htmlTxt):
    if htmlTxt is None:
            return None
        else:
            return ''.join(BeautifulSoup(htmlTxt).findAll(text=True)) 

허용 된 답변의 코드를 시도했지만 "런타임 오류 : 최대 재귀 깊이가 초과되었습니다."라는 메시지가 나타 났으며 위의 코드 블록에서는 발생하지 않았습니다.


1
방금 더 깨끗해 보이고 효과가 좋았 기 때문에 입력 방법을 시도하지 않았습니다. 입력 태그를 제거하지 않았습니다!
— kustomrtr

BeautifulSoup의 간단한 응용 프로그램에 공백이 ''.join(BeautifulSoup('<em>he</em>llo<br>world').find_all(text=True))있습니다. 여기서 출력은 "helloworld"이며, "hello world"가되기를 원할 것입니다. ' '.join(BeautifulSoup('<em>he</em>llo<br>world').find_all(text=True))그것이 "그는 세상"이 될 때 도움이되지 않습니다.
— Finn Årup Nielsen

@kustomrtr, 내 무지 미안 해요, 자기 주장에 무엇을 넣어? NameError : 이름 'self'가 정의되지 않았습니다
— Ian_De_Oliveira

@Ian_De_Oliveira 제거 할 수 있습니다. 클래스 안에 있다고 가정했지만 필요하지 않습니다. 나는 또한 그것을 제거하기 위해 답변을 편집
— Vasilis

@Ian_De_Oliveira 제거 할 수 있습니다. 클래스 안에 있다고 가정했지만 필요하지 않습니다. 나는 또한 그것을 제거하기 위해 답변을 편집
— Vasilis

10

다음은 놀랍도록 빠른 lxml라이브러리를 기반으로 HTML 태그를 제거하고 HTML 엔터티를 디코딩하는 간단한 솔루션입니다 .

from lxml import html

def strip_html(s):
    return str(html.fromstring(s).text_content())

strip_html('Ein <a href="">sch&ouml;ner</a> Text.')  # Output: Ein schöner Text.

3
2020 년 현재 HTML의 내용을 제거하는 가장 빠르고 최상의 방법이었습니다. 디코딩 처리의 보너스와 함께. 언어 감지에 좋습니다!
— dfabiano

text_content()반환 lxml.etree._ElementUnicodeResult당신 때문에 먼저 문자열로 캐스팅해야 할 수도 있습니다
— Suzana

1
@Suzana 좋은 지적입니다. str문자열 +인덱싱 과 같은 문자열 작업 을 위해 자동 전송되는 것 같습니다 []. 어쨌든 좋은 측정을 위해 캐스트를 추가했습니다.
— Robin Dinse

9

lxml.html 기반 솔루션 (LXML는 네이티브 라이브러리 때문에 훨씬 빠르게 어떤 순수 파이썬 솔루션보다).

from lxml import html
from lxml.html.clean import clean_html

tree = html.fromstring("""<span class="item-summary">
                            Detailed answers to any questions you might have
                        </span>""")

print(clean_html(tree).strip())

# >>> Detailed answers to any questions you might have

lxml.cleaner의 정확한 기능에 대해서는 http://lxml.de/lxmlhtml.html#cleaning-up-html 을 참조 하십시오 .

텍스트로 변환하기 전에 위생 상태를 정확히 제어해야하는 경우 생성자에 원하는 옵션을 전달하여 lxml Cleaner를 명시 적으로 사용할 수 있습니다 .

cleaner = Cleaner(page_structure=True,
                  meta=True,
                  embedded=True,
                  links=True,
                  style=True,
                  processing_instructions=True,
                  inline_style=True,
                  scripts=True,
                  javascript=True,
                  comments=True,
                  frames=True,
                  forms=True,
                  annoying_tags=True,
                  remove_unknown_tags=True,
                  safe_attrs_only=True,
                  safe_attrs=frozenset(['src','color', 'href', 'title', 'class', 'name', 'id']),
                  remove_tags=('span', 'font', 'div')
                  )
sanitized_html = cleaner.clean_html(unsafe_html)

1
AttributeError : 'HtmlElement'객체에 'strip'속성이 없습니다.
— aris

7

뷰티플 수프 패키지는이를 즉시 수행합니다.

from bs4 import BeautifulSoup

soup = BeautifulSoup(html)
text = soup.get_text()
print(text)

3
검토 대기열에서 : 답변과 관련하여 컨텍스트를 더 추가해 주시기 바랍니다. 코드 전용 답변은 이해하기 어렵습니다. 게시물에 더 많은 정보를 추가 할 수 있다면 독자와 미래 독자 모두에게 도움이됩니다.
— help-info.de

2

다음은 파이썬 3에 대한 솔루션입니다.

import html
import re

def html_to_txt(html_text):
    ## unescape html
    txt = html.unescape(html_text)
    tags = re.findall("<[^>]+>",txt)
    print("found tags: ")
    print(tags)
    for tag in tags:
        txt=txt.replace(tag,'')
    return txt

그것이 완벽한 지 확실하지 않지만 내 유스 케이스를 해결하고 단순 해 보입니다.


2

텍스트 만 추출하는 기능을 제공 하는 다른 HTML 파서 ( 예 : lxml 또는 Beautiful Soup ) 를 사용할 수 있습니다 . 또는 줄 문자열에서 태그를 제거하는 정규식을 실행할 수 있습니다. 자세한 내용은 Python 문서 를 참조하십시오 .


1
amk 링크가 죽었습니다. 대안이 있습니까?

2
파이썬 웹 사이트에는 좋은 사용법이 있습니다. 여기에 정규식 사용법이 있습니다 : docs.python.org/howto/regex
— Jason Coon

5
lxml에서 :lxml.html.fromstring(s).text_content()
— Bluu

1
lxml을 사용한 Bluu의 예는 HTML 엔터티 (예 :) &amp;를 텍스트로 디코딩 합니다.
— Søren Løvborg

1

나는 Eloff의 답변을 Python 3.1에 성공적으로 사용했습니다 [많은 감사합니다!].

Python 3.2.3으로 업그레이드하고 오류가 발생했습니다.

응답자 Thomas K 덕분에 여기 에 제공된 솔루션 super().__init__()은 다음 코드 에 삽입 하는 것입니다.

def __init__(self):
    self.reset()
    self.fed = []

... 다음과 같이 보이게하려면 :

def __init__(self):
    super().__init__()
    self.reset()
    self.fed = []

... 그리고 Python 3.2.3에서 작동합니다.

수정 사항과 위에 제공된 Eloff의 원래 코드에 대해 Thomas K에게 감사드립니다!


1

당신은 당신의 자신의 함수를 작성할 수 있습니다 :

def StripTags(text):
     finished = 0
     while not finished:
         finished = 1
         start = text.find("<")
         if start >= 0:
             stop = text[start:].find(">")
             if stop >= 0:
                 text = text[:start] + text[start+stop+1:]
                 finished = 0
     return text

1
문자열에 추가하면 문자열의 새 사본이 작성됩니까?
— Jeremy L

1
@Nerdling-그렇습니다. 자주 사용하는 기능 (또는 큰 텍스트 텍스트에 자주 사용되지 않는 기능)에서 다소 인상적인 비효율을 초래할 수 있습니다. 자세한 내용은 이 페이지를 참조하십시오 . : D
— Jeremy Sandell

인용 된 문자열에 대해 테스트합니까? 호
— 지미 케인

1

HTML-Parser를 사용하는 솔루션은 한 번만 실행하면 모두 깨질 수 있습니다.

html_to_text('<<b>script>alert("hacked")<</b>/script>

결과 :

<script>alert("hacked")</script>

당신이 방지하려는 것. HTML 파서를 사용하는 경우 0이 교체 될 때까지 태그를 계산하십시오.

from HTMLParser import HTMLParser

class MLStripper(HTMLParser):
    def __init__(self):
        self.reset()
        self.fed = []
        self.containstags = False

    def handle_starttag(self, tag, attrs):
       self.containstags = True

    def handle_data(self, d):
        self.fed.append(d)

    def has_tags(self):
        return self.containstags

    def get_data(self):
        return ''.join(self.fed)

def strip_tags(html):
    must_filtered = True
    while ( must_filtered ):
        s = MLStripper()
        s.feed(html)
        html = s.get_data()
        must_filtered = s.has_tags()
    return html

1
호출 된 함수를 호출 html_to_text하고 해당 텍스트를 이스케이프하지 않고 해당 함수에서 출력되는 텍스트를 html에 포함하면 이스케이프가 부족하여 html_to_text함수가 아닌 보안 취약점 입니다. 이 html_to_text함수는 출력 결과가 텍스트라고 약속하지 않았습니다. 그리고 이스케이프없이 HTML에 텍스트를 삽입하는 것은 텍스트를 얻었는지 html_to_text 또는 다른 소스 를 얻었는지에 관계없이 잠재적 인 보안 취약점 입니다.
— kasperd

이스케이프가 부족한 경우에는 맞지만 주어진 문자열에서 HTML을 제거하여 주어진 문자열을 이스케이프하지 않도록하는 것이 문제였습니다. 이전 답변에서 일부 HTML을 제거한 결과 솔루션으로 새로운 HTML을 작성하면이 솔루션의 사용이 위험합니다.
— 포크 니 시우스

1

이것은 빠른 수정이며 훨씬 더 최적화 될 수 있지만 제대로 작동합니다. 이 코드는 비어 있지 않은 모든 태그를 ""로 바꾸고 모든 html 태그를 지정된 입력 텍스트로 제거합니다. ./file.py 입력 출력을 사용하여 실행할 수 있습니다.

    #!/usr/bin/python
import sys

def replace(strng,replaceText):
    rpl = 0
    while rpl > -1:
        rpl = strng.find(replaceText)
        if rpl != -1:
            strng = strng[0:rpl] + strng[rpl + len(replaceText):]
    return strng


lessThanPos = -1
count = 0
listOf = []

try:
    #write File
    writeto = open(sys.argv[2],'w')

    #read file and store it in list
    f = open(sys.argv[1],'r')
    for readLine in f.readlines():
        listOf.append(readLine)         
    f.close()

    #remove all tags  
    for line in listOf:
        count = 0;  
        lessThanPos = -1  
        lineTemp =  line

            for char in lineTemp:

            if char == "<":
                lessThanPos = count
            if char == ">":
                if lessThanPos > -1:
                    if line[lessThanPos:count + 1] != '<>':
                        lineTemp = replace(lineTemp,line[lessThanPos:count + 1])
                        lessThanPos = -1
            count = count + 1
        lineTemp = lineTemp.replace("&lt","<")
        lineTemp = lineTemp.replace("&gt",">")                  
        writeto.write(lineTemp)  
    writeto.close() 
    print "Write To --- >" , sys.argv[2]
except:
    print "Help: invalid arguments or exception"
    print "Usage : ",sys.argv[0]," inputfile outputfile"

1

søren-løvborg의 답변에 대한 파이썬 3 적응

from html.parser import HTMLParser
from html.entities import html5

class HTMLTextExtractor(HTMLParser):
    """ Adaption of http://stackoverflow.com/a/7778368/196732 """
    def __init__(self):
        super().__init__()
        self.result = []

    def handle_data(self, d):
        self.result.append(d)

    def handle_charref(self, number):
        codepoint = int(number[1:], 16) if number[0] in (u'x', u'X') else int(number)
        self.result.append(unichr(codepoint))

    def handle_entityref(self, name):
        if name in html5:
            self.result.append(unichr(html5[name]))

    def get_text(self):
        return u''.join(self.result)

def html_to_text(html):
    s = HTMLTextExtractor()
    s.feed(html)
    return s.get_text()

1

한 프로젝트의 경우 HTML을 제거하고 CSS와 JS도 필요했습니다. 따라서 Eloffs 답변을 변형했습니다.

class MLStripper(HTMLParser):
    def __init__(self):
        self.reset()
        self.strict = False
        self.convert_charrefs= True
        self.fed = []
        self.css = False
    def handle_starttag(self, tag, attrs):
        if tag == "style" or tag=="script":
            self.css = True
    def handle_endtag(self, tag):
        if tag=="style" or tag=="script":
            self.css=False
    def handle_data(self, d):
        if not self.css:
            self.fed.append(d)
    def get_data(self):
        return ''.join(self.fed)

def strip_tags(html):
    s = MLStripper()
    s.feed(html)
    return s.get_data()

1

다음은 현재 허용되는 답변 ( https://stackoverflow.com/a/925630/95989 ) 과 비슷한 솔루션입니다 . 단, 내부 HTMLParser클래스를 직접 사용하므로 (즉, 서브 클래 싱 없음) 훨씬 더 간결 해집니다.

데프 스트립 _html (텍스트) :
    부품 = []                                                                      
    파서 = HTMLParser ()                                                           
    parser.handle_data = parts.append                                               
    파서 피드 (텍스트)                                                               
    return ''.join (부품)

0

Github readmes를 파싱하고 있으며 다음이 실제로 잘 작동한다는 것을 알았습니다.

import re
import lxml.html

def strip_markdown(x):
    links_sub = re.sub(r'\[(.+)\]\([^\)]+\)', r'\1', x)
    bold_sub = re.sub(r'\*\*([^*]+)\*\*', r'\1', links_sub)
    emph_sub = re.sub(r'\*([^*]+)\*', r'\1', bold_sub)
    return emph_sub

def strip_html(x):
    return lxml.html.fromstring(x).text_content() if x else ''

그리고

readme = """<img src="https://raw.githubusercontent.com/kootenpv/sky/master/resources/skylogo.png" />

            sky is a web scraping framework, implemented with the latest python versions in mind (3.4+). 
            It uses the asynchronous `asyncio` framework, as well as many popular modules 
            and extensions.

            Most importantly, it aims for **next generation** web crawling where machine intelligence 
            is used to speed up the development/maintainance/reliability of crawling.

            It mainly does this by considering the user to be interested in content 
            from *domains*, not just a collection of *single pages*
            ([templating approach](#templating-approach))."""

strip_markdown(strip_html(readme))

모든 markdown 및 html을 올바르게 제거합니다.


0

BeautifulSoup, html2text 또는 @Eloff의 코드를 사용하면 대부분 HTML 요소, 자바 스크립트 코드가 남아 있습니다 ...

따라서 이러한 라이브러리의 조합을 사용하고 마크 다운 형식을 삭제할 수 있습니다 (Python 3).

import re
import html2text
from bs4 import BeautifulSoup
def html2Text(html):
    def removeMarkdown(text):
        for current in ["^[ #*]{2,30}", "^[ ]{0,30}\d\\\.", "^[ ]{0,30}\d\."]:
            markdown = re.compile(current, flags=re.MULTILINE)
            text = markdown.sub(" ", text)
        return text
    def removeAngular(text):
        angular = re.compile("[{][|].{2,40}[|][}]|[{][*].{2,40}[*][}]|[{][{].{2,40}[}][}]|\[\[.{2,40}\]\]")
        text = angular.sub(" ", text)
        return text
    h = html2text.HTML2Text()
    h.images_to_alt = True
    h.ignore_links = True
    h.ignore_emphasis = False
    h.skip_internal_links = True
    text = h.handle(html)
    soup = BeautifulSoup(text, "html.parser")
    text = soup.text
    text = removeAngular(text)
    text = removeMarkdown(text)
    return text

그것은 나를 위해 잘 작동하지만 물론 향상 될 수 있습니다 ...


0

간단한 코드!. 그러면 모든 종류의 태그와 내용이 제거됩니다.

def rm(s):
    start=False
    end=False
    s=' '+s
    for i in range(len(s)-1):
        if i<len(s):
            if start!=False:
                if s[i]=='>':
                    end=i
                    s=s[:start]+s[end+1:]
                    start=end=False
            else:
                if s[i]=='<':
                    start=i
    if s.count('<')>0:
        self.rm(s)
    else:
        s=s.replace('&nbsp;', ' ')
        return s

그러나 텍스트에 <> 기호 가 포함되어 있으면 완전한 결과를 얻지 못합니다 .


0
# This is a regex solution.
import re
def removeHtml(html):
  if not html: return html
  # Remove comments first
  innerText = re.compile('<!--[\s\S]*?-->').sub('',html)
  while innerText.find('>')>=0: # Loop through nested Tags
    text = re.compile('<[^<>]+?>').sub('',innerText)
    if text == innerText:
      break
    innerText = text

  return innerText.strip()

-2

이 방법은 완벽하게 작동하며 추가 설치가 필요하지 않습니다.

import re
import htmlentitydefs

def convertentity(m):
    if m.group(1)=='#':
        try:
            return unichr(int(m.group(2)))
        except ValueError:
            return '&#%s;' % m.group(2)
        try:
            return htmlentitydefs.entitydefs[m.group(2)]
        except KeyError:
            return '&%s;' % m.group(2)

def converthtml(s):
    return re.sub(r'&(#?)(.+?);',convertentity,s)

html =  converthtml(html)
html.replace("&nbsp;", " ") ## Get rid of the remnants of certain formatting(subscript,superscript,etc).

3
이것은 HTML 엔터티를 일반 텍스트로 디코딩하지만 실제로 원래 질문 인 태그를 제거하지는 않습니다. (또한 코드가 많은 작업을 수행하려면 두 번째 시도 제외 블록을 들여 쓰기해야합니다.)
— Søren Løvborg
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.