The Python Challenge

本文详细解析了PythonChallenge网站上的解谜过程,包括利用Python编程解决问题的方法和步骤,从第一关到第八关的解答,涉及数学计算、网页爬虫、正则表达式、图像处理等多个方面,提供了解题思路和代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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


第8关

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值