Проверить (X)HTML в Python

Как лучше всего проверить, соответствует ли документ какой-либо версии HTML (желательно, которую я могу указать)? Я хотел бы знать, где происходят сбои, как в веб-валидаторе, за исключением собственного приложения Python.


person cdleary    schedule 30.08.2008    source источник
comment
Обратите внимание, что проверка отличается от уборки! Некоторые ответы, которые публикуют люди, касаются автоматического исправления HTML, а не простой проверки правильности HTML.   -  person Flimm    schedule 26.05.2017


Ответы (9)


XHTML — это просто, используйте lxml.

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

С HTML сложнее, так как традиционно HTML-толпа не проявляла особого интереса к валидации (запустите сам StackOverflow через валидатор, да). Самым простым решением будет выполнение внешних приложений, таких как nsgmls или OpenJade, а затем проанализируйте их вывод.

person John Millikin    schedule 30.08.2008

PyTidyLib — хорошая привязка Python для HTML Tidy. Их пример:

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

Более того, он совместим как с устаревшим HTML Tidy, так и с новый tidy-html5.

person Dave Brondsema    schedule 14.08.2009
comment
Пакет в Debian: python-tidylib - person sumid; 23.10.2012

Я думаю, что самый элегантный способ вызвать службу проверки W3C в

http://validator.w3.org/

программно. Мало кто знает, что вам не нужно очищать результаты, чтобы получить результаты, потому что сервис возвращает нестандартные параметры HTTP-заголовка.

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

для указания достоверности и количества ошибок и предупреждений.

Например, командная строка

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

возвращается

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:

# Programmatic XHTML Validations in Python
# Martin Hepp and Alex Stolz
# [email protected] / [email protected]

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)
person Martin Hepp    schedule 09.05.2012
comment
Этот URL теперь возвращает 302, а не 200. Сейчас не работает! - person sreeraag; 29.12.2015
comment
Элегантный, возможно, но не очень безопасный. - person RCross; 24.03.2021
comment
Если безопасность является проблемой, вы можете легко установить локальную копию валидатора W3C, как описано здесь: validator.w3.org/nu/about.html - person Martin Hepp; 30.03.2021

Вы можете установить валидатор HTML локально и создать клиент для запроса проверки.

Здесь я сделал программу для проверки списка URL-адресов в текстовом файле. Я просто проверял HEAD, чтобы получить статус проверки, но если вы сделаете GET, вы получите полные результаты. Посмотрите на API валидатора, вариантов для него предостаточно.

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
person karlcow    schedule 14.03.2009
comment
К сожалению, html5lib не проверяет. - person ron rothman; 25.01.2017

Попробуйте тидилиб. Вы можете получить некоторые действительно базовые привязки как часть модуля elementtidy (строит деревья элементов из HTML-документов). http://effbot.org/downloads/#elementtidy

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

Анализ журнала должен дать вам почти все, что вам нужно.

person Aaron Maenpaa    schedule 30.08.2008

Модуль html5lib можно использовать для проверки документа HTML5:

>>> import html5lib
>>> html5parser = html5lib.HTMLParser(strict=True)
>>> html5parser.parse('<html></html>')
Traceback (most recent call last):
  ...
html5lib.html5parser.ParseError: Unexpected start tag (html). Expected DOCTYPE.
person Changaco    schedule 27.03.2020

Я думаю, что HTML tidy сделает то, что вам нужно. Для него есть привязка Python.

person Neall    schedule 30.08.2008

Это очень простой валидатор HTML, основанный на HTMLParser lxml. Это не полный HTML-валидатор, но он выполняет несколько основных проверок, не требует подключения к Интернету и не требует большой библиотеки.

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

Обратите внимание, что при этом не будут проверяться закрывающие теги, поэтому, например, пройдет следующее:

validate_html("<a href='example.com'>foo")
> <lxml.etree._ElementTree at 0xb2fd888>

Однако следующее не будет:

validate_html("<a href='example.com'>foo</a")
> XMLSyntaxError: End tag : expected '>', line 1, column 29
person speedplane    schedule 24.10.2016
comment
Когда я нашел этот ответ, оценка была -1. Но это единственное, что у меня работает без установки чего-либо еще. Спасибо. - person HuongOrchid; 09.05.2019

В моем случае пакеты проверки Python W3C/HTML cli не работали (по состоянию на сентябрь 2016 года).

Я сделал это вручную, используя requests вот так

код:

r = requests.post('https://validator.w3.org/nu/', 
    data=open('FILE.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'})

print r.json()

в консоли:

$ echo '<!doctype html><html lang=en><head><title>blah</title></head><body></body></html>' | tee FILE.html 
$ 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.

>>> import requests

>>> r = requests.post('https://validator.w3.org/nu/', 
...                    data=open('FILE.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":[]}\n'

>>> r.json()
>>> {u'messages': []}

Дополнительная документация здесь запросы python, API W3C Validator

person user9869932    schedule 05.09.2016