r""" Return normalized form of HTML which ignores insignificant output differences: Multiple inner whitespaces are collapsed to a single space (except in pre tags): >>> normalize_html(" a \t b ") ' a b ' >>> normalize_html(" a \t\nb ")
(html)
| 129 | 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'video', 'script', 'style']) |
| 130 | |
| 131 | def normalize_html(html): |
| 132 | r""" |
| 133 | Return normalized form of HTML which ignores insignificant output |
| 134 | differences: |
| 135 | |
| 136 | Multiple inner whitespaces are collapsed to a single space (except |
| 137 | in pre tags): |
| 138 | |
| 139 | >>> normalize_html("<p>a \t b</p>") |
| 140 | '<p>a b</p>' |
| 141 | |
| 142 | >>> normalize_html("<p>a \t\nb</p>") |
| 143 | '<p>a b</p>' |
| 144 | |
| 145 | * Whitespace surrounding block-level tags is removed. |
| 146 | |
| 147 | >>> normalize_html("<p>a b</p>") |
| 148 | '<p>a b</p>' |
| 149 | |
| 150 | >>> normalize_html(" <p>a b</p>") |
| 151 | '<p>a b</p>' |
| 152 | |
| 153 | >>> normalize_html("<p>a b</p> ") |
| 154 | '<p>a b</p>' |
| 155 | |
| 156 | >>> normalize_html("\n\t<p>\n\t\ta b\t\t</p>\n\t") |
| 157 | '<p>a b</p>' |
| 158 | |
| 159 | >>> normalize_html("<i>a b</i> ") |
| 160 | '<i>a b</i> ' |
| 161 | |
| 162 | * Self-closing tags are converted to open tags. |
| 163 | |
| 164 | >>> normalize_html("<br />") |
| 165 | '<br>' |
| 166 | |
| 167 | * Attributes are sorted and lowercased. |
| 168 | |
| 169 | >>> normalize_html('<a title="bar" HREF="foo">x</a>') |
| 170 | '<a href="foo" title="bar">x</a>' |
| 171 | |
| 172 | * References are converted to unicode, except that '<', '>', '&', and |
| 173 | '"' are rendered using entities. |
| 174 | |
| 175 | >>> normalize_html("∀&><"") |
| 176 | '\u2200&><"' |
| 177 | |
| 178 | """ |
| 179 | html_chunk_re = re.compile(r"(\<!\[CDATA\[.*?\]\]\>|\<[^>]*\>|[^<]+)") |
| 180 | try: |
| 181 | parser = MyHTMLParser() |
| 182 | # We work around HTMLParser's limitations parsing CDATA |
| 183 | # by breaking the input into chunks and passing CDATA chunks |
| 184 | # through verbatim. |
| 185 | for chunk in re.finditer(html_chunk_re, html): |
| 186 | if chunk.group(0)[:8] == "<![CDATA": |
| 187 | parser.output += chunk.group(0) |
| 188 | else: |