Это конкретный случай, но поскольку я пришел на эту страницу, ища решение и не нашел его, я добавлю его здесь.
Windows (проверена с 7) не принимать специальные символы (например, á
) в именах классов и пакетов. Linux, однако.
Я узнал об этом, когда я построил .jar
в NetBeans и попытался запустить его в командной строке. Он работал в NetBeans, но не в командной строке.
Я успешно использовал ответ Eloff для Python 3.1 [большое спасибо!].
Я обновился до Python 3.2.3 и столкнулся с ошибками.
Решение, если здесь благодаря ответчику Томасу К, заключается в том, чтобы вставить super().__init__()
в следующий код:
def __init__(self):
self.reset()
self.fed = []
... чтобы он выглядел так:
def __init__(self):
super().__init__()
self.reset()
self.fed = []
... и он будет работать для Python 3.2.3.
Опять же, благодаря Thomas K для исправления и для Исходный код Eloff приведен выше!
Почему все вы делаете это с трудом? Вы можете использовать функцию 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)
Решение lxml.html (lxml - это родная библиотека и, следовательно, намного быстрее, чем любое чистое решение python).
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>""")
clean_tree = clean_html(tree)
print(clean_tree.text_content().strip())
# >>> Detailed answers to any questions you might have
Также см. http://lxml.de/lxmlhtml.html#cleaning-up-html , что именно делает lxml.cleaner.
blockquote>Если вам нужно больше контролировать то, что именно дезинфицировано перед преобразованием в текст, вы можете явно использовать 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)
Адаптация python 3 ответа søren-løvborg
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()
Вы можете использовать либо другой парсер HTML (, например lxml , либо Beautiful Soup ) - тот, который предлагает функции для извлечения только текста. Или вы можете запустить регулярное выражение в строке строки, которая удаляет теги. Подробнее см. В http://www.amk.ca/python/howto/regex/ .
Используя BeautifulSoup, html2text или код из @Eloff, большую часть времени он остается некоторыми элементами html, javascript-кодом ...
Таким образом, вы можете использовать комбинацию этих библиотек и удалить форматирование уценки (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
Он работает хорошо для меня, но его можно улучшить, конечно ...
Этот метод работает безупречно для меня и не требует дополнительных установок:
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(" ", " ") ## Get rid of the remnants of certain formatting(subscript,superscript,etc).
Это быстрое исправление и может быть еще более оптимизировано, но оно будет работать нормально. Этот код заменит все непустые теги на «» и разделит все теги 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("<","<")
lineTemp = lineTemp.replace(">",">")
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"
Существует простой способ:
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
PS - Если вас интересует класс (о умной отладке с помощью python) Я даю вам ссылку: http://www.udacity.com/overview/Course/cs259/CourseRev/1 . Это бесплатно!
Добро пожаловать! :)
Для одного проекта мне понадобилась стрижка HTML, а также css и js. Таким образом, я сделал вариант ответа Элоффа:
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()
Я разбираю 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))
Удаляет все отметки и html правильно.
Вы можете написать свою собственную функцию:
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
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 .
Одно дело, чтобы люди не могли <i>italicizing</i>
, не оставляя i
s плавающим вокруг. Но другое - принимать произвольные данные и сделать их совершенно безвредными. Большинство методов на этой странице оставят такие вещи, как закрытые комментарии (<!--
) и угловые скобки, которые не являются частью тегов (blah <<<><blah
) неповрежденными. Версия HTMLParser может даже оставить полные теги, если они находятся в закрытом комментарии.
Что делать, если ваш шаблон {{ firstname }} {{ lastname }}
? firstname = '<a'
и lastname = 'href="http://evil.com/">'
будут пропускаться каждым дескриптором тега на этой странице (кроме @Medeiros!), потому что они не являются полными тегами самостоятельно.
Версия jango strip_tags
, улучшенная (см. Следующий заголовок) версия верхнего ответа на этот вопрос, дает следующее предупреждение:
Предоставляется абсолютно безотказная информация о том, что полученная строка является безопасным для HTML. Поэтому НИКОГДА не маркируйте результат вызова
blockquote>strip_tags
, не ускоряя его, например, с помощьюescape()
.Следуйте их советам!
Чтобы снять метки с помощью HTMLParser, вы должны запускать его несколько раз.
Легко обойти верхний ответ на этот вопрос.
Посмотрите на эту строку ( источник и обсуждение ):
<img<!-- --> src=x onerror=alert(1);//><!-- -->
В первый раз, когда HTMLParser видит это, он не может сказать, что
<img...>
является тегом. Он выглядит сломанным, поэтому HTMLParser не избавляется от него. Он извлекает только<!-- comments -->
, оставляя вас с<img src=x onerror=alert(1);//>
. Эта проблема была раскрыта в проекте Django в марте 2014 года. Их старый
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()
.Обновление 19 марта 2015 г. В версиях Django произошла ошибка до 1.4.20, 1.6.11, 1.7.7 и 1.8c1. Эти версии могут вводить бесконечный цикл в функцию strip_tags (). Исправленная версия воспроизводится выше. Подробнее здесь .
Хорошие вещи для копирования или использования
Мой примерный код не обрабатывает HTML-объекты - это пакеты в Django и MarkupSafe.
Мой примерный код вытащил из превосходной библиотеки MarkupSafe для предотвращения межсайтового скриптинга. Это удобно и быстро (с ускорением C к его родной версии Python). Он включен в Google App Engine и используется Jinja2 (2.7 и выше) , Mako, Pylons и т. Д. Он легко работает с шаблонами Django из Django 1.7.
Django strip_tags и другие утилиты html из последней версии хороши, но я считаю их менее удобными, чем MarkupSafe. Они довольно самодостаточны, вы можете скопировать то, что вам нужно из этого файла .
Если вам нужно удалить почти все теги, [] g8] Библиотека Bleach хороша. Вы можете заставить его применять такие правила, как «мои пользователи могут выделять курсивом, но они не могут создавать iframes».
Поймите свойства вашего стриптизера тегов! Запустите тесты Fuzz! Вот код , который я использовал для исследования этого ответа.
sheepish note - Сам вопрос касается печати на консоли, но это является лучшим результатом Google для «python strip html from string», поэтому именно этот ответ составляет 99% в Интернете.
Пакет Beautiful Soup делает это немедленно для вас.
from bs4 import BeautifulSoup
soup = BeautifulSoup(html)
text = soup.get_text()
print(text)
Мне нужен способ стэка тегов и декодировать объекты HTML в обычный текст. Следующее решение основано на ответе Элоффа (который я не мог использовать, потому что он разбивает сущности).
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)'
Обработка ошибок:
&#apos;
, который действителен в XML и XHTML, но не является простым HTML) приведет к исключению ValueError
. 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).
(Тем не менее, ОП попросил распечатать результат на консоли, и в этом случае не требуется HTML-экранирование).
Решения с HTML-Parser являются обрывочными, если они запускаются только один раз:
html_to_text('<<b>script>alert("hacked")<</b>/script>
приводит к:
<script>alert("hacked")</script>
тому, что вы намерены предотвратить. если вы используете HTML-Parser, считайте теги до тех пор, пока не будут заменены ноль:
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
Если вы хотите удалить все теги 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))
Я пробовал код принятого ответа, но получаю «RuntimeError: превышена максимальная глубина рекурсии» , что не произошло с вышеупомянутым блоком кода.
Я не очень много думал о случаях, которые он пропустит, но вы можете сделать простое регулярное выражение:
re.sub('<[^<]+?>', '', text)
Для тех, кто не понимает регулярное выражение, он ищет строку <...>
, где внутреннее содержимое состоит из одного или нескольких (+
) символов, которые не являются <
. ?
означает, что он будет соответствовать самой маленькой строке, которую он может найти. Например, с учетом <p>Hello</p>
, он будет соответствовать <'p>
и </p>
отдельно с ?
. Без него он будет соответствовать всей строке <..Hello..>
.
Если в html (например, 2 < 3
) появляется не тег <
, он должен быть записан как escape-последовательность &...
поэтому ^<
может быть ненужным.