• Python爬虫之HDU提交数据


    前一篇http://www.cnblogs.com/liyinggang/p/6094338.html 使用了爬虫爬取hdu 的代码,今天实现了将数据向hdu 提交的功能,接下来就是需要将两个功能合并了.

    这里感谢綦大神的博客, 不仅ACM玩得厉害,而且还精通各种语言.我辈楷模,我从他这里学会了怎么使用 chrome 抓包.按 F12,然後去找到NetWork就行了.然后就可以看到各种信息.

    比如在hdu的登录界面我们就可以看到如下信息:

     

     然后可以根据这些信息确定这个网页是需要Post方法还是GET方法,还有header的信息,以及发送数据的格式等等.

    我们总共是有三个网页需要进行解析:

    登录 

    网页: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> 标签弄出来,然后到每个里面找我的提交记录,这样分开处理要好多了,然后找状态就很简单了.这里网页里面如果有 符用 .*? 是匹配不到的,因为 . 是不包括换行符的所有字符,所以要用 [sS]或者 [dD]这种.

    /**这一段是更新,不看也无妨**/

    /*************更新*******************************/
    这里的话有另一种的方法可以得到我们所需的表单提交时所需的信息,我们能够利用 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)
        
    View Code

    /*********************/

    附上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[^>]+>([sS]*?)</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[^>]+>([sS]*?)</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([sS]*)main()[dD]+)')  #如果是代码里面一定包含 main() 函数
        regex1 = re.compile('^(#import([sS]*)main()[dD]+)')
        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的服务器我就不放源代码了,反正博客里都写好了(。・ω・。) ):

  • 相关阅读:
    BZOJ1588_营业额统计_KEY
    关于欧几里得算法的认识
    javacv实战篇
    图像处理里面的的尺度什么?
    改成 否“依然报LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏”问题的解决
    javacv
    以前写过的一些oracle语句
    warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失
    在vs环境中跑动sift特征提取(原理部分)
    《sift算法详解》阅读笔记
  • 原文地址:https://www.cnblogs.com/liyinggang/p/6119201.html
Copyright © 2020-2023  润新知