Etree.tostring LXML, экранирующий URL в атрибутах ссылки href
При использовании LXML для анализа html-документа, а затем при помощи etree.tostring() я замечаю, что амперсанды в ссылках преобразуются в html-экранированные сущности.
Это разрыв связи по понятным причинам. Вот простой автономный пример проблемы:
>>> from lxml import etree
>>> parser = etree.HTMLParser()
>>> tree = etree.fromstring("""<a href="https://www.example.com/?param1=value1¶m2=value2">link</a>""", parser)
>>> etree.tostring(tree)
'<html><body><a href="https://www.example.com/?param1=value1&param2=value2">link</a></body></html>'
Я хотел бы, чтобы результат был:
<html><body><a href="https://www.example.com/?param1=value1¶m2=value2">link</a></body></html>
1 ответ
Хотя & кодирование должно быть стандартным способом. Если вам действительно необходимо избежать конвертации по каким-либо причинам, то вы можете сделать:
Шаг 1. Найдите уникальную строку, которой не должно быть в вашем HTML-источнике. Вы можете просто использовать ANDamp; как ваша переменная reserved_amp, если вы уверены "ANDamp;" Строка не будет отображаться в вашем источнике HTML. В противном случае вы можете сгенерировать случайный алфавит и убедиться, что эта строка не существует в вашем HTML-источнике:
>>> import random
>>> import string
>>> length = 15 #increase the length if it's still seems to be collide
>>> reserved_amp = "&"
>>> html = """<a href="https://www.example.com/?param1=value1¶m2=value2">link</a>"""
>>> while reserved_amp in [html, "&"]:
... reserved_amp = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(length)) + "amp;" #amp; is for you easy to spot on
...
>>> print reserved_amp
2eya6oywxg5z7q5amp;
Шаг 2. заменить все вхождения & перед анализом:
>>> html = html.replace("&", reserved_amp)
>>> html
'<a href="https://www.example.com/?param1=value12eya6oywxg5z7q5amp;param2=value2">link</a>'
>>>
Шаг 3. Замените его обратно, только если вам нужна оригинальная форма:
>>> from lxml import etree
>>> parser = etree.HTMLParser()
>>> tree = etree.fromstring(html, parser)
>>> etree.tostring(tree).replace(reserved_amp, "&")
'<html><body><a href="https://www.example.com/?param1=value1¶m2=value2">link</a></body></html>'
>>>
[ОБНОВИТЬ]:
Двоеточие поставить в конце reserved_amp
это безопасный охранник.
Что если мы сгенерировали reserved_amp
как это?
ampXampXampXampX + amp;
И HTML содержит:
yyYampX&
Это будет закодировано в этой форме:
yyYampXampXampXampXampXamp;
Тем не менее, невозможно вернуть / декодировать неправильный результат yy&YampX
(оригинал yyYampX&
) из-за того, что последний символ защищен двоеточием, это не алфавит ASCII, который никогда не будет сгенерирован как reserved_amp
от string.ascii_lowercase + string.digits
выше.
Таким образом, убедитесь, что случайным образом не используется двоеточие (или другой не-ASCII символ), а затем добавьте его в конце (ДОЛЖЕН быть последним символом), не нужно беспокоиться о yyYampX&
вернуться к yy&YampX
ловушка.
Согласно документации lxml tostring(),method='xml'
можно передать, чтобы избежать специфики html
etree.tostring(tree, method='xml')
В своих проектах я использую:
from lxml import html
html.tostring(node, with_tail=False, method='xml', encoding='unicode')