2008-08-30 27 views
29

¿Cuál es la mejor forma de validar que un documento sigue alguna versión de HTML (preferiblemente que puedo especificar)? Me gustaría saber dónde ocurren los fallos, como en un validador basado en web, excepto en una aplicación nativa de Python.Validar (X) HTML en Python

+0

Tenga en cuenta que la validación es diferente de la limpieza! Algunas de las respuestas que publican las personas son acerca de la corrección automática de HTML, en lugar de simplemente verificar si el HTML es válido o no. – Flimm

Respuesta

8

XHTML es fácil, usa lxml.

HTML es más difícil, ya que tradicionalmente no ha habido tanto interés en la validación entre la multitud de HTML (ejecutar StackOverflow a través de un validador, ¡ay!). La solución más fácil sería ejecutar aplicaciones externas como nsgmls o OpenJade, y luego analizar su salida.

+0

Nota: el enlace lxml está roto. Use [este] (http://lxml.de/), tal vez? –

3

Creo que HTML tidy hará lo que quiera. Hay un enlace de Python para ello.

5

Prueba tidylib. Puede obtener enlaces realmente básicos como parte del módulo elementtidy (construye elementos de árbol a partir de documentos 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 

Analizar el registro debe darle más o menos todo lo que necesita.

11

Puede decidir instalar el validador de HTML localmente y crear un cliente para solicitar la validación.

Aquí hice un programa para validar una lista de URL en un archivo txt. Solo estaba revisando HEAD para obtener el estado de validación, pero si haces un GET obtendrás los resultados completos. Mira la API del validador, hay muchas opciones para ello.

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

Lamentablemente, 'html5lib' [no valida] (http://stackoverflow.com/a/29992363/593047). –

22

PyTidyLib es una buena unión para HTML Tidy pitón. Su ejemplo:

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 

Además es compatible tanto con legacy HTML Tidy y la new tidy-html5.

+3

Paquete en Debian: python-tidylib – sumid

15

creo que la forma más elegante para invocar el servicio de validación W3C en

http://validator.w3.org/ 

mediante programación. Pocas personas saben que usted no tiene a la pantalla-raspar los resultados con el fin de obtener los resultados, debido a que el servicio devuelve cabecera HTTP no estándar Paramaters

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

para indicar la validez y el número de errores y advertencias.

Por ejemplo, la línea de comandos

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

vuelve

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 

Por lo tanto, se puede elegantemente invocar el servicio de validación W3C y extraer los resultados de la cabecera 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) 
+6

También hay una API de servicio web completa para el Validador W3C y un enlace de Python: https://bitbucket.org/nmb10/py_w3c –

+0

Esta url está devolviendo 302 ahora y no 200. No funciona ahora! – sreeraag

0

En mi caso, los paquetes de validación de python W3C/HTML no funcionaron pip search w3c (a partir de septiembre de 2016).

He resuelto esto con

$ 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, ... 

más documentación aquí python requests, W3C Validator API

0

Este es un validador de HTML muy básico basado en HTMLParser de lxml. No requiere ninguna conexión a internet.

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

Tenga en cuenta que esto no va a comprobar si hay etiquetas de cierre, así por ejemplo, la siguiente pasará:

validate_html("<a href='example.com'>foo</a>") 

Sin embargo, el siguiente planteo:

validate_html("<a href='example.com'>foo</a")