Экранирование плохого XML при разборе

1

Я пытаюсь проанализировать URL-адреса из файла Sitemap XML, который не является моим. К сожалению, некоторые из XML плохо написаны и содержат unescaped/invalid characters, такие как амперсанды.

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

from xml.etree import ElementTree as ET

tree = ET.parse('test.xml')
root = tree.getroot()

name_space = '{http://www.sitemaps.org/schemas/sitemap/0.9}'

urls = []
for child in root.iter():
    for block in child.findall('{}url'.format(name_space)):
        for url in block.findall('{}loc'.format(name_space)):
            urls.append('{}\n'.format(url.text))

with open('sample_urls.txt', 'w+') as f:
    f.writelines(urls)

Я сталкиваюсь с этой ошибкой, когда он сталкивается с неэкранированным URL: ParseError: неверно сформирован (недействительный токен).

Как я могу избежать этих проблем и продолжать разбирать файл? Я столкнулся с функцией escape() модуля xml.sax.saxutils, но не уверен, что лучший способ применить его на основе того, что у меня есть.

  • 0
    Я нашел способ обойти проблемы, переключившись на etree в наборе инструментов lxml и добавив 'parser = ET.XMLParser (recover = True)' и 'tree = ET.parse (' test.xml ', parser = parser)'. Это, кажется, отбрасывает ту часть URL, которая является проблематичной, и продолжается. Не такая идея, как побег, но может работать в крайнем случае.
  • 0
    Не можете ли вы предварительно обработать XML и удалить все недопустимые символы? Конечно, вы не можете избежать, например, элементов, не закрытых, но это должно быть началом. Также было бы хорошо, если бы вы могли опубликовать некоторые фрагменты XML с ошибками, с которыми вы сталкиваетесь.
Показать ещё 1 комментарий
Теги:
python-3.x
elementtree

2 ответа

1
Лучший ответ

Если можно, попробуйте использовать lxml.html. Вы должны быть осторожны, хотя; он игнорирует пространства имен, поэтому вам нужно быть уверенным, что вы выбираете то, что собираетесь на выбор.

Пример...

sitemap_products_1.xml (Укороченная версия той, с которой вы связались. Обратите внимание, что второй url имеет плохое значение loc.)

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
 xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
 <url>
  <loc>https://www.samsclub.com/sams/mirror-convex/prod13760282.ip</loc>
  <image:image>
   <image:title>See All 160 Degree Convex Security Mirror - 24&quot; w x 15&quot; h</image:title>
   <image:loc>https://scene7.samsclub.com/is/image/samsclub/0003308171524_A</image:loc>
  </image:image>
 </url>
 <url>
  <loc>https://www.samsclub.com/sams/at&t-3-handset-cordless-phone/prod21064454.ip</loc>
  <image:image>
   <image:title>AT&amp;T 3 Handset Cordless Phone</image:title>
   <image:loc>https://scene7.samsclub.com/is/image/samsclub/0065053003067_A</image:loc>
  </image:image>
 </url>
 <url>
  <loc>https://www.samsclub.com/sams/premium-free-flow-waterbed-mattress-kit-queen/104864.ip</loc>
  <image:image>
   <image:title>Premium Free Flow Waterbed Mattress Kit- Queen</image:title>
   <image:loc>https://scene7.samsclub.com/is/image/samsclub/0040649555859_A</image:loc>
  </image:image>
 </url>
</urlset>

Python 3.x

from lxml import html

tree = html.parse("sitemap_products_1.xml")

for elem in tree.findall(".//url/loc"):
    print(elem.text)

Вывод (обратите внимание, что второй URL-адрес полностью напечатан).

https://www.samsclub.com/sams/mirror-convex/prod13760282.ip
https://www.samsclub.com/sams/at&t-3-handset-cordless-phone/prod21064454.ip
https://www.samsclub.com/sams/premium-free-flow-waterbed-mattress-kit-queen/104864.ip
  • 0
    Интересно, это должно определенно работать для моих целей.
0

Учитывая пример, который вы опубликовали, я бы сказал, что использование регулярного выражения будет достаточно, когда дело доходит до символов &. То есть, если вы полностью не хотите удалить такие элементы <loc/>. Ниже приведен алгоритм, который поможет вам восстановить такие ошибки.

  1. Поскольку &t- внутри .../at&t-3-handset-cordless... явно не является допустимым символьным кодом амперсанда, вы можете захватить все между & и первым ; внутри значения <loc/> или начала закрывающего тега (</, который будет </loc>).

  2. Затем вы можете проверить, действительно ли захваченная строка является символьным символом (поскольку они ограничены, вы можете создать набор и проверить, находится ли строка внутри). Если это не так, замените этот (только тот!) Амперсанд с помощью &amp; строка.

  3. Продолжайте движение туда, где заменено & было и продолжайте повторять, пока вы не охватите полный элемент <loc/>.

После этого вы можете запустить синтаксический анализатор XML, и поскольку все недопустимые коды символов амперсанда были заменены, вы должны иметь возможность правильно сформировать XML, то есть, если нет других проблем с ним.

Обратите внимание, что это просто из головы.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню