虽然 & 编码应该是standard way。如果由于某些原因您确实需要避免转换,那么您可以这样做:
第 1 步。 查找不应存在于您的 html 源代码中的唯一字符串。如果您确信“ANDamp;”,您可以简单地使用 ANDamp; 作为您的 reserved_amp 变量字符串不会出现在您的 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;
由于最后一个字符的 冒号 安全防护是非 ASCII 字母,因此无法返回/解码错误的反转结果,例如 yy&YampX(原始为 yyYampX&)它永远不会从上面的string.ascii_lowercase + string.digits 生成为reserved_amp。
因此,确保随机不使用冒号(或其他非 ASCII 字符),然后将其附加在末尾(必须是最后一个字符)将无需担心 yyYampX& 会返回到 yy&YampX 陷阱。