上文介绍了Python Challenge第11至15关的通关攻略及代码,本文继续介绍第16至19关的通关攻略及代码。
第16关:let me get this straight
url:http://www.pythonchallenge.com/pc/return/mozart.html
16.1 攻略
界面中的图片有很多粉色的短横线,而图片下方以及源代码中都未找到隐藏的提示,因此应该需要处理的就是界面中的这一张图片。结合关卡名“let me get this straight”猜测是将每行的短横线移动拼接在一起,果然拼接后的图片显示出答案“romance”,因此修改url为http://www.pythonchallenge.com/pc/return/romance.html进入第17关。
16.2 代码
from PIL import Image
img = Image.open('mozart.gif')
width, height = img.size
new_img = Image.new('RGB', (width, height))
for j in range(height):
row = [img.getpixel((i, j)) for i in range(width)]
start = row.index(195)
new_row = row[start:] + row[:start]
for k in range(width):
new_img.putpixel((k, j), new_row[k])
new_img.show()
输出:
第17关:eat?
url:http://www.pythonchallenge.com/pc/return/romance.html
17.1 攻略
- 界面中是一些小饼干,查看源代码发现主体图片名为“cookies.jpg”,因此猜测本关与cookie有关。左下角是第4关的关卡图片(第4关攻略见Python Challenge第0至5关的通关攻略及代码),因此访问第4关url(http://www.pythonchallenge.com/pc/def/linkedlist.php)查看cookie发现提示信息info=“you should have followed busynothing…”。
- 结合第4关通关过程中首先访问的链接为http://www.pythonchallenge.com/pc/def/linkedlist.php?nothing=12345,我们将该链接中的nothing替换为busynothing,发现了类似第4关的提示信息,如下图所示,且cookie中同样有info信息,因此尝试按照第4关的方式从该url开始进行链式访问,并将cookie拼接起来,通过bz2解码后得到提示信息“is it the 26th already? call his father and inform him that “the flowers are on their way”. he’ll understand.”。
- 提示信息中提到“the flowers are on their way”,第15关提到买花的事情,因此里面的“他”指的是第15关的Mozart,百度查找莫扎特的爸爸是Leopold Mozart。
- “call his father”是说要给Leopold打电话,再结合第13关的打电话操作——xmlrpc,得到答案“555-VIOLIN”。因此修改url为http://www.pythonchallenge.com/pc/return/violin.html,但此时并未进入下一关,界面提示需要修改url为http://www.pythonchallenge.com/pc/stuff/violin.php。
- 修改后页面中出现了莫扎特爸爸的头像,页面标题提示“it’s me. what do you want?”,说明他爸爸接起来了电话但我们还有信息没给他,再次结合第2步中的提示需要将"the flowers are on their way"告诉他爸爸,尝试以cookie形式传递给该url,最后得到提示信息“oh well, don’t you dare to forget the balloons.”,修改url为http://www.pythonchallenge.com/pc/return/balloons.html进入第18关。
17.2 代码
import requests
import bz2
url = "http://www.pythonchallenge.com/pc/def/linkedlist.php?busynothing="
suffix = "12345"
info = ""
for i in range(400):
response = requests.get(url + suffix)
for cookie in response.cookies:
info += cookie.value
if response.text.split()[-1].isdigit():
suffix = response.text.split()[-1]
else:
break
print(info)
# Output:
# BZh91AY%26SY%94%3A%E2I%00%00%21%19%80P%81%11%00%AFg%9E%A0%20%00hE%3DM%B5%23%D0%D4%D1%E2%8D%06%A9%FA%26S%D4%D3%21%A1%EAi7h%9B%9A%2B%BF%60%22%C5WX%E1%ADL%80%E8V%3C%C6%A8%DBH%2632%18%A8x%01%08%21%8DS%0B%C8%AF%96KO%CA2%B0%F1%BD%1Du%A0%86%05%92s%B0%92%C4Bc%F1w%24S%85%09%09C%AE%24%90
import urllib.parse
print(bz2.decompress(urllib.parse.unquote_to_bytes(info)).decode('ascii'))
# Output:
# is it the 26th already? call his father and inform him that "the flowers are on their way". he'll understand.
import xmlrpc.client
proxy = xmlrpc.client.ServerProxy("http://www.pythonchallenge.com/pc/phonebook.php")
print(proxy.phone("Leopold"))
# Output:
# 555-VIOLIN
import requests
url = "http://www.pythonchallenge.com/pc/stuff/violin.php"
cookies = {"info": "the flowers are on their way"}
response = requests.get(url, cookies=cookies)
print(response.text)
# Output:
"""
<html>
<head>
<title>it's me. what do you want?</title>
<link rel="stylesheet" type="text/css" href="../style.css">
</head>
<body>
<br><br>
<center><font color="gold">
<img src="leopold.jpg" border="0"/>
<br><br>
oh well, don't you dare to forget the balloons.</font>
</body>
</html>
"""
第18关:can you tell the difference?
url:http://www.pythonchallenge.com/pc/return/balloons.html
18.1 攻略
- 界面中是两张天鹅的图片,关卡名提示寻找两张图片的不同,看起来只有亮度不同,查看源代码发现提示信息“it is more obvious that what you might think”,说明思路就是直白明显的,因此尝试修改url为http://www.pythonchallenge.com/pc/return/brightness.html。
- 在修改后的url源代码中发现新的提示信息“maybe consider deltas.gz”,因此修改url为http://www.pythonchallenge.com/pc/return/deltas.gz下载得到文件deltas.gz。
- 查看deltas.gz里面的txt文件发现数据刚好可以分成左右两部分,因此结合关卡名提示使用difflib对比左右两边的差异,对比结果可以分为:只在右边的、只在左边的、两者相同的三类,依次转换为二进制图像得到“butter”、“fly”、“…/hex/bin.html”三张图片,因此修改url为http://www.pythonchallenge.com/pc/hex/bin.html,用butter和fly分别作为用户名和密码登录进入第19关。
18.2 代码
import gzip
import difflib
import binascii
from PIL import Image
import io
left = [] #左半边数据
right = [] #右半边数据
with gzip.open('deltas.gz', 'rt', encoding='utf-8') as file:
content = file.read()
rows = content.split('\n')
for row in rows:
left.append(row[:53])
right.append(row[56:])
diff = difflib.Differ().compare(left, right) #比较差异
rightonly_list = [] #只在右边的
leftonly_list = [] #只在左边的
same_list = [] #相同的
for line in diff:
flag = line[0]
if flag == '+':
rightonly_list.append(line[1:].replace(" ", ""))
elif flag == '-':
leftonly_list.append(line[1:].replace(" ", ""))
else:
same_list.append(line[1:].replace(" ", ""))
data = binascii.unhexlify(''.join(rightonly_list))
img = Image.open(io.BytesIO(data))
img.show()
data = binascii.unhexlify(''.join(leftonly_list))
img = Image.open(io.BytesIO(data))
img.show()
data = binascii.unhexlify(''.join(same_list))
img = Image.open(io.BytesIO(data))
img.show()
输出:
第19关:please!
url:http://www.pythonchallenge.com/pc/hex/bin.html
19.1 攻略
- 界面是一张地图,没有明显信息,查看源代码发现如下图所示的提示信息,看起来是一封邮件,发件人是leopold.moz@pythonchallenge.com,附件是经过base64编码的“indian.wav”,提示需要我们打开附件,因此解码得到indian.wav。
- 播放音频听到“sorry”,因此修改url为http://www.pythonchallenge.com/pc/hex/sorry.html,界面提示“what are you apologizing for?”,说明还有信息未发现。
- 结合关卡图片地图的陆地和海水颜色颠倒,并且关卡源代码中提示“Maybe my computer is out of order.”,再次尝试将音频颠倒过来解码,播放得到“You are a idiot, hahahahaha”,因此修改url为http://www.pythonchallenge.com/pc/hex/idiot.html。界面中再次出现了莫扎特爸爸的头像,下面提示说“Now you should apologize…”,现在可以道歉了,点击“Continue to the next level”链接进入第20关http://www.pythonchallenge.com/pc/hex/idiot2.html。
19.2 代码
import base64
import speech_recognition as sr
with open('attachment.txt') as f:
s = f.read()
with open('india.wav', 'wb') as result:
result.write(base64.b64decode(s))
r = sr.Recognizer()
with sr.AudioFile('india.wav') as source:
audio_text = r.record(source)
print(r.recognize_sphinx(audio_text, language='en-US'))
# Output:
# sorry
import wave
with wave.open('india.wav', 'rb') as audio:
with wave.open('india_reverse.wav', 'wb') as result:
params = audio.getparams()
result.setparams(params)
for i in range(audio.getnframes()):
result.writeframes(audio.readframes(1)[::-1])
# 逐帧翻转后的音频带有背景音乐,语音识别效果不好,此处未进行语音识别
完整代码及运行结果详见: