The html.entities module in Python’s standard library contains reference tables that connect HTML entity names, Unicode characters, and code points. It is useful when an application needs to understand references such as &, ©, , or ☃, generate entity documentation, verify conversions, or build text-processing tools.
The module is not a complete HTML parser and it does not sanitize content. Its main role is to expose reference data. To process tags, attributes, comments, and text nodes, read the guide to Python html.parser. To convert an entire string containing HTML references, html.unescape() is usually the simpler high-level choice.
What an HTML entity is
An entity is a textual representation of a character. In HTML, an ampersand begins a character reference. A named reference uses an identifier, such as < for the less-than sign. A numeric reference uses a decimal or hexadecimal Unicode code point, such as < or <.
Character references exist because some characters have a special meaning in markup or may be inconvenient to type. However, every character does not need to become an entity. Modern HTML and UTF-8 can represent most symbols directly. The correct representation depends on the output context.
The module’s four dictionaries
The official documentation describes four main mappings:
html.entities.html5maps HTML5 named character references to their Unicode text.html.entities.name2codepointmaps HTML4 names to Unicode code points.html.entities.codepoint2namemaps Unicode code points back to HTML4 names.html.entities.entitydefscontains XHTML 1.0 entity definitions and replacement text.
These mappings are not interchangeable. HTML5 contains more names, and some references expand to more than one Unicode character. Select the table that matches the document standard and your purpose.
Looking up HTML5 entities
from html.entities import html5
print(html5["copy;"])
print(html5["nbsp;"])
print(html5["NotEqualTilde;"])
Keys in html5 commonly include the trailing semicolon. Some references accepted by the standard also appear without it. Do not automatically remove the semicolon before lookup because its absence can change parsing behavior in particular contexts.
A value may contain one or several Unicode characters. Never assume that len(value) is always one. That distinction matters when calculating positions, truncating text, highlighting matches, or creating a reverse index.
Searching entities by name
from html.entities import html5
prefix = "copy"
matches = {
name: value
for name, value in html5.items()
if name.lower().startswith(prefix)
}
for name, value in matches.items():
print(name, repr(value))
This pattern can support documentation pages, editor completion, or educational tools. In a web application, limit the number of returned items and never turn user-supplied names into raw HTML without contextual escaping.
Using name2codepoint
from html.entities import name2codepoint
codepoint = name2codepoint["euro"]
character = chr(codepoint)
print(codepoint)
print(character)
name2codepoint returns integers. The built-in chr() function converts a code point into a Unicode string. The reverse mapping is available through codepoint2name:
from html.entities import codepoint2name
name = codepoint2name.get(ord("©"))
print(name)
Use get() when a missing name is expected. Many Unicode characters have no named HTML4 entity. Your application can preserve the character, emit a numeric reference, or follow an explicit fallback policy.
Creating numeric references
def decimal_reference(character: str) -> str:
if len(character) != 1:
raise ValueError("Provide exactly one character")
return f"&#{ord(character)};"
print(decimal_reference("☃"))
For hexadecimal output, use f"&#x{ord(character):X};". Numeric references work for a wider range of characters, but they should still be produced according to context. Encoding every character as a reference makes documents larger and harder to read without automatically improving security.
When to use html.escape and html.unescape
The parent html module provides higher-level functions. html.escape() protects special characters when inserting plain text into basic HTML content. html.unescape() interprets named and numeric character references using HTML rules.
import html
text = "Tom & Jerry <3 programming"
escaped = html.escape(text)
restored = html.unescape(escaped)
print(escaped)
print(restored)
html.entities is the better fit when you need to inspect tables, understand a particular name, build an index, or implement a controlled conversion. For ordinary whole-string encoding and decoding, prefer the tested high-level functions.
Decoding is not sanitizing
This is the most important security distinction. Calling html.unescape("<script>") produces a string that contains a script tag. The function only converts references; it does not decide whether the result is safe to render.
If untrusted content must appear as text, escape it at the output boundary. If an application allows a subset of HTML, use a maintained sanitization library with an allowlist of tags and attributes. Do not attempt to build a sanitizer by stripping entities, using regular expressions, or blocking a handful of words.
Entities inside attributes
Attribute contexts have additional rules. A value inserted into href, src, style, or an event attribute cannot be protected merely by replacing angle brackets. URLs require scheme and origin validation, and dangerous attributes should not be accepted from untrusted authors.
For URL decomposition, the guide to Python urllib.parse explains components and encoding. Parsing a URL still does not make it trustworthy.
Optional semicolons
HTML5 accepts some named references without a semicolon under specific historical compatibility rules. The html5 table can contain both forms. When generating new HTML, use the semicolon. It is clearer and prevents ambiguity with letters or digits that follow the entity name.
from html.entities import html5
print("amp;" in html5)
print("amp" in html5)
When processing existing documents, let a standards-aware parser apply the rules. A custom routine that only searches from an ampersand to the next semicolon will fail on incomplete or ambiguous markup.
References with multiple characters
Some HTML5 references represent Unicode sequences rather than a single code point. Code that assumes a one-to-one relationship may truncate output or calculate the wrong index. Preserve the full string and include complex entities in tests.
from html.entities import html5
for name, value in html5.items():
if len(value) > 1:
print(name, [f"U+{ord(char):04X}" for char in value])
break
This also interacts with Unicode normalization. Two visually similar strings can use different sequences. For comparison and search, consider unicodedata.normalize(), described in the guide to Python unicodedata.
Building an entity catalog
from html.entities import html5
catalog = []
for name, value in sorted(html5.items()):
catalog.append({
"name": name,
"text": value,
"codepoints": [f"U+{ord(char):04X}" for char in value],
})
print(catalog[:3])
This catalog can be exported to JSON, CSV, or a documentation page. When creating HTML output, escape both labels and values through the template system. Even trusted standard-library data should travel through the correct output mechanism so future code changes do not accidentally introduce raw markup.
Handling unknown names
from html.entities import html5
def resolve(name: str) -> str | None:
key = name if name.endswith(";") else name + ";"
return html5.get(key)
print(resolve("copy"))
print(resolve("missing_entity"))
Do not silently replace an unknown entity with an empty string because that loses information. Preserve the source, return None, log a bounded warning, or reject the input according to the application contract.
Performance considerations
The tables are already dictionaries and key lookups are fast. Most applications should not copy the entire mapping repeatedly. Import once, reuse the objects, and create additional indexes only when a measured workload needs them.
For large documents, avoid running one replacement pass per entity. Use html.unescape() or an incremental parser. The html.parser guide demonstrates feeding input in chunks.
Recommended tests
Test common names, decimal and hexadecimal numeric references, optional semicolons, values containing several characters, unknown names, already escaped text, and malformed input. Test the final output context as well: text content, attributes, JSON, logs, or a database field.
A test should verify more than the resulting character. It should also verify the security policy. A correctly decoded string may still be unsafe to render as HTML.
Common mistakes
Frequent mistakes include using the HTML4 mapping for HTML5 content, assuming every value is one character, forgetting the semicolon, discarding unknown references, treating unescape() as a sanitizer, escaping too early and then double-escaping, and placing decoded values in URLs or attributes without contextual validation.
Conclusion
html.entities gives direct access to the relationships between HTML names and Unicode. It is valuable for catalogs, analysis tools, specialized converters, and validation. For common tasks, combine it with html.escape(), html.unescape(), and an appropriate parser.
Read the official html.entities documentation and the HTML named character reference list. Keep decoding, parsing, validation, escaping, and sanitization as separate operations.







