Python Challenge是一个过关式的解谜站点,使用的是经典在线解谜站点Not Pr0n的模式:根据提示找出下一关的网页地址。和Not Pr0n不同的是,在每一关里你都需要编写程序来寻找答案。闯关地址:http://www.pythonchallenge.com/
本文的python代码的环境为 python3.5.1,代码运行过程需要抓取网页,所以需要联网才可以运行。
第0关
利用python计算 238
print(2**38) #274877906944
替换第0关的url中的数字0,即得到第一关的URL
第1关
1、根据提示1转化下面的一长串字符。
2、根据解密后的一长串字符的提示得到下一关的URL
#coding:utf-8
#需要安装第三库 BeautifulSoup4
#pip install BeautifulSoup4
from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen("http://www.pythonchallenge.com/pc/def/map.html")
bsObj = BeautifulSoup(html)
nameList = bsObj.findAll("br")
myStr=nameList[0].get_text()#提取加密的提示字符
fromStr='abcdefghijklmnopqrstuvwxyz'
toStr='cdefghijklmnopqrstuvwxyzab'
tbl = str.maketrans(fromStr, toStr)
print(myStr.translate(tbl))#得到解密后提示
'''
i hope you didnt translate it by hand.
thats what computers are for.
doing it in by hand is inefficient and
that's why this text is so long. using string.maketrans() is recommended.
now apply on the url.
'''
print('map'.translate(tbl))#得到地址 ocr
将ocr替换本关URL中的map即得到下一关的URL。
第2关
根据提示去查看网页源码,其中的注释中有: find rare characters in the mess below;下面是一堆字符。也就是找出这堆字符中常见字符也就是数字和字母了。
(本关主要利用正则表达式来求解,有关正则表达式可以参考这篇博文)
#coding:utf-8
from urllib.request import urlopen
import re
myStr=urlopen("http://www.pythonchallenge.com/pc/def/ocr.html").read()
myStr= myStr.decode('GBK')
myStr = ''.join(re.findall('%%(.*)-->',myStr,re.S))
result= ''.join(re.findall(r'[a-z]|[A-Z]|[0-9]',myStr))
print(result) #equality
将得到的结果equality替换本关URL中的ocr即可得到下一关的地址
第3关
跟上一关一样,也是从源码中给出的 一堆字符中查找满足条件的字符。
即: 找到这样的“小写字符”,其两侧恰好都被3个大写字母占据。
#coding:utf-8
from urllib.request import urlopen
import re
myStr=urlopen("http://www.pythonchallenge.com/pc/def/equality.html").read()
myStr= myStr.decode('GBK')
myStr = ''.join(re.findall('<!--(.*)-->',myStr,re.S))
result= ''.join(re.findall(r'[^A-Z][A-Z]{3}([a-z])[A-Z]{3}[^A-Z]',myStr))
print(result) #linkedlist
将本关的URL中的 equality.html替换为linkedlist.html,会提示你改为 linkedlist.php
第4关
一直抓取网页中出现的 数字替换nothing后面的数字的到下一个地址。中途会出现两次特殊情况。
#coding:utf-8
from urllib.request import urlopen
from bs4 import BeautifulSoup
import re
#获取最初的nothing值
html = urlopen("http://www.pythonchallenge.com/pc/def/linkedlist.php")
bsObj = BeautifulSoup(html)
link=bsObj.findAll("a")
link=link[0].attrs['href']
number=''.join(re.findall(r'=([0-9]*)',link))
number_pre=number
def getNumber(number):
myStr = urlopen("http://www.pythonchallenge.com/pc/def/linkedlist.php?nothing="+number).read()
print(myStr)
myStr= myStr.decode('GBK')
#number= ''.join(re.findall('\s([0-9]*)',myStr))
number= ''.join(re.findall('the next nothing is ([0-9]*)',myStr))
print('number:',number)
return number
while number:
number_pre=number
number=getNumber(number)
'''
Yes. Divide by two and keep going.
'''
number=str(int(number_pre,10)//2)
while number:
number_pre=number
number=getNumber(number)
'''
There maybe misleading numbers in the
text. One example is 82683. Look only for the next nothing and the next nothing is 63579
if number=='8268363579':
number='63579'
'''
运行完之后可以得到peak.html即为下一关的URL
第5关
这一关对python的pickle模块不熟悉的话比较难想到用pickle,而且后面的数据需要做过类似的题目,可能容易想到该怎么处理。
#coding:utf-8
import pickle
from urllib.request import urlopen
banner = urlopen('http://www.pythonchallenge.com/pc/def/banner.p').read()
banner = pickle.loads(banner)
#print(banner[2])
'''
for line in banner:
print ("".join(map(lambda pair: pair[0]*pair[1], line)))
'''
#根据banner中每一行中每个pair(字符,字符个数),根据pair组合成一个字符串输出
for linelist in banner:
line = [ch * count for ch, count in linelist]
print ("".join(line)) #channel
将channel替换peak即得到下一关的URL
第6关
将html改成zip可以下载到channel.zip文件,解压缩看到里面的 readme.txt给出了
welcome to my zipped list.
hint1: start from 90052
hint2: answer is inside the zip
所以从90052.txt开始处理
#coding:utf-8
import zipfile,re
z=zipfile.ZipFile('channel.zip')
number='90052'
zpp = []
def getNumber(number):
myStr=z.read('%s.txt' %number).decode('utf-8')
print(myStr)
number=''.join(re.findall('Next nothing is ([0-9]+)',myStr))
return number
while number:
zpp.append(number)
number=getNumber(number)
#得到提示:Collect the comments.
print (b''.join([z.getinfo('%s.txt' %p).comment for p in zpp]).decode('utf-8'))
运行代码之后可以得到下面这个图形:hocky,经hocky.html中的提示,hockey分别由什么字母组成。得到oxygen,将它替换channel得到下一关的URL
****************************************************************
****************************************************************
** **
** OO OO XX YYYY GG GG EEEEEE NN NN **
** OO OO XXXXXX YYYYYY GG GG EEEEEE NN NN **
** OO OO XXX XXX YYY YY GG GG EE NN NN **
** OOOOOOOO XX XX YY GGG EEEEE NNNN **
** OOOOOOOO XX XX YY GGG EEEEE NN **
** OO OO XXX XXX YYY YY GG GG EE NN **
** OO OO XXXXXX YYYYYY GG GG EEEEEE NN **
** OO OO XX YYYY GG GG EEEEEE NN **
** **
****************************************************************
**************************************************************
第7关
观察图片看见大概中间位置是灰度的。灰度图像的 R=G=B,再观察可以看见长灰度条多个小竖条,每个竖条的灰度值应该是相等的。这样每个7个像素点取一次灰度值。
#coding:utf-8
from PIL import Image
from io import BytesIO
from urllib.request import urlopen
import re
img = urlopen('http://www.pythonchallenge.com/pc/def/oxygen.png').read()#urlopen returns a bytes object
img = Image.open(BytesIO(img)) #Image.open requires a file-like object
#每个7个取一个象素点。事先判断出了灰度条大概在中间位置
row = [img.getpixel((x, 45)) for x in range(0, img.size[0], 7)]
#print(row)
ords = [r for r, g, b, a in row if r == g == b]
#print(ords)
print ("".join(map(chr, ords)))
#smart guy, you made it. the next level is [105, 110, 116, 101, 103, 114, 105, 116, 121]
print ("".join(map(chr, [105, 110, 116, 101, 103, 114, 105, 116, 121])))
#integrity
得到结果integrity
本文详细解析了PythonChallenge网站上的解谜过程,包括利用Python编程解决问题的方法和步骤,从第一关到第八关的解答,涉及数学计算、网页爬虫、正则表达式、图像处理等多个方面,提供了解题思路和代码实现。
4190

被折叠的 条评论
为什么被折叠?



