在Python中验证(X)HTML

在Python中验证(X)HTML

Validate (X)HTML in Python

验证文档是否遵循某种版本的HTML(最好是我可以指定)的最佳方法是什么? 我希望能够知道失败发生的地方,例如基于Web的验证器,但本机Python应用程序除外。


PyTidyLib是HTML Tidy的不错的python绑定。他们的例子:

1
2
3
4
5
6
from tidylib import tidy_document
document, errors = tidy_document('''<p>
f&otilde;o <img src="bar.webp">'''
,
    options={'numeric-entities':1})
print document
print errors

此外,它与旧的HTML Tidy和新的tidy-html5兼容。


我认为以最优雅的方式调用W3C验证服务

1
http://validator.w3.org/

以编程方式很少有人知道您不必为了获得结果而对屏幕进行刮取,因为该服务返回了非标准的HTTP标头参数

1
2
3
4
X-W3C-Validator-Recursion: 1
X-W3C-Validator-Status: Invalid (or Valid)
X-W3C-Validator-Errors: 6
X-W3C-Validator-Warnings: 0

用于指示有效性以及错误和警告的数量。

例如,命令行

1
curl -I"http://validator.w3.org/check?uri=http%3A%2F%2Fwww.stalsoft.com"

退货

1
2
3
4
5
6
7
8
9
10
11
HTTP/1.1 200 OK
Date: Wed, 09 May 2012 15:23:58 GMT
Server: Apache/2.2.9 (Debian) mod_python/3.3.1 Python/2.5.2
Content-Language: en
X-W3C-Validator-Recursion: 1
X-W3C-Validator-Status: Invalid
X-W3C-Validator-Errors: 6
X-W3C-Validator-Warnings: 0
Content-Type: text/html; charset=UTF-8
Vary: Accept-Encoding
Connection: close

因此,您可以优雅地调用W3C验证服务并从HTTP标头中提取结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Programmatic XHTML Validations in Python
# Martin Hepp and Alex Stolz
# mhepp@computer.org / alex.stolz@ebusiness-unibw.org

import urllib
import urllib2

URL ="http://validator.w3.org/check?uri=%s"
SITE_URL ="http://www.heppnetz.de"

# pattern for HEAD request taken from
# http://stackoverflow.com/questions/4421170/python-head-request-with-urllib2

request = urllib2.Request(URL % urllib.quote(SITE_URL))
request.get_method = lambda : 'HEAD'
response = urllib2.urlopen(request)

valid = response.info().getheader('X-W3C-Validator-Status')
if valid =="Valid":
    valid = True
else:
    valid = False
errors = int(response.info().getheader('X-W3C-Validator-Errors'))
warnings = int(response.info().getheader('X-W3C-Validator-Warnings'))

print"Valid markup: %s (Errors: %i, Warnings: %i)" % (valid, errors, warnings)


您可以决定在本地安装HTML验证器,并创建一个客户端以请求验证。

在这里,我编写了一个程序来验证txt文件中的网址列表。我只是检查HEAD以获取验证状态,但是如果执行GET,则将获得完整结果。看一下验证器的API,有很多选择。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import httplib2
import time

h = httplib2.Http(".cache")

f = open("urllistfile.txt","r")
urllist = f.readlines()
f.close()

for url in urllist:
   # wait 10 seconds before the next request - be nice with the validator
   time.sleep(10)
   resp= {}
   url = url.strip()
   urlrequest ="http://qa-dev.w3.org/wmvs/HEAD/check?doctype=HTML5&uri="+url
   try:
      resp, content = h.request(urlrequest,"HEAD")
      if resp['x-w3c-validator-status'] =="Abort":
         print url,"FAIL"
      else:
         print url, resp['x-w3c-validator-status'], resp['x-w3c-validator-errors'], resp['x-w3c-validator-warnings']
   except:
      pass

XHTML很简单,使用lxml。

1
2
3
from lxml import etree
from StringIO import StringIO
etree.parse(StringIO(html), etree.HTMLParser(recover=False))

HTML更难,因为传统上对HTML人群的验证兴趣不大(通过验证器yikes运行StackOverflow本身)。最简单的解决方案是执行诸如nsgmls或OpenJade之类的外部应用程序,然后解析其输出。


尝试tidylib。您可以在elementtidy模块中获得一些真正的基本绑定(从HTML文档构建elementtrees)。 http://effbot.org/downloads/#elementtidy

1
2
3
4
5
6
>>> import _elementtidy
>>> xhtml, log = _elementtidy.fixup("<html></html>")
>>> print log
line 1 column 1 - Warning: missing <!DOCTYPE> declaration
line 1 column 7 - Warning: discarding unexpected </html>
line 1 column 14 - Warning: inserting missing 'title' element

解析日志应该可以为您提供几乎所有需要的东西。


我认为HTML整洁会做您想要的。有一个Python绑定。


这是基于lxml的HTMLParser的非常基本的html验证器。它不需要任何互联网连接。

1
2
3
4
5
6
7
8
_html_parser = None
def validate_html(html):
    global _html_parser
    from lxml import etree
    from StringIO import StringIO
    if not _html_parser:
        _html_parser = etree.HTMLParser(recover = False)
    return etree.parse(StringIO(html), _html_parser)

请注意,这不会检查结束标记,因此,例如,以下将通过:

1
validate_html("foo")

但是,以下内容不会:

1
validate_html("foo</a")

就我而言,python W3C / HTML验证软件包在pip search w3c上不起作用(截至2016年9月)。

我解决了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ pip install requests

$ python
Python 2.7.12 (default, Jun 29 2016, 12:46:54)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.57)] on darwin
Type"help","copyright","credits" or"license" for more information.

>>> r = requests.post('https://validator.w3.org/nu/',
...                    data=file('index.html', 'rb').read(),
...                    params={'out': 'json'},
...                    headers={'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36',
...                    'Content-Type': 'text/html; charset=UTF-8'})

>>> r.text
>>> u'{"messages":[{"type":"info", ...

>>> r.json()
>>> {u'
messages': [{u'lastColumn': 59, ...

此处提供更多文档python请求,W3C验证程序API


推荐阅读