BeautifulSoup .prettify()的自定义缩进宽度

时间:2013-03-19 20:07:31

标签: python beautifulsoup indentation code-formatting

有没有办法为.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代码,请告诉我。

4 个答案:

答案 0 :(得分:18)

我实际上是以最可能的方式处理这个问题:通过后处理结果。

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_2space代替prettify。这对于解决方案来说并不重要,但无论如何我们都要这样做,并将缩进宽度设为参数,而不是将其硬编码为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,你必须在那里做同样的事情。 (您可能希望创建一个可以应用于两者的通用包装器,而不是重复自己。)如果还有其他prettify方法,那么相同的交易。

答案 1 :(得分:5)

据我所知,这个功能并没有内置,因为这个问题有一些解决方案。

假设您使用的是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中的Tag类中):

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

然后向上滚动到Tag类中的decode方法并进行以下更改:

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('&lt; root&gt;&lt; child&gt;&lt; desc&gt; Text&lt; / desc&gt;&lt; / child&gt;&lt; / root&gt;')。美化(myTab = 4)将返回:

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

**无需修补BeautifulSoup类,因为它继承了Tag类。修补标记类足以实现目标。

答案 2 :(得分:1)

这是不增加原始功能等而增加缩进的一种方法。创建以下功能:

export default class Players extends React.Component {
   componentDidMount() {
      // Function for today
      let date = new Date();
      let day = date.getDay();
      console.log(day);
      let today =
         day === 0
            ? "sunday"
            : day === 1
            ? "monday"
            : day === 2
            ? "tuesday"
            : day === 3
            ? "wednesday"
            : day === 4
            ? "thursday"
            : day === 5
            ? "friday"
            : "saturday";
      console.log(today);
   }

   constructor() {
      super();
      this.state = {
         isFlipped: false,
      };
      this.handleClick = this.handleClick.bind(this);
   }

   handleClick(e) {
      e.preventDefault();
      this.setState((prevState) => ({ isFlipped: !prevState.isFlipped }));
   }

   render() {
      return (
         <AppTemplate>
            <h4 className="my-4 text-center text-color-white">Players</h4>
        <ReactCardFlip
           isFlipped={this.state.isFlipped}
           flipDirection="horizontal"
        >
           <div>
              <UserDataFront1 />
              <button
                 className="btn btn-primary btn-success mb-5"
                 onClick={this.handleClick}
              >
                 Click to see availability
              </button>
           </div>

           <div>
              <UserDataBack1 />
              <button
                 className="btn btn-primary btn-success mb-5"
                 onClick={this.handleClick}
              >
                 Back to info
              </button>
           </div>
        </ReactCardFlip>

        <ReactCardFlip
           isFlipped={this.state.isFlipped}
           flipDirection="horizontal"
        >
           <div>
              <UserDataFront2 />
              <button
                 className="btn btn-primary btn-success mb-5"
                 onClick={this.handleClick}
              >
                 Click to see availability
              </button>
           </div>

           <div>
              <UserDataBack2 />
              <button
                 className="btn btn-primary btn-success mb-5"
                 onClick={this.handleClick}
              >
                 Back to info
              </button>
           </div>
        </ReactCardFlip>

        <ReactCardFlip
           isFlipped={this.state.isFlipped}
           flipDirection="horizontal"
        >
           <div>
              <UserDataFront3 />
              <button
                 className="btn btn-primary btn-success mb-5"
                 onClick={this.handleClick}
              >
                 Click to see availability
              </button>
           </div>

           <div>
              <UserDataBack3 />
              <button
                 className="btn btn-primary btn-success mb-5"
                 onClick={this.handleClick}
              >
                 Back to info
              </button>
           </div>
        </ReactCardFlip>

        <ReactCardFlip
           isFlipped={this.state.isFlipped}
           flipDirection="horizontal"
        >
           <div>
              <UserDataFront4 />
              <button
                 className="btn btn-primary btn-success mb-5"
                 onClick={this.handleClick}
              >
                 Click to see availability
              </button>
           </div>

           <div>
              <UserDataBack4 />
              <button
                 className="btn btn-primary btn-success mb-5"
                 onClick={this.handleClick}
              >
                 Back to info
              </button>
           </div>
        </ReactCardFlip>

        <ReactCardFlip
           isFlipped={this.state.isFlipped}
           flipDirection="horizontal"
        >
           <div>
              <UserDataFront5 />
              <button
                 className="btn btn-primary btn-success mb-5"
                 onClick={this.handleClick}
              >
                 Click to see availability
              </button>
           </div>

           <div>
              <UserDataBack5 />
              <button
                 className="btn btn-primary btn-success mb-5"
                 onClick={this.handleClick}
              >
                 Back to info
              </button>
           </div>
        </ReactCardFlip>
     </AppTemplate>
  );

然后使用上述功能转换您获得的文本:

# Increase indentation of 'text' by 'n' spaces
def add_indent(text,n):
  sp = " "*n
  lsep = chr(10) if text.find(chr(13)) == -1 else chr(13)+chr(10)
  lines = text.split(lsep)
  for i in range(len(lines)):
    spacediff = len(lines[i]) - len(lines[i].lstrip())
    if spacediff: lines[i] = sp*spacediff + lines[i] 
  return lsep.join(lines)

答案 3 :(得分:0)

如果您使用的是pycharm,则可以通过按以下步骤自动重新格式化html文件:

ctrl + alt + L

同时在pycharm中打开经过修饰的html文件。

这会将缩进从一个空格更改为4,或者您在 Settings> Editor> Code Style> HTML 中为html设置的任何值(默认= 4)。

https://www.jetbrains.com/pycharm/guide/tips/reformat-code/

您必须对在其上运行prettify()的每个html文件执行此操作。

对不起,如果我正在恢复旧线程,但是我遇到了同样的问题,并找到了一个简单的解决方案。