PAT个人代码的抓取
August 5,2012
PAT是浙大的程序设计测
试平台,上面有浙大研究生机试和实验室面试所用题目。在参加复试之前曾在PAT上做过一段时间的题目,最近有同学索要代码,不幸的我本科四年所敲大部分代
码在一次重装系统过程中不慎遗失,而且特别令人费解的是,虽然PAT保留的用户所有提交代码,但是我却没有找见提交的搜索页面,只得一页一页地在提交记录
里面翻看。最近正在学Python,就拿Python抓一抓。 需要解决的问题有: 登录平台 个人提交编号的抓取 根据编号抓取代码 HTML字符转换 校园网VPN代理
PAT
的代码提交历史列表只有已登录用户才可查看,而且只能查看自己提交的代码。所以要实现代码的抓取,首先要过了登录一关,目测PAT采用的是cookie方
式进行验证,所以需要用到cookielib。实验室上外网要用VPN,需用到urllib2的ProxyHandler。初始化代码如下: 1 2 3 4 5 6 7 8 | def __init__( self ,userName,password):
self .userName = userName
self .password = password
self .cookie = cookielib.LWPCookieJar()
opener = urllib2.build_opener(proxy,urllib2.HTTPCookieProcessor( self .cookie))
urllib2.install_opener(opener)
|
登录采用POST方式,向http://pat./users/sign_in提交用户名和密码,同时保存生成的cookie。 1 2 3 4 5 6 7 8 9 10 11 12 13 | def login( self ):
postdata = {
'user[handle]' : self .userName,
'user[password]' : self .password
}
postdata = urllib.urlencode(postdata)
req = urllib2.Request(
data = postdata,
headers = self .header
)
result = urllib2.urlopen(req).read()
self .cookie.save( self .cookiefile)
|
获得某分页所有用户的提交列表:
1 2 3 4 5 6 7 8 | def getList( self ,page = 1 ):
req = urllib2.Request(
headers = self .header
)
result = urllib2.urlopen(req).read()
result = str (result)
return result
|
用正则表达式筛选出自己的提交:
1 2 3 4 5 6 7 8 9 10 | def getMine( self ,content):
tr = re. compile ( '<tr>.*?</tr>' ,re.S)
trs = tr.findall(content)
result = []
findme = re. compile ( '.*WAmaker.*' ,re.S)
for item in trs:
if findme.match(item):
result.append(item)
return result
|
利用正则表达式得到提交的ID和题目的ID,不得不说,正则的分组真是个好东西:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | def getIDs( self ,mysubs):
result = []
getID = re. compile ( '.*submissions/(\d+)">.*practise/(\d+)' ,re.S)
for item in mysubs:
ret = getID.match(item)
if ret:
result.append([ret.group( 1 ),ret.group( 2 )])
return result
def gao( self ):
li = []
for i in range ( 1 , 200 ):
print "Scanning page:" ,i,
content = user.getList(i)
res = user.getMine(content)
ll = user.getIDs(res)
li + = ll
print ".Done! Found" , len (ll)
fl = open ( 'res.dat' , 'w' )
cPickle.dump(li,fl)
fl.close()
|
根据提交ID进入代码查看页面,由于高亮过的代码含大量HTML标签,不适合抓取,还好页面的源代码里面还有未高亮处理的代码,不过还得用HTMLParser将>等字符转换回小于号等(当然字符串替换也可)。按照题目ID_提交ID的格式保存在本地:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | def getCode( self ):
fl = open ( 'res.dat' , 'r' )
li = cPickle.load(fl)
fl.close()
htmlpaser = HTMLParser()
for ID in li:
print 'Handling ' + ID [ 0 ] + '...' ,
req = urllib2.Request(
headers = self .header
)
result = urllib2.urlopen(req).read()
result = str (result)
patten = re. compile ( '<textarea.*?>.*</textarea>' ,re.S)
text = patten.findall(result)
code = re.match( '<textarea.*?>(.*)</textarea>' ,text[ 0 ],re.S).group( 1 )
ff = open ( 'pat/' + ID [ 1 ] + '_' + ID [ 0 ] + '.cpp' , 'w+' )
code = htmlpaser.unescape(code)
ff.write(code)
ff.close()
print 'Saved to pat/' + ID [ 1 ] + '_' + ID [ 0 ] + '.cpp'
|
|