前一篇http://www.cnblogs.com/liyinggang/p/6094338.html 使用了爬虫爬取hdu 的代码,今天实现了将数据向hdu 提交的功能,接下来就是须要将两个功能合并了.php
这里感谢綦大神的博客, 不只ACM玩得厉害,并且还精通各类语言.我辈楷模,我从他这里学会了怎么使用 chrome 抓包.按 F12,然後去找到NetWork就好了.而后就能够看到各类信息.css
好比在hdu的登陆界面咱们就能够看到以下信息:html
而后能够根据这些信息肯定这个网页是须要Post方法仍是GET方法,还有header的信息,以及发送数据的格式等等.c++
咱们总共是有三个网页须要进行解析:正则表达式
登陆 chrome
网页:http://acm.hdu.edu.cn/userloginex.php?action=login 数据: username=用户名&userpass=密码&login=Sign+In
提交:服务器
网页:http://acm.hdu.edu.cn/submit.php?action=submit 数据:problemid=pid&language=lang&usercode=code&check=1
而后获取状态的页面,下载好了而后再用正则表达式去匹配.这里对于每一个网页的下载,特别是这个 status 页面,我用本身写的Download 函数下不下来,多是HDU作了什么防爬虫的手段...这里关于传输数据,下载在网上参考了别人写的代码才搞定,可是它的正则表达式是有问题的...说说这个正则表达式吧,真的弄了我很久,由于我一直想很贪心的把本身的提交记录一会儿就给匹配到,这样反而作很差 (反正我是弄很差一句话去匹配,老是匹配多了 = =) 后来我直接先把全部的 <tr ** > </tr> 标签弄出来,而后到每一个里面找个人提交记录,这样分开处理要好多了,而后找状态就很简单了.这里网页里面若是有 \n 符用 .*? 是匹配不到的,由于 . 是不包括换行符的全部字符,因此要用 [\s\S]或者 [\d\D]这种.cookie
/**这一段是更新,不看也无妨**/ide
/*************更新*******************************/ 这里的话有另外一种的方法能够获得咱们所需的表单提交时所需的信息,咱们可以利用 lxml.html 的 cssselect 进行解析。 /*********************************************/ #coding:utf-8 import urllib2 import lxml.html __author__ = 'liyinggang' def getInputFromForm(html): '''This method is to use all the input tags of the form ''' tree = lxml.html.fromstring(html) data = {} for e in tree.cssselect('form input'): #使用css选择器遍历表单全部 input标签 if e.get('name'): data[e.get('name')] = e.get('value') return data if __name__ == '__main__': url = 'http://acm.hdu.edu.cn/userloginex.php' html = urllib2.urlopen(url).read() getInputFromForm(html)
/*********************/函数
附上code(^_^但愿你们学习爬虫不要不停地刷hdu界面,那样的话对你们都很差,hdu的维护靠你们~):
#coding:utf-8 ''' Created on 2016年11月29日 @author: liyinggang ''' import cookielib, logging from time import sleep import urllib2, urllib, re seed_url = "http://acm.hdu.edu.cn" login_url = "/userloginex.php?action=login" submit_url = "/submit.php?action=submit" status_url ="/status.php" class HDU: def __init__(self,username,password): self.username= username self.password = password self.code = None self.pid = 1000 self.retry=False cj=cookielib.CookieJar() opener=urllib2.build_opener(urllib2.HTTPCookieProcessor(cj),urllib2.HTTPHandler) #urllib2.urlopen()函数不支持验证、cookie或者其它HTTP高级功能。要支持这些功能,必须使用build_opener()函数建立自定义Opener对象。 urllib2.install_opener(opener) #这句必须加,开始一直登陆不上,可是具体为何依旧待弄清 self.headers ={"User-Agent":"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Mobile Safari/537.36"} def login(self): postdata = {'username': self.username, 'userpass': self.password, 'login': 'Sign In'} postdata = urllib.urlencode(postdata) try: request=urllib2.Request(seed_url+login_url,postdata,self.headers) response = urllib2.urlopen(request, timeout=10) html = response.read() if html.find('Sign Out')==-1: logging.error('login failed') return False print 'login success!' return True except: logging.error('login failed') return False def getstatus(self): postdata = {'user': self.username, 'lang': 0, 'first': '', 'pid': '', 'status': 0} postdata = urllib.urlencode(postdata) status = '' waitstatus = ['Compiling','Queuing','Running'] cnt = 0 #regex = '(<tr( bgcolor=#D7EBFF | )align=center >){1}(<td.*?</td>){2}<td><font color=.*?>(.*?)</font></td>(<td.*?</td>){5}<td class=fixedsize><a href="/userstatus.php\?user=%s">(?=.*?</a></td>)'%self.username while True: try: regex = '<table[^>]+>([\s\S]*?)</table>' request=urllib2.Request(seed_url+status_url,postdata,self.headers) response = urllib2.urlopen(request, timeout=10) html = response.read() table = re.findall(regex, html)[1] regex = '<tr[^>]+>([\s\S]*?)</tr>' L = re.findall(regex, table) result = L[1] regex = str(self.username) flag = True for i in L: if re.search(regex, i): flag = False result = i break #print result if flag: status = 'UNKNOWN ERROR' break regex = '<font[^>]+>(.*?)</font>' status = re.findall(regex, result)[0] if status not in waitstatus or cnt>=50: break cnt+=1 sleep(10) except: print '程序发生错误终止' return False print 'hduoj problem '+str(self.pid)+':'+status if status=='Compilation Error' and self.retry==False: self.retry = True self.submit(pid=self.pid,lang=2,code=self.code) if self.getstatus(): #再用c++交一次 return True if status=='Accepted': return True return False def submit(self,pid,lang,code): postdata = {'problemid':pid, 'language' :lang, 'usercode' : code, 'check': '1' } self.code = code self.pid = pid postdata = urllib.urlencode(postdata) try: request=urllib2.Request(seed_url+submit_url,postdata,self.headers) response = urllib2.urlopen(request, timeout=10) sleep(1) if(response.code!=200 and response.code!=302): logging.error("submit fail!") return False except: logging.error("submit fail!") return False print 'submit success!' return True
在blog里面提取想要代码(开头的连接已经有这部分功能了,不过整合一下,若是有大佬能提出修改意见,帮我提供更好的正则表达式固然再感谢不过,宝宝内心苦,博客园的代码解析出来有时候带有行号,因此干脆不要了,心塞塞(/TДT)/ ):
def getcode(url): '''返回值的第一个参数表明code,第二个参数表明用什么语言提交, 0是G++,5是 Java ''' D = Downloader(user_agent='lyg') html = D(url) tree = lxml.html.fromstring(html) texts = tree.cssselect('pre') texts.extend(tree.cssselect('p > textarea.cpp')) regex0 = re.compile('^(#include([\s\S]*)main()[\d\D]+)') #若是是代码里面必定包含 main() 函数 regex1 = re.compile('^(#import([\s\S]*)main()[\d\D]+)') for text in texts: text = text.text_content() pattern0 = re.search(regex0, text) pattern1 = re.search(regex1, text) if(pattern0): text = pattern0.group(1) return [text,0] if(pattern1): text = pattern1.group(1) return [text,5] return None
测试代码:
#coding:utf-8 ''' Created on 2016年11月29日 @author: admin ''' from HDU import HDU from time import sleep lang = 0 pid = 1000 code = ''' #include<stdio.h> int main() { int a,b; while(scanf("%d%d",&a,&b)!=EOF) printf("%d\\n",a+b); return 0; } ''' hdu = HDU('***','***') if(hdu.login()): if(hdu.submit(pid, lang, code)): sleep(2) hdu.getstatus()
下面是我完成以后的代码的运行功能(AC率挺高的,嘻嘻,不过为了HDU的服务器我就不放源代码了,反正博客里都写好了(。・ω・。) ):