2013-03-19 9 views
17

Gibt es eine Möglichkeit, benutzerdefinierte Einzug Breite für .prettify() Funktion zu definieren? Von dem, was ich von der Quelle bekommen kann -Benutzerdefinierte Einzug Breite für BeautifulSoup .prettify()

def prettify(self, encoding=None, formatter="minimal"): 
    if encoding is None: 
     return self.decode(True, formatter=formatter) 
    else: 
     return self.encode(encoding, True, formatter=formatter) 

Es gibt keine Möglichkeit, die Breite der Einrückung anzugeben. Ich denke, es ist wegen dieser Zeile in der decode_contents() Funktion -

s.append(" " * (indent_level - 1)) 

, die eine feste Länge von 1 Platz hat! (WARUM !!) Ich habe versucht, indent_level=4 Angabe, dass nur Ergebnisse in diesem -

<section> 
    <article> 
     <h1> 
     </h1> 
     <p> 
     </p> 
    </article> 
    </section> 

Welche einfach nur dumm aussieht. : |

Jetzt kann ich das weghacken, aber ich will nur sicher sein, wenn es etwas gibt, das ich vermisse. Weil dies ein grundlegendes Merkmal sein sollte. : -/

Wenn Sie eine bessere Möglichkeit haben, HTML-Codes zu verschönern, lassen Sie es mich wissen.

+0

Als Antwort auf Ihre Frage ("Warum?"): HTML und XML sind sehr, sehr tief verschachtelt, und ich denke die Crummy Typen wie 80-Spalten-Fenster. Aber vielleicht möchtest du einen Beitrag in der Mailing-Liste/Gruppe posten und/oder einen Fehler bei dieser Funktion einreichen (und da der Patch ziemlich einfach ist - und Ramabodhi hat es schon ziemlich für dich geschrieben - solltest du ihn mit deinem E-Mail/Bug einbinden) Bericht). – abarnert

+0

Es sieht so aus, als hätte jemand vor ein paar Jahren einen ähnlichen Patch gegen 3.2 an die Mailingliste geschickt. Siehe [hier] (https://groups.google.com/forum/?fromgroups=#!topic/beautifulsoup/B4qryJpJqpY). – abarnert

+0

"1 Leerzeichen Eindruck sieht einfach dumm.: |" - Vielen Dank. Dies ist genau das, was ich dachte, als ich nach diesem Problem suchte. – Brandin

Antwort

11

Ich habe mich selbst auf die hackiest Art und Weise behandelt: durch Nachbearbeitung des Ergebnisses.

r = re.compile(r'^(\s*)', re.MULTILINE) 
def prettify_2space(s, encoding=None, formatter="minimal"): 
    return r.sub(r'\1\1', s.prettify(encoding, formatter)) 

Eigentlich monkeypatched ich prettify_2space anstelle von prettify in der Klasse. Das ist nicht wesentlich für die Lösung, aber wir tun es trotzdem, und machen die indent Breite einen Parameter statt hartzucodieren es 2:

orig_prettify = bs4.BeautifulSoup.prettify 
r = re.compile(r'^(\s*)', re.MULTILINE) 
def prettify(self, encoding=None, formatter="minimal", indent_width=4): 
    return r.sub(r'\1' * indent_width, orig_prettify(self, encoding, formatter)) 
bs4.BeautifulSoup.prettify = prettify 

So:

x = '''<section><article><h1></h1><p></p></article></section>''' 
soup = bs4.BeautifulSoup(x) 
print(soup.prettify(indent_width=3)) 

... gibt:

<html> 
    <body> 
     <section> 
     <article> 
      <h1> 
      </h1> 
      <p> 
      </p> 
     </article> 
     </section> 
    </body> 
</html> 

Offensichtlich, wenn Sie Tag.prettify sowie BeautifulSoup.prettify patchen wollen, müssen Sie das gleiche tun dort. (Möglicherweise möchten Sie einen generischen Wrapper erstellen, den Sie auf beide anwenden können, anstatt sich selbst zu wiederholen.) Und wenn es noch andere Methoden gibt, gleichen Deal.

4

Soweit ich sagen kann, ist diese Funktion nicht eingebaut, da es eine Handvoll Lösungen für dieses Problem gibt. .

Angenommen, Sie verwenden BeautifulSoup 4, hier sind die Lösungen, die ich mit

Hard es in aufkam Diese minimale Änderungen erfordert, ist es in Ordnung, wenn Sie unter verschiedenen Umständen unterschiedlich nicht den Einzug sein müssen:

Ein weiteres Problem mit der vorherigen Lösung ist, dass der Textinhalt nicht vollständig konsistent, aber attraktiv eingerückt wird. Wenn Sie eine flexiblere/konsistentere Lösung benötigen, können Sie die Klasse einfach ändern. Finden

die Funktion und verschönern ändern sie als solche (es ist in der Tag-Klasse in element.py befindet):

#Add the myTab keyword to the functions parameters (or whatever you want to call it), set it to your preferred default. 
def prettify(self, encoding=None, formatter="minimal", myTab=2): 
    Tag.myTab= myTab # add a reference to it in the Tag class 
    if encoding is None: 
     return self.decode(True, formatter=formatter) 
    else: 
     return self.encode(encoding, True, formatter=formatter) 

Und dann in der Tag-Klasse zu dem Decodierverfahren nach oben und machen die folgende Änderungen:

if pretty_print: 
    #space = (' ' * (indent_level - 1)) 
    space = (' ' * (indent_level - Tag.myTab)) 
    #indent_contents = indent_level + Tag.myTab 
    indent_contents = indent_level + Tag.myTab 

zur decode_contents Methode in der Tag-Klasse Dann gehen und diese Änderungen vornehmen:

#s.append(" " * (indent_level - 1)) 
s.append(" " * (indent_level - Tag.myTab)) 

Jetzt BeautifulSoup ('<Wurzel> <Kind> <desc> Text </desc > </Kind > </root >') .prettify (MyTab = 4) kehrt:

<root> 
    <child> 
     <desc> 
      Text 
     </desc> 
    </child> 
</root> 

** No müssen die BeautifulSoup-Klasse patchern, da sie die Tag-Klasse erbt. Patching-Tag-Klasse ist ausreichend, um das Ziel zu erreichen.

+0

Dies sollte sehr einfach in einen Patch gegen den bs4 Source Tree umgewandelt werden, was praktisch ist. Der OP kann einfach seinen eigenen Zweig des bzr-Baumes machen und ihn patchen, den Patch upstream einreichen usw. – abarnert

+0

Danke Leute. Ich konnte einfach nicht glauben, dass nur eine Person in diesen Jahren ein Problem damit hatte und schlug einen Patch vor, der immer noch nicht zusammengeführt wird. Ich habe die Funktion bereits geändert, um variable Länge zu nehmen (weil ich hasse, Dinge hart zu kodieren). Es macht ziemlich genau das, was Sie vorgeschlagen haben. Aber die Sache ist, dass du etwas für "indent_level" bereitstellen musst wegen dieser Zeile 'pretty_print = (indent_level ist nicht None)' Und wie ich sehe, ist der Standardwert von 'indent_level' 'None' und es gibt keine dynamische Möglichkeit zu ändern es. <_ < –