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’등을 인쇄합니다. 어떻게하면 좋을까요?
답변
필자는 파이썬 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()
답변
나는 그것이 놓칠 사건에 대해 많이 생각하지 않았지만 간단한 정규 표현식을 수행 할 수 있습니다.
re.sub('<[^<]+?>', '', text)
정규 표현식을 이해하지 못하는 사람들을 위해 <...>
내부 컨텐츠 +
가 아닌 하나 이상의 문자 로 구성된 string을 검색 합니다 <
. ?
수단은 그것을 찾을 수있는 작은 문자열과 일치하는 것이다. 예를 들어 주어진를 들어 <p>Hello</p>
, 그것은 일치 <'p>
와 </p>
별도로 ?
. 그것이 없으면 전체 문자열과 일치합니다 <..Hello..>
.
비 태그 <
가 html (예 :)로 표시 되면 어쨌든 2 < 3
이스케이프 시퀀스로 작성해야 &...
하므로 ^<
불필요 할 수 있습니다.
답변
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")
:).
답변
짧은 버전!
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 % 인 이유입니다.
답변
태그를 제거 하고 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>(¬ \u0394ημώ)</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 컨텍스트에서 안전하게 사용할 수 없습니다.
예 : <script>alert("Hello");</script>
로 변환됩니다 <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>(¬ \u0394ημώ)</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('<script>alert("Hello");</script>')
'<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 < z <!--b')
'x < y < z '
Unrecognized named entities are included as-is. ''' is recognized,
despite being XML only.
>>> html_to_text('&nosuchentity; ' ')
"&nosuchentity; ' "
"""
s = HTMLTextExtractor()
s.feed(html)
return s.get_text()
HTMLParser는 Python 3에서 개선되었습니다 (코드가 적고 오류 처리가 향상됨).
답변
간단한 방법이 있습니다.
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 링크를 제공합니다 . 무료입니다!
천만에요! 🙂
답변
HTML 엔티티 (예 &
🙂 를 유지해야하는 경우 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()