hdu—自动AC机(python)

这里再次对所有跟我一样学习ACM的同学和大佬以及hdu管理员陪个不是,毕竟这只是个取巧的方式......望见谅

(测试发现C++的通过率实在有点尴尬,并且出现了大部分转码有问题造成CE的情况....在学长的建议下转投python大法.....然后排名直冲第二...)






python跟C++不一样的地方是python对爬虫,网页操作等着极好的封包操作,在这里选用requests第三方库进行POST和GET的操作,特别是这个BeautifulSoup,能够非常方便的从网页中某个标签内提取自己需要的东西
import requests
import re
import time
from bs4 import BeautifulSoup

(一) 整体思路
整体思路分成两个操作,一个是页面操作,一个是爬取代码
网页操作中包含三个函数
1.login()   //登录操作
2.submit() //提交代码操作
3.getsolve()  //从个人界面中提取已AC的所有题号,判断当前题目是否被AC
爬取代码中包含一个函数
1.getcsdn()   //在百度搜索中查找csdn博客题解,并且提取第一页中所有博客中的代码


(1)模拟浏览器
python跟C++一样,需要浏览器环境支持,C++代码中我不知道怎么模拟浏览器环境,但是python模拟浏览器环境非常方便
 def __init__(self):
        self.session = requests.Session()
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36'
        }
        self.session.headers.update(headers)
(2)利用POST模拟账号登录


利用F12抓包,在network里可以看到,在登录的时候会需要用到login操作界面,而这个界面的data中需要三个内容,username,userpass和login,所以只要我们在data中填上这三个内容,就可以实现登录操作
def login(self, username, password):
        url = 'http://acm.hdu.edu.cn/userloginex.php?action=login'
        data = {
            'username': username,
            'userpass': password,
            'login': 'Sign In'
        }
        r = self.session.post(url, data=data)

(3)在个人界面中查看自己已通过的题目,判断当前题目是否通过


打开个人界面,F12查看HTML源代码,一层层标签展开后我们可以发现,有一个'p'标签,格式为align='left'的标签内存放着“List of solved problems”
这里就要用到python的BeautifulSoup函数库了,Beautiful Soup提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。它是一个工具箱,通过解析文档为用户提供需要抓取的数据
所以在对HTML进行BeautifulSoup操作后,我们可以直接找到格式为align='left'的'p'标签并且提取出这个标签内的所有内容,并对这段字符串进行处理,提取出我们已经AC的题号集合
def getsolved(self, username):
        url = 'http://acm.hdu.edu.cn/userstatus.php?user=%s' %username
        solved = []
        r = self.session.get(url)
        soup = BeautifulSoup(r.text, 'html.parser')
        res = soup.find('p', align='left')
        # print(res)
        str = res.text.split(';')
        for item in str:
            if item:
                item = re.search(r'\d{4}', item)
                solved.append(item.group(0))
        return solved

(4)在确定当前题目没有被通过后,我们需要考虑在网上搜索这道题的题解,并且提取代码
首先搜索代码想到的肯定是百度了,但是在我C++爬虫文章中写过,百度的搜索都进行了转义加密,但是python有一个好处,有个命令叫match,所以就不要紧了。
对于如何查看搜索界面中所有标签,跟上面一样,使用F12展开标签页,找到包含搜索结果链接的标签页,并且提取所有链接也就是find_all,在提取了搜索界面所有链接后,我们只要match所有链接中是否存在csdn链接,保存所有csdn链接即可
同样,在csdn中我们可以发现



代码框中的代码被分成每行一个class,这样的话就非常难以提取代码,但是我们在python代码中输出找到的网页源代码,可以发现是不一样的,所有代码被放在一个'pre'标签内,内容是name="code"




所以我们可以按照这个提取代码,提取格式为name='code'的'pre'标签内的内容,并且存下所有代码

def getcsdn(self, problemID):
        solutions = []
        solutionurls = []
        url = r'http://www.baidu.com/s?wd=hdu%20' + str(problemID) +'%20csdn' #r防止转义
        baidusession = requests.session()
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36'
        }
        baidusession.headers.update(headers)
        r = baidusession.get(url)
        soup = BeautifulSoup(r.text, 'html.parser')
        res = soup.find_all('a', attrs={'target': '_blank', 'class': 'c-showurl', 'style': 'text-decoration:none;'})
        for item in res:
            if re.match("blog.csdn.net", item.text):
                solutionurls.append(item['href'])
        for item in solutionurls:
            r = baidusession.get(item)
            soup = BeautifulSoup(r.text, 'html.parser')
            code = soup.find('pre',attrs={'name': 'code'})
            if code:
                solutions.append(code.text)
                #print(code.text)
        return solutions




(5)获得代码后,利用submit函数提交程序到指定题目


同样的利用F12的network抓包,手动提交一次之后可以发现,真正的提交操作是在url=http://acm.hdu.edu.cn/submit.php?action=submit
这个页面中的,另外我们可以发现,data中需要填入的有check,problemid,language和usercode
problemid和usercode很容易看清楚是什么,那么languag也很容易可以发现,就是我们选择的提交语言

我们可以发现,之前提交的G++在language中选项是0,那么依次对应的就是
G++: 0
GCC: 1
C++: 2
C:   3
Pascal:4
Java:5
C#:  6
//check选项我不知道是干什么的。。不管提交什么代码都是0,那么就默认它为0就可以了~


def submit(self, problemID, code, language=0):
        url = 'http://acm.hdu.edu.cn/submit.php?action=submit'
        code = code.encode('utf-8').decode()             //使用python的命令转码代码
        # print(code)
        data = {
            'check': 0,
            'problemid': str(problemID),
            'language': str(language),
            'usercode': code
        }
        se = self.session
        r = se.post(url, data=data)

(6)结构体主函数
遍历所有题号,按照上面的步骤运行,这里有两点要注意:
1.前面提取代码的时候忽略了'pre'标签中的一个内容是class='cpp',因为有的博客大佬是用java写的程序...所以为了提高AC率,我们提取所有java或者c++的代码,在提交时选择一下语言即可,判断是否是java代码也非常简单...判断一下是不是存在Scanner命令就好了..
2.我们写爬虫是为了自己娱乐...或者学习新东西,但是这个的前提是不影响其他同学正常提交以及正常练习,所以我们这里在每次提交后使用time.sleep()函数间隔30秒再继续提交
def acc(self, start=1001, end=6000, timelate=30):
        language = 0
        for problemID in range(start, end):
            print("Problem",problemID,end=" ")
            if str(problemID) not in ac.getsolved(user)://判断当前题目是否被AC
                answer = ac.getcsdn(problemID)          //若没有被AC则提取百度搜索第一页中所有csdn博客中的代码
                if answer:
                    flag = 0
                    for ans in answer:
                        if ans.find('Scanner') != -1:   //若搜索到java的关键字Scanner,则选择language为5
                            language = 5
                        else:
                            language = 0
                        if str(problemID) not in ac.getsolved(user):
                            ac.submit(problemID, ans, language=language)
                            time.sleep(timelate)
                        else:
                            flag = 1                    //若已经AC,则跳出循环节省时间
                            break
                    if flag:
                        print('Accepted')
                    else:
                        print('')
            else:
                print("Accepted")

(7)至此,整个结构体操作已经写完了...也没有什么好写的了.....看到这里如果都能看懂的话,稍微理解一下,我们可以用同样的方式爬取博客园,Acmer等等题解中的代码来提高AC率,这里我就不加了...
欢迎各位fork~完整代码就不贴了,90%的代码都已经在这里了



//另外加一句~最近的个人感慨,你爱的人不一定能陪你到最后,但是爱你的人一定会!


然后我的博客听说最近不能留言了...不知道是不是真的麻烦各位大佬告诉我一下,谢谢~(*^▽^*)



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值