在python中生成HTML文档


70

在python中,生成HTML文档的最优雅的方法是什么。我目前将所有标签手动添加到一个巨大的字符串中,并将其写入文件中。有没有更优雅的方式做到这一点?


3
python html generator的可能重复项。如果要生成XHTML,还可以考虑使用XML工具。

1
几种适用于Python的模板系统。那是您要找的东西吗?
乔治·康明斯,

Answers:


61

我发现yattag是执行此操作的最优雅的方法。

from yattag import Doc

doc, tag, text = Doc().tagtext()

with tag('html'):
    with tag('body'):
        with tag('p', id = 'main'):
            text('some text')
        with tag('a', href='/my-url'):
            text('some link')

result = doc.getvalue()

它读起来像html,具有不必关闭标签的附加好处。


有一个类似但更容易的选择airium::stackoverflow.com/a/63952611/2823074
Mikaelblomkvistsson

33

我建议使用适用于python的许多模板语言中的一种,例如Django内置的一种 (您不必使用Django的其余部分来使用其模板引擎)-google查询应为您提供许多其他选择模板实现。

我发现学习模板库有很多帮助-每当您需要生成电子邮件,HTML页面,文本文件或类似文件时,只需编写一个模板,将其加载到模板库中,然后让模板代码创建即可成品。

以下是一些简单的代码,可以帮助您入门:

#!/usr/bin/env python

from django.template import Template, Context
from django.conf import settings
settings.configure() # We have to do this to use django templates standalone - see
# http://stackoverflow.com/questions/98135/how-do-i-use-django-templates-without-the-rest-of-django

# Our template. Could just as easily be stored in a separate file
template = """
<html>
<head>
<title>Template {{ title }}</title>
</head>
<body>
Body with {{ mystring }}.
</body>
</html>
"""

t = Template(template)
c = Context({"title": "title from code",
             "mystring":"string from code"})
print t.render(c)

如果您在磁盘上有模板,则更加简单-检出django 1.7的render_to_string函数,该函数可以从预定义的搜索路径列表中从磁盘加载模板,将字典中的数据填充并呈现为字符串-全部在一个函数调用中进行。(已从django 1.8上删除,请参见Engine.from_string以获取类似操作)


7
我想到了这一点,但我不认为这正是OP所要求的。听起来好像他们想以编程方式构建HTML本身,而模板假定您已经拥有HTML,但只需要填写一些变量即可。
Daniel Roseman

2
听起来好像他们已经准备好内容,然后需要在内容周围粘贴html。这正是模板引擎的用途。
野鸭2011年

5
另外,如果您想要像Django中那样的模板引擎,请使用Jinja2。它更快,更强大,并且是一个独立的项目。jinja.pocoo.org/docs
Wilduck

我正在一个项目中,我需要完全像这样的东西。我已将代码插入PyScripter。如何查看HTML输出。是否将其另存为.py文件或.html?我可以在浏览器中打开它吗?
Anon

11

如果您要构建HTML文档,那么我强烈建议使用其他人建议的模板系统(例如jinja2)。如果您需要一些低水平的html位生成(也许作为模板输入),那么xml.etree包是标准的python包,可能很合适。

import sys
from xml.etree import ElementTree as ET

html = ET.Element('html')
body = ET.Element('body')
html.append(body)
div = ET.Element('div', attrib={'class': 'foo'})
body.append(div)
span = ET.Element('span', attrib={'class': 'bar'})
div.append(span)
span.text = "Hello World"

if sys.version_info < (3, 0, 0):
  # python 2
  ET.ElementTree(html).write(sys.stdout, encoding='utf-8',
                             method='html')
else:
  # python 3
  ET.ElementTree(html).write(sys.stdout, encoding='unicode',
                             method='html')

打印以下内容:

<html><body><div class="foo"><span class="bar">Hello World</span></div></body></html>

1
除非我将其更改为“ sys.stdout.write(ET.tostring(html).decode(“ utf-8”),否则示例的最后一行对我而言失败,并显示“ TypeError:write()参数必须为str,而不是字节” ))”
劳尔·萨利纳斯,蒙特阿古

1
@RaúlSalinas-Monteagudo:原始代码段适用于python 2(在2.7上测试)。我已经对其进行了更新,以便它现在也适用于python 3(在3.5上测试)。
cheshirekow

注意ElementTree的安全风险Warning The xml.etree.ElementTree module is not secure against maliciously constructed data. If you need to parse untrusted or unauthenticated data see XML vulnerabilities.
jtpereyda

1
@jtpereyda很好地注意到了这一事实,但是在解析XML时存在此警告/漏洞,而OP明确要求生成(而不是解析)HTML。
cheshirekow

8

我建议使用xml.dom来做到这一点。

http://docs.python.org/library/xml.dom.html

阅读本手册页,它具有构建XML(以及XHTML)的方法。它使所有XML任务变得更加容易,包括添加子节点,文档类型,添加属性,创建文本节点。这应该能够帮助您完成创建HTML的大部分工作。

这对于分析和处理现有的xml文档也非常有用。

希望这可以帮助

聚苯乙烯

这是一个教程,可以帮助您应用语法

http://www.postneo.com/projects/pyxml/


3
HTML不是XML的子集。如果您使用的是XML工具,则将生成XHTML,而不是HTML。

1
严重缺乏Python没有标准的非XML版本,特定于html的版本(例如,具有div(id ='myid',otherattr ='...'),ul()等方法)的版本(有第三方的)。Perl和Ruby都可以。
JDonner 2012年

3

我正在throw_out_your_templates为自己的一些项目使用该代码段:

https://github.com/tavisrudd/throw_out_your_templates

https://bitbucket.org/tavisrudd/throw-out-your-templates/src

不幸的是,没有pypi软件包,它也不是任何发行版的一部分,因为这仅是概念验证。我也找不到能够接受该代码并开始将其维护为实际项目的人。尽管如此,我认为还是值得尝试的,即使这意味着您必须throw_out_your_templates.py随代码一起提供自己的副本。

与John Smith Optional关于使用yattag的建议类似,该模块不需要您学习任何模板语言,并且可以确保您永远不会忘记关闭标签或引用特殊字符。一切都用Python编写。这是一个如何使用它的示例:

html(lang='en')[
  head[title['An example'], meta(charset='UTF-8')],
  body(onload='func_with_esc_args(1, "bar")')[
      div['Escaped chars: ', '< ', u'>', '&'],
      script(type='text/javascript')[
           'var lt_not_escaped = (1 < 2);',
           '\nvar escaped_cdata_close = "]]>";',
           '\nvar unescaped_ampersand = "&";'
          ],
      Comment('''
      not escaped "< & >"
      escaped: "-->"
      '''),
      div['some encoded bytes and the equivalent unicode:',
          '你好', unicode('你好', 'utf-8')],
      safe_unicode('<b>My surrounding b tags are not escaped</b>'),
      ]
  ]

那将是非常有趣的。不幸的是,它非常古老:它是用Python 2编写的。我试图将其移植到Python 3中,但无法使其正常工作:它没有像HTML5Doc:
Regis

2

还有一个不错的,现代的替代方法airium::https : //pypi.org/project/airium/

from airium import Airium

a = Airium()

a('<!DOCTYPE html>')
with a.html(lang="pl"):
    with a.head():
        a.meta(charset="utf-8")
        a.title(_t="Airium example")

    with a.body():
        with a.h3(id="id23409231", klass='main_header'):
            a("Hello World.")

html = str(a) # casting to string extracts the value

print(html)

打印这样的字符串:

<!DOCTYPE html>
<html lang="pl">
  <head>
    <meta charset="utf-8" />
    <title>Airium example</title>
  </head>
  <body>
    <h3 id="id23409231" class="main_header">
      Hello World.
    </h3>
  </body>
</html>

的最大优点airium是-它还有一个反向转换器,可以从html字符串中构建python代码。如果您想知道如何实现给定的html代码段-转换器立即为您提供了答案。

它的存储库包含带有示例页面的测试,这些示例页面自动翻译airium为:tests / documents。一个很好的起点(任何现有的教程)-是这个:tests / documents / w3_architects_example_original.html.py


过去yattag(从当前投票最高的答案中)我使用过,但是我更喜欢此解决方案,因为对象之间没有隐式共享状态。
SethMMorton

哦,是的,yattag是上一代的airium。我强烈建议改用,airium因为1.更好,2.在airium(更高效的作曲家)中,大型文档的生成更快,3 .没有,但是airium拥有自己的编译器yattag
Mikaelblomkvistsson

-4

是的,您正在寻找文件.writelines

序列通常是列表或数组。因此,将所有行都放入列表或数组中。并将它们扔到下面的功能。

为了安全起见,请确保从字符串中删除所有新行常数。

Python文档(搜索file.writelines)

file.writelines(sequence)将字符串序列写入文件。该序列可以是产生字符串的任何可迭代对象,通常是字符串列表。没有返回值。(该名称旨在与readlines()匹配; writelines()不添加行分隔符。)


这根本不能回答问题。
Mikaelblomkvistsson
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.