本文将针对pythonchallenge中的问题,做一些学习笔记和解决答案,该网站以看图解谜的方式让玩家通过代码去解决答案,还是比较有意思的,有兴趣的可以独立的去做做看,在解谜中学习代码。
warm up
如图所示,只需要计算2的38次幂,然后把结果填入url中的数字即可
核心代码:2**38
level 4
问题4链接
这道题会做的人十分有技巧性,不会做的只能一番抓耳挠腮后憋出不是很美观的代码,虽然也能实现,但希望你能多思考该问题的解决方案
当你点击图片时,页面会发生跳转
看到这个数字,你肯定会想着把拿到的数字去替换掉原来url中的数字。等你替换几次后,他还是不断的跳出数字,系统也提醒你是不是复制累了,这时候就该上代码解决了。
核心步骤:
- 发送请求,获取响应中的数字
- 将上一请求拿到的数字去替换原来url中的数字
- 直至响应没有数字,此时的url就是通往下一关的大门。
先看看我的笨办法:
import re
import urllib.request
def listToString(s):
# initialize an empty string
str1 = " "
# return string
return (str1.join(s))
num="52899"
baseurl="http://www.pythonchallenge.com/pc/def/linkedlist.php?nothing="
url=baseurl+num
result=urllib.request.urlopen(url).read().decode('GBK')
pattern=re.compile(r'\d{1}.*')
resultNum=pattern.findall(result)
resultNum=listToString(resultNum)
while "next" in result :
num=resultNum
url=baseurl+num
result=urllib.request.urlopen(url).read().decode('GBK')
pattern=re.compile(r'\d{1}.*')
if "next" in result:
resultNum=pattern.findall(result)
resultNum=listToString(resultNum)
print(resultNum)
来讲几个核心函数:
result=urllib.request.urlopen(url).read().decode('GBK')
为什么这里要有read()和decode函数,最好的办法亲自动手去掉他,去掉decode,你会发现
在做字符串包含判断时,编译器提示,你不能在byte里用string的方法,decode就是将byte变成string,那么read呢,如果你去掉了
<http.client.HTTPResponse object at 0x03203450>
#没去掉的
'peak.html'
read就是将响应变得可读,接下来就是正则匹配的问题了,将响应中的进行数字匹配并提取,如果没匹配到数字了,说明已经到头了。
pattern=re.compile(r'\d{1}.*')
#\d代表数字,{1}代表重复次数。{3}时就代表有三个数字,.*代表至少后面还跟一位
resultNum=pattern.findall(result)
#findall匹配出的结果是存到list中,这时还需要将list转为string,这样才能将其加到url后
resultNum=listToString(resultNum)
def listToString(s):
# initialize an empty string
str1 = " "
# return string
return (str1.join(s))
看了这个方案是不是觉得太繁琐了,又要正则,又得list转换,重复代码还多,那就来看看四两拨千斤的方案
import urllib
import urllib2
data= {}
number = '12345'
for i in range(400):
data['nothing'] = number
url_values = urllib.urlencode(data)
url = 'http://www.pythonchallenge.com/pc/def/linkedlist.php'
full_url = url + '?' + url_values
foo = urllib2.urlopen(full_url)
foo = foo.read()
print foo
foo = foo.split(" ")
number = [i for i in foo if i.isdigit()][0]
惊讶于代码整洁性的同时,或许你会疑惑number = [i for i in foo if i.isdigit()][0]
是干嘛的,这也是最关键的一句,功能你能猜出来,但用法可能会有些疑惑:
明白了吗?他只是功能代码的缩写。expression代表你要对提取的数字的操作,来看个例子
foo = "next 12 4 5 6"
foo = foo.split(" ")
number = [int(i)+1 for i in foo if i.isdigit()]
print(number)
输出结果:
[13, 5, 6, 7]
详细解释摸我
知道了这个用法,其实你还可以发散一下思维,原来的list转string,用这个也能做了
s = ['I', 'want', 4, 'apples', 'and', 18, 'bananas']
# using list comprehension
listToStr = ' '.join([str(elem) for elem in s])
print(listToStr)
level 5
这题显得有些匪夷所思,还要做题者会读英文,当然也需要一定python基础才会知道,他要考察的是python的pickle,序列化,反序列化的函数,题目往往隐藏在页面源码的注释中,
import urllib2, sys, pickle
data = pickle.loads(urllib2.urlopen('http://www.pythonchallenge.com/pc/def/banner.p').read())
for line in data:
for char, count in line: sys.stdout.write(char * count)
sys.stdout.write("\n")
执行结果:图形是个channel英文
pickle的使用可以参看这篇文章:pickle tutorial
level 6
本题比较花里胡哨,先要下载一个zip文件,主要考察对zip文件的读取,解压后里面的txt文件内容显示的是Next nothing is 2144,主要找到没有next的文件就是答案了,同样需要用到正则匹配。
import zipfile
from zipfile import ZipFile
with ZipFile('E:\workspace\python\challenge\channel.zip', 'r') as zipObj:
# Get list of files names in zip
listOfiles = zipObj.namelist()
f=1
# Iterate over the list of file names in given list & print them
for elem in listOfiles:
a=zipObj.read(elem).decode('utf-8')
if "Next" in a:
f=1
else:
f=0
if f ==0:
print(a)
print(elem)
break
zipObj.close()
这里代码要排除readme的特殊文件,其他的都可以进行遍历去正则匹配,最后输出的文件内容为:Collect the comments.
到了这里,发现离答案还有距离
python操作zip