HTML-filtering in Python: verschil tussen versies
(7 tussenliggende versies door dezelfde gebruiker niet weergegeven) | |||
Regel 1: | Regel 1: | ||
+ | Dit artikel is ontstaan in 2018. Ik werkte voor een klant, die productbeschrijvingen in HTML had. Deze productbeschrijvingen wilde ik gebruiken voor Amazon. Echter, Amazon ondersteunt maar een beperkt aantal tags (en bv. geen externe links). Er moesten dus flink wat tags gefiltered en/of vervangen worden. Al snel bleek ''copy-paste'' geen oplossing te zijn. En toen ontstond dit artikel. | ||
+ | |||
+ | == HTMLParser-library == | ||
+ | |||
+ | Er zijn meer wegen die naar Rome leiden, maar de eerste weg die ik tegenkwam, was in de gedaante van de ''HTMLParser-library''. | ||
+ | |||
+ | De ''HTMLParser''-library (of -module) defineert een klasse ''HTMLParser'' waarmee je HTML kunt ''parsen''. Je voert 'm HTML-code, en hij roept diverse ''handler method'' aan. Die handler methods moet je ''overriden'' om ze te laten doen wat je wilt dat ze doen. De klasse kent ''handler methods'' en 'gewone' methods. | ||
+ | |||
== Eerste voorbeeld == | == Eerste voorbeeld == | ||
+ | |||
+ | Gebaseerd op [https://stackoverflow.com/questions/753052/strip-html-from-strings-in-python]: | ||
<pre> | <pre> | ||
Regel 22: | Regel 32: | ||
def strip_tags(html): | def strip_tags(html): | ||
s = MLStripper() | s = MLStripper() | ||
− | s.feed(html) | + | s.feed(html) # Feed is een HTMLParser class-method/function |
return s.get_data() | return s.get_data() | ||
Regel 31: | Regel 41: | ||
print(s) | print(s) | ||
print(o) | print(o) | ||
+ | </pre> | ||
+ | |||
+ | Output: | ||
+ | |||
+ | <pre> | ||
+ | <h1> Hello, <strong>world</strong></h1> | ||
+ | Hello, world | ||
+ | </pre> | ||
+ | |||
+ | == Voorbeeld: Selectief filter == | ||
+ | |||
+ | Hier is de truuk, dat ''sommige'' tags behouden moeten worden. Waarschijnlijk is dit geen erg mooi programmeervoorbeeld, maar het werkt wel: | ||
+ | |||
+ | <pre> | ||
+ | #! /usr/bin/python3 | ||
+ | # | ||
+ | # parser-03.py - Jan. 2019 | ||
+ | ############################################################################## | ||
+ | # | ||
+ | from html.parser import HTMLParser | ||
+ | |||
+ | class MyHTMLParser(HTMLParser): | ||
+ | |||
+ | def handle_starttag(self, tag, attrs): | ||
+ | # | ||
+ | # Starttags that need to be preserved or transformed | ||
+ | #################################################### | ||
+ | # | ||
+ | if tag=="br": self.s_output=self.s_output+"<br>" | ||
+ | if tag=="ul": self.s_output=self.s_output+"<ul>" | ||
+ | if tag=="li": self.s_output=self.s_output+"<li>" | ||
+ | |||
+ | def handle_endtag(self, tag): | ||
+ | # | ||
+ | # Endtags that need to be preserved or transformed | ||
+ | #################################################### | ||
+ | # | ||
+ | # print("Encountered an end tag :", tag) | ||
+ | # | ||
+ | if tag=="title": self.s_output=self.s_output+"<br>" | ||
+ | if tag=="h1": self.s_output=self.s_output+"<br>" | ||
+ | if tag=="h2": self.s_output=self.s_output+"<br>" | ||
+ | if tag=="h3": self.s_output=self.s_output+"<br>" | ||
+ | if tag=="ul": self.s_output=self.s_output+"</ul>" | ||
+ | |||
+ | def handle_data(self, data): | ||
+ | # | ||
+ | # Incorporate all actual data | ||
+ | #################################################### | ||
+ | # | ||
+ | # print("Encountered some data :", data) | ||
+ | # | ||
+ | self.s_output=self.s_output+data | ||
+ | |||
+ | def __init__(self): | ||
+ | # print("Dit is de __init__-functie") | ||
+ | self.reset() | ||
+ | self.strict = False | ||
+ | self.convert_charrefs= True | ||
+ | self.s_output = "" | ||
+ | |||
+ | def return_output(self): | ||
+ | # | ||
+ | # Some postprocessing + return parsed string | ||
+ | #################################################### | ||
+ | # | ||
+ | # * Maybe convert e.g. "<br> " to "<br>" | ||
+ | # | ||
+ | return ''.join(self.s_output) | ||
+ | |||
+ | |||
+ | ############################################################################## | ||
+ | # | ||
+ | s_input="<html><head><title>Title-data</title></head><body><h1>H1-title</h1>Gewone tekst met ümlaut en break<br> Gewone tekst<ul><li>LI-Item a<li>LI-Item 2</ul></body></html>" | ||
+ | print(" ") | ||
+ | print("######################################") | ||
+ | print(s_input) | ||
+ | |||
+ | parser = MyHTMLParser() | ||
+ | parser.feed(s_input) | ||
+ | print(parser.return_output()) | ||
+ | </pre> | ||
+ | |||
+ | Output: | ||
+ | |||
<pre> | <pre> | ||
+ | Title-data<br>H1-title<br>Gewone tekst met ümlaut en break<br> Gewone tekst<ul><li>LI-Item a<li>LI-Item 2</ul> | ||
+ | </pre> | ||
== Zie ook == | == Zie ook == | ||
Regel 42: | Regel 139: | ||
* https://stackoverflow.com/questions/753052/strip-html-from-strings-in-python - Uitgangspunt | * https://stackoverflow.com/questions/753052/strip-html-from-strings-in-python - Uitgangspunt | ||
* https://stackoverflow.com/questions/753052/strip-html-from-strings-in-python#13703994 - Preserve HTML-entiteiten | * https://stackoverflow.com/questions/753052/strip-html-from-strings-in-python#13703994 - Preserve HTML-entiteiten | ||
+ | * https://docs.python.org/3/library/html.parser.html - Interessant! |
Huidige versie van 24 jul 2019 om 18:46
Dit artikel is ontstaan in 2018. Ik werkte voor een klant, die productbeschrijvingen in HTML had. Deze productbeschrijvingen wilde ik gebruiken voor Amazon. Echter, Amazon ondersteunt maar een beperkt aantal tags (en bv. geen externe links). Er moesten dus flink wat tags gefiltered en/of vervangen worden. Al snel bleek copy-paste geen oplossing te zijn. En toen ontstond dit artikel.
HTMLParser-library
Er zijn meer wegen die naar Rome leiden, maar de eerste weg die ik tegenkwam, was in de gedaante van de HTMLParser-library.
De HTMLParser-library (of -module) defineert een klasse HTMLParser waarmee je HTML kunt parsen. Je voert 'm HTML-code, en hij roept diverse handler method aan. Die handler methods moet je overriden om ze te laten doen wat je wilt dat ze doen. De klasse kent handler methods en 'gewone' methods.
Eerste voorbeeld
Gebaseerd op [1]:
#! /usr/bin/python3 # # parser-01.py - Jan. 2019 ############################################################################## # from html.parser import HTMLParser class MLStripper(HTMLParser): def __init__(self): self.reset() self.strict = False self.convert_charrefs= True self.fed = [] def handle_data(self, d): self.fed.append(d) def get_data(self): return ''.join(self.fed) def strip_tags(html): s = MLStripper() s.feed(html) # Feed is een HTMLParser class-method/function return s.get_data() ############################################################################## # s="<h1> Hello, <strong>world</strong></h1>" o=strip_tags(s) print(s) print(o)
Output:
<h1> Hello, <strong>world</strong></h1> Hello, world
Voorbeeld: Selectief filter
Hier is de truuk, dat sommige tags behouden moeten worden. Waarschijnlijk is dit geen erg mooi programmeervoorbeeld, maar het werkt wel:
#! /usr/bin/python3 # # parser-03.py - Jan. 2019 ############################################################################## # from html.parser import HTMLParser class MyHTMLParser(HTMLParser): def handle_starttag(self, tag, attrs): # # Starttags that need to be preserved or transformed #################################################### # if tag=="br": self.s_output=self.s_output+"<br>" if tag=="ul": self.s_output=self.s_output+"<ul>" if tag=="li": self.s_output=self.s_output+"<li>" def handle_endtag(self, tag): # # Endtags that need to be preserved or transformed #################################################### # # print("Encountered an end tag :", tag) # if tag=="title": self.s_output=self.s_output+"<br>" if tag=="h1": self.s_output=self.s_output+"<br>" if tag=="h2": self.s_output=self.s_output+"<br>" if tag=="h3": self.s_output=self.s_output+"<br>" if tag=="ul": self.s_output=self.s_output+"</ul>" def handle_data(self, data): # # Incorporate all actual data #################################################### # # print("Encountered some data :", data) # self.s_output=self.s_output+data def __init__(self): # print("Dit is de __init__-functie") self.reset() self.strict = False self.convert_charrefs= True self.s_output = "" def return_output(self): # # Some postprocessing + return parsed string #################################################### # # * Maybe convert e.g. "<br> " to "<br>" # return ''.join(self.s_output) ############################################################################## # s_input="<html><head><title>Title-data</title></head><body><h1>H1-title</h1>Gewone tekst met ümlaut en break<br> Gewone tekst<ul><li>LI-Item a<li>LI-Item 2</ul></body></html>" print(" ") print("######################################") print(s_input) parser = MyHTMLParser() parser.feed(s_input) print(parser.return_output())
Output:
Title-data<br>H1-title<br>Gewone tekst met ümlaut en break<br> Gewone tekst<ul><li>LI-Item a<li>LI-Item 2</ul>
Zie ook
Bronnen
- https://stackoverflow.com/questions/753052/strip-html-from-strings-in-python - Uitgangspunt
- https://stackoverflow.com/questions/753052/strip-html-from-strings-in-python#13703994 - Preserve HTML-entiteiten
- https://docs.python.org/3/library/html.parser.html - Interessant!