Python 3中的Python挑战级别17

2024-09-30 20:18:08 发布

您现在位置:Python中文网/ 问答频道 /正文

我最近开始玩The Python Challenge。虽然相当复杂,但所需的编码并不十分困难,这使得学习许多有用的模块变得非常有趣。在

我的问题是关于17级的。我理解在收集曲奇的同时,按照4级所需的线索,我就是这样做的。但是,我不能对得到的字符串进行BZ2解压缩。在

我尝试了google,发现了一个很好的博客,里面有python2的解决方案。具体地说,17级的那个是here。通过分析,我意识到我确实得到了正确的压缩字符串(来自cookies),并且它在python2中得到了正确的解压:

bz2.decompress(urllib.unquote_plus(compressed))

但是,Python 3中的bz2.decompress需要一个字节数组而不是一个字符串,但是明显的Python 3对应于上面的行:

^{pr2}$

失败,返回OSError: Invalid data stream。我尝试了所有的standard encodings和上面的一些变体,但是没有用。在

到目前为止,我的(非工作)解决方案如下:

#!/usr/bin/env python3

"""
The Python Challenge #17: http://www.pythonchallenge.com/pc/return/romance.html

This is similar to #4 and it actually uses its solution. However, the key is in
the cookies. The page's cookie says: "you+should+have+followed+busynothing..."

So, we follow the chain from #4, using the word "busynothing" and
reading the cookies.
"""

import urllib.request, urllib.parse
import re
import bz2

nothing = "12345"
last_cookie = None
message = ""
while True:
    headers = dict()
    if last_cookie:
        headers["Cookie"] = last_cookie
    r = urllib.request.Request("http://www.pythonchallenge.com/pc/def/linkedlist.php?busynothing=" + nothing, headers=headers)
    with urllib.request.urlopen(r) as u:
        last_cookie = u.getheader("Set-Cookie")
        m = re.match(r"info=(.*?);", last_cookie)
        if m:
            message += m.group(1)
        text = u.read().decode("utf8")
        print("{} >>> {}".format(nothing, text))
        m = re.search(r"\d+$", text)
        try:
            nothing = str(int(m.group(0)))
        except Exception as e:
            print(e)
            break

print("Cookies message:", message)
print("Decoded:", bz2.decompress(urllib.parse.unquote_plus(message).encode("utf8")))

所以,我的问题是:解决上述问题的Python3解决方案是什么样子的?为什么我的解决方案不能像预期的那样工作?在

我很清楚这其中的一部分可以做得更好。我想要一个快速而肮脏的解决方案,所以我在这里的兴趣只在于它能起作用(为什么不能像我上面所说的那样)。在


Tags: the字符串messagecookieurllib解决方案decompressheaders
1条回答
网友
1楼 · 发布于 2024-09-30 20:18:08

您需要在这里使用^{} function。它不支持+到空间的映射,但这与str.replace()无关:

urllib.parse.unquote_to_bytes(message.replace('+', '%20'))

这样就可以很好地减压。您可以将生成的未压缩字符串解码为ASCII:

^{pr2}$

演示使用一条不同的消息,我准备不泄露谜题:

>>> import bz2
>>> import urllib.parse
>>> another_message = 'BZh91AY%26SY%80%F4C%E8%00%00%02%13%80%40%00%04%00%22%E3%8C%00+%00%22%004%D0%40%D04%0C%B7%3B%E6h%B1AIM%3D%5E.%E4%8Ap%A1%21%01%E8%87%D0'
>>> bz2.decompress(urllib.parse.unquote_to_bytes(another_message.replace('+', '%20'))).decode('ascii')
'This is not the message'

另一种方法是用cd4-UTF代替cd4-UTF。unquote_plus()的默认错误处理程序设置为'replace',因此您不会注意到原始数据无法解码为UTF-8,因此字节被U+FFFD替换字符替换,这是导致解压缩失败的原因。Latin-1将oe上的所有字节1直接映射到前256个Unicode字符,因此您可以将其编码回原始字节:

>>> '\ufffd' in urllib.parse.unquote_plus(another_message)
True
>>> bz2.decompress(urllib.parse.unquote_plus(another_message, 'latin1').encode('latin1')).decode('ascii')
'This is not the message'

相关问题 更多 >