#python #xml #web-services #parsing #minidom
#python #xml #веб-сервисы #синтаксический анализ #minidom
Вопрос:
Я запрашиваю веб-службу, используя urllib2.request, и получаю XML. Если я нарушаю ограничение скорости веб-службы (1 вызов в секунду), я получаю обратно HTML с сообщением, что я нарушил ограничение скорости.
Несмотря на то, что я могу time.sleep() в течение 2-3 секунд после каждого вызова, я все равно, по какой-либо причине, нарушаю ограничение скорости.
Чтобы проверить, является ли мой ответ XML или HTML, я использую xml.dom.minidom(), а затем проверяю наличие html-элемента
try:
dom = xml.dom.minidom.parseString(response_text)
except xml.parsers.expat.ExpatError:
return False
if len(dom.getElementsByTagName('html')) == 0:
return True
else:
return False
Это позволяет выполнить работу, но я столкнулся со случаем, когда один из XML-атрибутов содержит XML. В этом случае команда parseString() завершается ошибкой с
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/opt/python/default-2.6/lib/python2.6/xml/dom/minidom.py", line 1918, in parse
return expatbuilder.parse(file)
File "/opt/python/default-2.6/lib/python2.6/xml/dom/expatbuilder.py", line 924, in parse
result = builder.parseFile(fp)
File "/opt/python/default-2.6/lib/python2.6/xml/dom/expatbuilder.py", line 207, in parseFile
parser.Parse(buffer, 0)
xml.parsers.expat.ExpatError: not well-formed (invalid token): line 1, column 3125
В этом случае столбец 3125 является частью некоторого текстового значения атрибута, который содержит амперсанд-pound-x-9 (Stackoverflow скрывает мой unicode).
Должен ли xml.dom.minidom справиться с этим? Может ли быть другая проблема с XML, помимо этой, которая приводит к сбою синтаксического анализа?
Кроме того, я открыт для других способов решения такого рода ситуаций, если у сообщества есть такой.
Если это поможет, вот что веб-служба возвращает, когда я нарушил их ограничение скорости:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="eng">
<head>
<title>Service Temporarily Unavailable - Rate Limited</title>
</head>
<body style="text-align:center;background-color:white;">
<h1>Service Temporarily Unavailable</h1>
<hr />
<div>
You have used this service too often in a short time. Please wait before using this service again.
<br/><br/>
Please visit the <a href="http://wiki.xxxx.com/index.php?title=API_Usage">wiki</a> for more details.
</div>
</body>
</html>
Ответ №1:
Я думаю, что amp;#x9
это вкладка. Вы должны попробовать http://docs.python.org/library/htmllib.html#module-htmlentitydefs для преобразования специальных объектов html обратно в то, чем они являются. (Это может быть проблемой amp;<
и т.д.). Или вы могли бы выполнить замену строки, которая amp;#x9
заменяет пробел.
Просто в качестве предложения, когда вы разбираете материал, и анализатор сталкивается с проблемой, такой как несоответствие вашему шаблону, вместо остановки операции вы должны разрешить анализатору продолжить, но выдать предупреждение. Таким образом, вы можете увидеть, в чем проблема, и потенциально исправить ее или, по крайней мере, увидеть, что проблема существует.
Также что касается вашей проблемы с ограничением скорости, почему бы не кэшировать запрошенный HTML один раз, чтобы вы могли выполнять обработку локально.
Комментарии:
1. спасибо — я посмотрю. Проблема в том, что ограничение скорости API стороннего веб-сервиса нарушено. Они документируют 1 вызов в секунду, с чем я могу смириться, но даже если я сплю более 3 секунд, я все равно время от времени получаю ошибку ограничения скорости.
Ответ №2:
Вы также можете проверить строку на наличие HTML, прежде чем пытаться проанализировать результат:
if response_text.lstrip().startswith('<!DOCTYPE html'):
# we received an html response, sleep again
...
Я также не смог заставить minidom работать с атрибутом, содержащим объект tab. Возможно, это неправильно завершенная последовательность объектов, например, amp;#9
без конечной точки с запятой? Minidom, похоже, в порядке с правильно экранированными объектами внутри атрибутов:
text = '<root><a href="amp;#9;fooamp;<">link</a></root>'
tree = minidom.parseString(text)
print tree.toxml()
u'<?xml version="1.0" ?>n<root><a href="tfooamp;<">link</a></root>'