【问题标题】:Python: Decoding base64 encoded strings within an HTML file and replacing these strings with their decoded counterpartPython:解码 HTML 文件中的 base64 编码字符串,并将这些字符串替换为解码后的对应字符串
【发布时间】:2018-04-20 10:59:08
【问题描述】:

请帮忙,因为这个翻转程序是我持续的噩梦!

我有几个包含一些 base64 编码字符串的文件。 示例文件的一部分内容如下:

charset=utf-8;base64,I2JhY2tydW5uZXJfUV81c3R7aGVpZ2h0OjkzcHg7fWJhY2tydW5uZXJfUV81c3R7ZGlzcGxheTpibG9jayFpbXBvcnRhbnQ7fQ==" 

它们始终采用“ANYTHINGbase64,STRING”格式 它是 html,但我将其视为一个大字符串并在其他地方使用 BeautifulSoup。我正在使用正则表达式'base'来提取base64字符串,然后根据我定义的函数“debase”使用base64模块对其进行解码。

这在一定程度上似乎没问题:b64encode 的输出由于某种原因添加了不必要的东西:

b'#backrunner_Q_5st{height:93px;}backrunner_Q_5st{display:block!important;}' 中间是字符串。

我猜这意味着以字节为单位;所以我尝试让我的函数将其编码为 utf8,但基本上我已经超出了我的深度。

我想要的最终结果是让我的 html 中的所有“base64,STRING”都被解码并替换为 DECODEDSTRING。

请帮忙!

import os, sys, bs4, re, base64, codecs
from bs4 import BeautifulSoup

def debase(instr):
    outstring = base64.b64decode(instr)
    outstring = codecs.utf_8_encode(str(outstring))
    outstring.split("'")[1]
    return outstring

base = re.compile('base64,(.*?)"')

for eachArg in sys.argv[1:]:
    a=open(eachArg,'r',encoding='utf8')
    presoup = a.read()
    b = re.findall(base, presoup)
    for value in b:
        re.sub('base64,.*?"', debase(value))
        print(debase(value))


    soup=BeautifulSoup(presoup, 'lxml')
    bname= str(eachArg).split('.')[0]
    a.close()
    [s.extract() for s in soup('script')]
    os.remove(eachArg)
    b=open(bname +'.html','w',encoding='utf8')
    b.write(soup.prettify())
    b.close()

【问题讨论】:

  • 中间的那些字符确实存在于base64编码的字符串中;字符集告诉您编码是 utf8,如果您使用 utf8 解码这些字节,您将得到“相同”的结果:都是 ASCII。所以问题是为什么这些字符存在于base64编码的字符串中。根据您的输出,我认为您的解码尝试是正确的。
  • 对不起,我不明白的是有一个额外的 b' ' 和撇号,我正在尝试删除
  • 所以我希望能够以纯文本形式交换它。但输出似乎是二进制或字节数据

标签: python html beautifulsoup base64 decoding


【解决方案1】:

您的输入格式有点奇怪(例如,结尾带有一个不匹配的单引号),因此请确保您没有做不必要的工作或以奇怪的方式解析内容。

无论如何,假设你的输入是给定的形式,你必须像刚才那样使用 base64 对其进行解码,然后使用给定的编码进行解码以获得字符串而不是字节串:

import base64

inp = 'charset=utf-8;base64,I2JhY2tydW5uZXJfUV81c3R7aGVpZ2h0OjkzcHg7fWJhY2tydW5uZXJfUV81c3R7ZGlzcGxheTpibG9jayFpbXBvcnRhbnQ7fQ=="'
head,tail = inp.split(';')
_,enc = head.split('=') # TODO: check if the beginning is "charset"
_,msg = tail.split(',') # TODO: check that the beginning is "base64"

plaintext_bytes = base64.b64decode(msg)
plaintext_str = plaintext_bytes.decode(enc)

现在两个结果是

>>> plaintext_bytes
b'#backrunner_Q_5st{height:93px;}backrunner_Q_5st{display:block!important;}'
>>> plaintext_str
'#backrunner_Q_5st{height:93px;}backrunner_Q_5st{display:block!important;}'

如您所见,字节的内容已经可读,这是因为内容是 ASCII。另请注意,我没有从您的字符串中删除尾随引号:base64 足够聪明,可以忽略内容中两个等式符号之后的内容。


简而言之,字符串是 python 3 中文本的某种抽象表示,如果您想用 1 和 0 流表示文本(从一个地方传输数据时需要),则需要特定的编码给另一个)。当您以字节为单位获取字符串时,您必须知道它是如何编码的,以便对其进行解码并获得正确的字符串。如果字符串与 ASCII 兼容,则编码相当简单,但是一旦出现更多通用字符,如果您使用错误的编码,您的代码就会中断。

【讨论】:

  • 快速问题:有单尾引号的原因是我用它来描绘正则表达式边界:有没有办法让正则表达式停止而不知道第一个无 base64编码字符在第一位?
  • @lgjmac 末尾的两个等式符号表示 base64 字符串的填充端。您始终可以在正则表达式中明确包含要匹配的字符作为 base64 字符串的一部分;但老实说,我怀疑使用 beautifulsoup 本身来提取您需要的信息应该很简单(即标签/字段/包含您的 base64 字符串的任何内容,而不必使用正则表达式),毕竟它是一个 html 解析器库。如果你不能这样做,你可以编写一个只匹配 base64 使用的 64 个字符的讨厌的正则表达式。我会尝试后者。
猜你喜欢
  • 2012-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多