2013-03-19 186 views
17

是否有任何方法可以爲.prettify()函數定義自定義縮進寬度?從我可以得到它的來源 -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) 

沒有辦法指定縮進寬度。我想這是因爲該線路decode_contents()功能 -

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

其中有1個空間固定長度! (爲什麼!)我試過指定indent_level=4,只是導致了這一點 -

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

它看起來真的是傻瓜。 :|

現在,我可以破解這個,但我只是想確定是否有什麼我失蹤。因爲這應該是一個基本功能。 : -/

如果您有一些更好的美化HTML代碼的方法,請告訴我。

+0

爲了回答你的問題(「WHY!」):HTML和XML往往嵌套得非常非常深,我猜測像80列窗口這樣的Crummy傢伙。但是你可能想要發佈到郵件列表/組和/或提交一個請求這個功能的bug(並且,因爲這個補丁非常簡單,而且ramabodhi已經爲你寫了很多東西),你應該將它包含在你的電子郵件/ bug中報告)。 – abarnert 2013-03-20 01:20:14

+0

幾年前,它似乎有人在3.2版本的郵件列表中提交了類似的補丁。請參閱[這裏](https://groups.google.com/forum/?fromgroups=#!topic/beautifulsoup/B4qryJpJqpY)。 – abarnert 2013-03-20 01:37:55

+0

「1格縮進看起來簡直愚蠢。」| |「 - 謝謝。這正是我在尋找這個問題時的想法。 – Brandin 2015-08-24 18:37:16

回答

11

我實際上用最簡單的方式處理了這個問題:通過後處理結果。

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)) 

其實,我代替prettify在類monkeypatched prettify_2space。這是該解決方案不是必需的,但讓我們做吧,使縮進寬度,而不是它硬編碼到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 

所以:

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

...給:

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

很明顯,如果你想補丁Tag.prettify以及BeautifulSoup.prettify,你必須在那裏做同樣的事情。 (您可能想要創建一個通用包裝器,您可以將它們應用於這兩者,而不是重複自己。)如果還有其他方法,則使用相同的處理。

4

據我所知,這個功能不是內置的,因爲這個問題有一些解決方案。 。

假設你正在使用BeautifulSoup 4,這裏是我想出了

硬編碼的解決方案,這需要最少的變化,如果你不需要縮進到在不同的環境不同,這是好的:

myTab = 4 # add this 
if pretty_print: 
    # space = (' ' * (indent_level - 1)) 
    space = (' ' * (indent_level - myTab)) 
    #indent_contents = indent_level + 1 
    indent_contents = indent_level + myTab 

以前的解決方案的另一個問題是,文本內容不會被完全一致地縮進,而是有吸引力的,仍然。如果您需要更靈活/一致的解決方案,您可以修改該類。

找到美化功能,並修改它本身(它位於element.py標籤類):

#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) 

然後向上滾動的標籤類的解碼方法,並進行以下變化:

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

然後去在Tag類的decode_contents方法,使這些變化:

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

現在BeautifulSoup( '<根> <孩子> <遞減>文本< /遞減> < /兒童> < /根>').prettify(MYTAB = 4)將返回:

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

**無需要修補BeautifulSoup類,因爲它繼承了Tag類。修補標記類足以實現目標。

+0

這應該很容易轉換成針對bs4源代碼樹的補丁,這很方便。 OP可以製作自己的bzr樹叉並修補它,向上遊提交補丁等。 – abarnert 2013-03-20 01:30:53

+0

謝謝你們。我無法相信這些年來只有一個人有這個問題,並且提出了一個補丁,但它仍然沒有合併。我已經修改了函數來採取可變長度(因爲我討厭硬編碼的東西)。它幾乎完成了你的建議。但是,你需要爲'indent_level'提供一些東西,因爲這行'pretty_print =(indent_level不是None)'而且我看到'indent_level'的默認值是'None',並且沒有動態的方法來改變它。 <_ < – 2013-03-20 06:27:19