파이썬에서 문자열에서 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.