Cómo analizar HTML con entidades como & nbsp; usando la biblioteca integrada ElementTree en Python 2 y Python 3?

Hay momentos en los que desea analizar algunas páginas HTML razonablemente bien formadas, pero es reacio a introducir una dependencia de biblioteca adicional como BeautifulSoup o lxml. Por lo tanto, probablemente le gustará probar el ElementTree integrado primero, porque es una biblioteca estándar, es rápido (implementado en C) y admite una interfaz mucho mejor (como el soporte XPATH) que el HTMLParser básico. Sin mencionar, HTMLParser tiene sus propias limitaciones .

ElementTree funcionará, hasta que encuentre algunas entidades, como   , que no se manejan por defecto.

 import xml.etree.ElementTree as ET html = ''' 
Some reasonably well-formed HTML content.
It is not unusual to see   in an HTML page.
''' et = ET.fromstring(html)

Ejecútelo en Python 2 o Python 3, verá este error:

 xml.etree.ElementTree.ParseError: undefined entity: line 7, column 38 

Hay algunas preguntas y respuestas por ahí, como esta y aquella . ElementTree.XMLParser().parser.UseForeignDTD(True) usar ElementTree.XMLParser().parser.UseForeignDTD(True) pero no puedo hacer que funcione en Python 3.3 y Python 3.4.

 $ python3.3 Python 3.3.5 (v3.3.5:62cf4e77f785, Mar 9 2014, 01:12:57) [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import xml.etree.ElementTree as ET >>> ET.XMLParser().parser Traceback (most recent call last): File "", line 1, in  AttributeError: 'xml.etree.ElementTree.XMLParser' object has no attribute 'parser' >>> 

Inspirados por esta publicación , podemos anteponer alguna definición XML al contenido HTML sin procesar entrante, y ElementTree funcionaría sin conexión.

Esto funciona tanto para Python 2.6, 2.7, 3.3, 3.4.

 import xml.etree.ElementTree as ET html = ''' 
Some reasonably well-formed HTML content.
It is not unusual to see   in an HTML page.
''' magic = '''< !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" [ ]>''' # You can define more entities here, if needed et = ET.fromstring(magic + html)