Какой самый простой способ избежать HTML в Python?

cgi.escape кажется одним возможным выбором. Это хорошо работает? Есть ли что-то, что считается лучше?

Ответ 1

cgi.escape в порядке. Он ускользает:

  • < to &lt;
  • > to &gt;
  • & to &amp;

Этого достаточно для всего HTML.

EDIT: Если у вас есть символы non-ascii, которые вы также хотите избежать, для включения в другой закодированный документ, который использует другую кодировку, например, говорит Крейг, просто используйте:

data.encode('ascii', 'xmlcharrefreplace')

Не забудьте сначала декодировать data до unicode, используя любую кодировку, которая была закодирована.

Однако по моему опыту такое кодирование бесполезно, если вы просто работаете с unicode все время от начала. Просто закодируйте в конце кодировку, указанную в заголовке документа (utf-8 для максимальной совместимости).

Пример:

>>> cgi.escape(u'<a>bá</a>').encode('ascii', 'xmlcharrefreplace')
'&lt;a&gt;b&#225;&lt;/a&gt;

Также стоит отметить (спасибо Грегу) дополнительный параметр quote cgi.escape. Если он установлен в True, cgi.escape также избегает символов двойной кавычки ("), поэтому вы можете использовать полученное значение в атрибуте XML/HTML.

EDIT: обратите внимание, что cgi.escape устарел в Python 3.2 в пользу html.escape, который делает то же самое, за исключением того, что quote по умолчанию - True.

Ответ 2

В Python 3.2 был представлен новый html модуль, который используется для экранирования зарезервированных символов из разметки HTML.

У него есть одна функция escape():

>>> import html
>>> html.escape('x > 2 && x < 7')
'x &gt; 2 &amp;&amp; x &lt; 7'

Ответ 3

Если вы хотите избежать HTML в URL-адресе:

Это, вероятно, НЕ то, что хотел OP (в вопросе явно не указано, в каком контексте подразумевается использование экранирования), но родная библиотека Python urllib имеет метод для удаления HTML-объектов, которые должны быть включены в URL-адрес безопасно.

Ниже приведен пример:

#!/usr/bin/python
from urllib import quote

x = '+<>^&'
print quote(x) # prints '%2B%3C%3E%5E%26'

Найти документы здесь

Ответ 4

cgi.escape должно быть хорошо, чтобы избежать HTML в ограниченном смысле избежания HTML-тегов и объектов символов.

Но вам, возможно, придется также рассмотреть проблемы с кодировкой: если HTML, который вы хотите процитировать, имеет символы, отличные от ASCII, в определенной кодировке, тогда вам также следует позаботиться о том, чтобы вы представляли их разумно при цитировании. Возможно, вы можете преобразовать их в объекты. В противном случае вы должны убедиться, что правильные преобразования кодирования выполняются между "исходным" HTML и страницей, в которую он встроен, чтобы не повредить символы, отличные от ASCII.

Ответ 5

Существует также превосходный пакет markupsafe.

>>> from markupsafe import Markup, escape
>>> escape("<script>alert(document.cookie);</script>")
Markup(u'&lt;script&gt;alert(document.cookie);&lt;/script&gt;')

Пакет markupsafe хорошо спроектирован и, возможно, самый универсальный и Pythonic способ избежать, IMHO, потому что:

  1. return (Markup) - это класс, производный от Unicode (то есть isinstance(escape('str'), unicode) == True
  2. он правильно обрабатывает ввод Unicode
  3. это работает в Python (2.6, 2.7, 3.3 и pypy)
  4. он учитывает пользовательские методы объектов (т.е. объекты со свойством __html__) и перегрузки шаблона (__html_format__).

Ответ 6

Нет библиотек, чистый Python, безопасно экранирует текст в HTML-текст:

text.replace('&', '&amp;').replace('>', '&gt;').replace('<', '&lt;'
        ).encode('ascii', 'xmlcharrefreplace')

Ответ 7

cgi.escape extended

Эта версия улучшает cgi.escape. Он также сохраняет пробелы и символы новой строки. Возвращает строку unicode.

def escape_html(text):
    """escape strings for display in HTML"""
    return cgi.escape(text, quote=True).\
           replace(u'\n', u'<br />').\
           replace(u'\t', u'&emsp;').\
           replace(u'  ', u' &nbsp;')

например

>>> escape_html('<foo>\nfoo\t"bar"')
u'&lt;foo&gt;<br />foo&emsp;&quot;bar&quot;'

Ответ 8

Не самый простой способ, но все же простой. Основное отличие от cgi.escape модуля - оно по-прежнему будет работать правильно, если в тексте уже есть &amp;. Как вы видите из комментариев к нему:

cgi.escape version

def escape(s, quote=None):
    '''Replace special characters "&", "<" and ">" to HTML-safe sequences.
    If the optional flag quote is true, the quotation mark character (")
is also translated.'''
    s = s.replace("&", "&amp;") # Must be done first!
    s = s.replace("<", "&lt;")
    s = s.replace(">", "&gt;")
    if quote:
        s = s.replace('"', "&quot;")
    return s

регулярная версия

QUOTE_PATTERN = r"""([&<>"'])(?!(amp|lt|gt|quot|#39);)"""
def escape(word):
    """
    Replaces special characters <>&"' to HTML-safe sequences. 
    With attention to already escaped characters.
    """
    replace_with = {
        '<': '&gt;',
        '>': '&lt;',
        '&': '&amp;',
        '"': '&quot;', # should be escaped in attributes
        "'": '&#39'    # should be escaped in attributes
    }
    quote_pattern = re.compile(QUOTE_PATTERN)
    return re.sub(quote_pattern, lambda x: replace_with[x.group(0)], word)

Ответ 9

Через BeautifulSoup4:

>>> bs4.dammit import EntitySubstitution
>>> esub = EntitySubstitution()
>>> esub.substitute_html("r&d")
'r&amp;d'