介绍
Python Challenge 是一个很久之前的网页闯关游戏,通过修改网址,不断的进行关卡探险。 大部分关卡都需要借助编程语言工具来进行闯关。
一共有 33 关。 开始网址是:The Python Challenge
计划
- 33关闯关完成,使用
Python语言;闯关完成24关 - 33关闯关完成,使用
Golang语言;
tips 建议:
- 注意阅读每关网页的名字(title), 里面包含了提示信息;
- 每关闯关成功是需要出现一张图片,如果没有图片,那本关就是没有闯关成功
资料归档
具体题目分析
第0关 warming up
看图找到提示:计算 2^38 二的三十八次方。
ans = 2 ** 38
print(ans) ## 274877906944
第1关 What about making trans?
看图找到提示: 这是一种古老的密码,关键就是往后移两位。
a_str = "abcdefghijklmnopqrstuvwxyz"
curr = "map"
ans = ""
for ss in curr:
idx = a_str.index(ss) + 2
ans += a_str[idx]
print(ans) # ocr
第2关 ocr
注意提示,查看页面源代码(重要的套路,后面的问题中经常遇到),发现其中有很长的一段代码。
# ./orc.txt中记录就是那一长段源代码中注释内容
with open('./orc.txt', 'r') as ff:
content = ff.read()
# print(content)
from collections import Counter
counter = Counter(content)
ans = ""
counter = sorted(counter.items(), key=lambda x:x[1]) # 可删去排序
# print(counter) ## type: list
for key, times in counter:
if times < 10: ans += key
print(ans) # equality
第3关 re
结合提示信息,三个大写字母夹杂一个小写,再跟三个大写字母,类似 ABCaDFG
与上一题一样,关键信息在源代码中寻找,发现其中有很长一段注释的(看似)乱码的字符串。
# 源码中那一长串被注释的字符串,存在./equality.txt 文件中
with open('./equality.txt', 'r') as ff:
content = ff.read()
import re
reg = re.compile('[a-z][A-Z]{3}[a-z][A-Z]{3}[a-z]')
res = reg.findall(content)
# print(res)
ans = [ss[4] for ss in res]
print("".join(ans)) # linkedlist, 注意后缀
提示: 输入结果后,根据页面内容提示要修改后缀。
第4关 follow the chain
查看网页源代码,有一个可点击的超链接URL,结合注释,通过不断修改来参数的值,跳转网页,最终得到新的网页内容。
from urllib import request
start = "12345"
i = 0
while True:
curr_url = f"http://www.pythonchallenge.com/pc/def/linkedlist.php?nothing={start}"
res = request.urlopen(curr_url)
content = res.read().decode('utf-8').split()
start = content[-1]
# print(i, start) # 运行时,可将此解开,可以看到具体的变化
i += 1
if "html" in start:
break
print(content) # peak.html
第5关 peak hell
网页源代码中有个 banner.p文件,下载下来,结合提示 peak hell ≈ pickle
python pickle 模块,可将Python对象转化成二进制格式文件或字符串,便于数据的存储和传输。
pickle.dumps(),pickle.loads()互为逆操作, 二进制格式和Python对象的相互转换。
import pickle
with open('./banner.p', 'rb') as f:
ss = f.read()
res = pickle.loads(ss)
print(res)
for row in res:
for key, times in row:
print(key * times, end="")
print() # channel
- 注意,这里最后是一个类似象形文字的有着特殊位置的排列的结果。
第6关 now there are pairs
这一关,干扰性比较强,但图片就是答案,也可以查看源代码,其中注释就是答案,修改后缀名。 输入正确网址(www.pythonchallenge.com/pc/def/chan…
zipfile 的 comment 是压缩文件的注释值。
from zipfile import ZipFile
ans = []
with ZipFile('./channel.zip') as zz:
filename = "90052.txt"
while filename in zz.namelist():
ans.append(zz.getinfo(filename).comment.decode('utf-8'))
with zz.open(filename) as ff:
content = ff.read().decode('utf-8')
filename = f"{content.split()[-1]}.txt"
# print(filename)
else:
print(content)
print("".join(ans)) # oxygen
- 注意,区别上一关,这里是使用拼凑图形的字母。
第7关 smarty
看图片上有一行马赛克,那一定是从图片中获取信息了。 点开源码,下载图片。
from PIL import Image
img = Image.open("./oxygen.png")
data = img.load()
width, height = img.size
res = ""
for i in range(0, width, 7):
r, g, b, x = data[i, height // 2]
if r == g: res += chr(r)
# print(res)
res = res.split("is ")[-1][1:-1].split(', ')
# print(res) # ['105', '110', '116', '101', '103', '114', '105', '116', '121']
ans = "".join([chr(int(item)) for item in res])
print(ans) # integrity
第8关,working hard?
图片提示:蜜蜂。 bz2库,查看页面源代码,下方由两排注释,思路就是解压内容。
bz2 是一种压缩算法。
bz2.compress()和bz2.decompress()互为逆向方法,压缩和解压
import bz2
un = b'BZh91AY&SYA\xaf\x82\r\x00\x00\x01\x01\x80\x02\xc0\x02\x00 \x00!\x9ah3M\x07<]\xc9\x14\xe1BA\x06\xbe\x084'
pw = b'BZh91AY&SY\x94$|\x0e\x00\x00\x00\x81\x00\x03$ \x00!\x9ah3M\x13<]\xc9\x14\xe1BBP\x91\xf08'
ans = []
for item in (un, pw):
res = bz2.decompress(item).decode('utf-8')
ans.append(res)
print(f'username: {ans[0]}, password: {ans[1]}')
第9关 connect the dots
查看页面源代码,下方有注释。处理注释的内容
first = [146,399,163,403,170,393,169,391,166,386,170,381,170,371,170,355,169,346,167,335,170,329,170,320,170,
310,171,301,173,290,178,289,182,287,188,286,190,286,192,291,194,296,195,305,194,307,191,312,190,316,
190,321,192,331,193,338,196,341,197,346,199,352,198,360,197,366,197,373,196,380,197,383,196,387,192,
389,191,392,190,396,189,400,194,401,201,402,208,403,213,402,216,401,219,397,219,393,216,390,215,385,
215,379,213,373,213,365,212,360,210,353,210,347,212,338,213,329,214,319,215,311,215,306,216,296,218,
290,221,283,225,282,233,284,238,287,243,290,250,291,255,294,261,293,265,291,271,291,273,289,278,287,
279,285,281,280,284,278,284,276,287,277,289,283,291,286,294,291,296,295,299,300,301,304,304,320,305,
327,306,332,307,341,306,349,303,354,301,364,301,371,297,375,292,384,291,386,302,393,324,391,333,387,
328,375,329,367,329,353,330,341,331,328,336,319,338,310,341,304,341,285,341,278,343,269,344,262,346,
259,346,251,349,259,349,264,349,273,349,280,349,288,349,295,349,298,354,293,356,286,354,279,352,268,
352,257,351,249,350,234,351,211,352,197,354,185,353,171,351,154,348,147,342,137,339,132,330,122,327,
120,314,116,304,117,293,118,284,118,281,122,275,128,265,129,257,131,244,133,239,134,228,136,221,137,
214,138,209,135,201,132,192,130,184,131,175,129,170,131,159,134,157,134,160,130,170,125,176,114,176,
102,173,103,172,108,171,111,163,115,156,116,149,117,142,116,136,115,129,115,124,115,120,115,115,117,
113,120,109,122,102,122,100,121,95,121,89,115,87,110,82,109,84,118,89,123,93,129,100,130,108,132,110,
133,110,136,107,138,105,140,95,138,86,141,79,149,77,155,81,162,90,165,97,167,99,171,109,171,107,161,
111,156,113,170,115,185,118,208,117,223,121,239,128,251,133,259,136,266,139,276,143,290,148,310,151,
332,155,348,156,353,153,366,149,379,147,394,146,399]
second = [156,141,165,135,169,131,176,130,187,134,191,140,191,146,186,150,179,155,175,157,168,157,163,157,159,
157,158,164,159,175,159,181,157,191,154,197,153,205,153,210,152,212,147,215,146,218,143,220,132,220,
125,217,119,209,116,196,115,185,114,172,114,167,112,161,109,165,107,170,99,171,97,167,89,164,81,162,
77,155,81,148,87,140,96,138,105,141,110,136,111,126,113,129,118,117,128,114,137,115,146,114,155,115,
158,121,157,128,156,134,157,136,156,136]
print(len(first), len(second)) ## 两倍关系
m, n = len(first), len(second)
x, y = [], []
for i in range(m):
xx = first[i]
if i % 2 == 0: x.append(xx)
else: y.append(xx)
for j in range(n):
xx = second[j]
if j % 2 == 0: x.append(xx)
else: y.append(xx)
from matplotlib import pyplot as plt
plt.scatter(x, y)
plt.show() # bull
第10关 what are you looking at?
查看源代码,发现有个.txt文件,点开是5个数组成的a数组,结合下面的问题,思路就是,找到a数组规律,计算第31位置的长度。
ans = []
pre, curr = "1", ""
for i in range(30):
start = nxt = 0
n = len(pre)
while start < n:
while nxt < n and pre[start] == pre[nxt]: nxt += 1
curr += str(nxt-start) + pre[start]
start = nxt
pre, curr = curr, ""
ans = len(pre)
print(ans) # 5808
第11关 odd even
一看这个图片那么奇怪,那就一定是要处理图片。结合title,思路是分开奇偶。
from PIL import Image
img = Image.open('./cave.jpg')
width, height = img.size
new_img = Image.new('RGB', (width//2, height//2))
for i in range(width):
for j in range(height):
pixel = img.getpixel((i,j))
new_img.putpixel((i//2-1, j//2-1), pixel) # 奇数
# new_img.putpixel((i//2, j//2), pixel) # 偶数
new_img.show() ## evil
第12关 dealing evil
查看页面源代码