码迷,mamicode.com
首页 > 其他好文 > 详细

【颓废篇】Py:从零开始的poj自动提交

时间:2018-02-24 20:49:28      阅读:180      评论:0      收藏:0      [点我收藏+]

标签:文件   状态   zoj   csdn   href   pip   偏差   请求   .post   

之前学习了一些python的爬虫技术... 已经可以通过python来水blog的阅读量了 你知道的太多了, 然而你看我这个blog惨不忍睹的访问量, 有人吗? 有人吗?

今天突然又双叒叕心血来潮想写一个poj的自动提交脚本(其实已经觊觎各大oj好久了)..
本来是想选bzoj的, 但是不知道用了什么黑科技 requests会404.. 加header好像也没用... 不知道浏览器怎么做到的..
所以还是选poj吧... 不过poj的结构做得也是很清晰(就鬼咯)

因为几乎是第一次开发这种东西, 所以不免有些不成熟的地方.. 但是管它呢, 能用就行呗
所以也想分享一下自己做这东西的全过程, 来记录自己的成长, 或许可能的话还能帮一些跟我一样的萌新解决一点问题.. 那我一定会很欣慰的... 而且自己并没有系统学过python或者前端的知识, 全靠在网上吃百家饭, 如果有什么高明的见解, 欢迎提出哟~

这里采用的是requests和BeautifulSoup4, 都是直接pip安装的, 大约都是最新版吧(萌新不懂...
这两个东西的教程网上也有不少, 官方文档(的翻译)大约也是可以搜得到的...
这里因为自己也没完全学完, 所以就不详细讲了(说了能用就行嘛)

然后我们想提交肯定要登录啊对吧, 那我们就观察一下登录要做些什么...
想要查看登录需要一些什么东西, 我们需要抓包, 而最简单的方式就是采用自己的浏览器辣~
我们可以打开自己的Chorme(Firefox什么的应该也可以, 这里用的是装虚拟机里面自带的Chormium..)

我们就利用一个新注册的测试账户"fk_poj"来进行实验.
我们先输入账号和密码, 别急着点login!!, 然后按F12, 打开开发人员工具界面. 大约像这样:
技术分享图片
然后我们看到顶上的选项卡, 选NetWork..
技术分享图片
现在这里应该就一句话, 没显示什么东西..
这样我们再点击login, 看到这里多了一堆东西, 有一个叫login的, 点它左边的小白块就可以查看详细信息了~
技术分享图片
然后我们就可以看到, 登录就是一个POST请求, 而请求的内容也在下面的Form Data中显示出来了,(好像顺便暴露了密码...), 我们只需要处理成一个字典:

logindata={
    'user_id1':'fk_poj',
    'password1':'123456',
    'B1':'login',
    'url':'/'
}

然后用requests.post往Request URL(http://poj.org/login)里把这个字典发过去就ok了..

r=requests.post('http://poj.org/login',data=logindata)

但是我们又不能同时登录和交题, 所以我们要保持登录...
这样我们就不能每次调用requests.post/get了, 但是requests替我们想了办法...
我们可以用requests.session..

session=requests.session()
r=session.post('http://poj.org/login',data=logindata)

这样很显然session这个变量还能继续使用, 然后这个连接就会保持...

好的我们已经实现了发送登录数据, 但是我们并不知道是否登录成功了啊, 我们模拟一下登录错误的情况, 输密码多输一个7:
发现并没有什么提示啊之类的, 界面也没有切换, 抓包里面的也没有特殊的返回...
这就比较难办咯.. 但是有些功能是只有登录后才能用的!
(比如我们要做的交题就是... 留个小练习:自己动手做一下如果不登录就用POST交题(方法下面会讲), 会产生什么现象?)
这里我选择了邮件... 如果登录不成功的话会是这样的:
技术分享图片

而登录成功的话是这样的:
技术分享图片

那我们就找出两个界面中html代码的不同(不同还挺大), 然后正则处理一波就行了...
(这里我用的是"Error", 判断存不存在的时候可以用开发人员工具中的Elements选项卡里Ctrl+F搜索...)

这样就登录完了, 该交题了.
由于我们只自动提交, 所以不需要读题啊获取题目信息啊之类的..
那我们就直接打开交题界面就行了...
这里选择了伟大的1000 A+B Problem
然后贴一段代码(越简单越好啊, 不要用什么"高标预流推进"之类的啦)

技术分享图片

然后点submit, 会发现代码变成了这个熊样
技术分享图片

而且看抓包信息的话, 这鬼东西作为了表单中的Source被POST了进去

技术分享图片

而由常识, 我们可以一眼看出这是base64的编码...
而非常巧的是, python支持base64的编码和解码, 所以我们只需要:

#import base64 # 只要import就好啦
submitdata={
    'problem_id':1000,
    # 语言的话当然是填列表项的索引, 注意从0开始
    'language':4,
    # base64的解码解出来是unicode, 所以再强转一步str
    'source':str(base64.b64encode(code.encode('utf-8'))),
    'submit':'Submit',
    'encoded':1
}

然后我们把表单POST给**http://poj.org/submit**就行啦~

r=session.post('http://poj.org/submit',data=submitdata)

这样就做完了, 我们来看一下是否成功地提交了呢?

技术分享图片

嗯 成功了, status中出现了我们的提交记录.

但是平时交题的时候基本都不是交上就算了的, 肯定还要知道自己的结果怎样, 而如果每次都手动查看的话, 显然还不如直接在oj上主动交呢.. 所以我们还要获取一下提交的结果.

为了防止其他人交题过多造成的干扰(比如交了好几页), 我们不妨利用搜索功能, 用对应的用户名、题目名和语言来找到最近的提交记录(就是刚刚提交的..) 我们还是来搜索然后抓一下包看看做了什么.

技术分享图片

嗯, 这次是一个GET指令, 而且其实有很显然的GET的标志——选项都写在了url里..
所以我们如果是按照题目编号 用户名和语言三个关键字来搜索的话, 就应该写

status=fxxk_poj_.mainurl+'/status?problem_id=%d&user_id=%s&result=&language=%d'\
        %(prob_id,self.user_id,lang)
r=session.get(status)

然后我们就可以获取到网页的内容了...
然后为了找到提交的结果, 我们用BeautifulSoup来分析网页的html代码

from bs4 import BeautifulSoup # 引入BeautifulSoup
soup=BeautifulSoup(r.text)

这样这碗美丽的汤就会自动帮我们做分析了...
但是我们要找到我们要的东西还是要找到这东西的特征...
那我们就找到Elements选项卡, 然后点左上角的箭头, 再单击我们要找的"Accepted"
技术分享图片

然后分析它和它父亲 祖父... 标签的关系,
我们发现这东西在一个table里面, 而这个table和其它的table不同的一点是, 这个table有一个class="a"的与众不同的属性.
我们找到了特征, 就可以从汤里把这个table捞出来~

# 自定义比较函数, 找到所有有class标签且class="a"的table
def stat_tab(tag):
    '''
    ignore tables which is no the submission table
    '''
    return tag.has_attr('class') and tag['class']==['a']
    
# 然后用find_all, 不过返回值是个列表, 我们取第0号元素即可(因为是唯一哒)
tbs=soup.find_all(stat_tab)[0]

这样我们就提取出了我们要的状态所在的table... 我们来输出一下看看是不是我们找的...

print tbs.prettify() # 这样可以以正常的缩进来输出

然后我们再在里面精确的定位即可.
我们就可以利用类似于这篇blog讲的那样处理出我们要的信息, 这里我为了防止时间太长定位出偏差选择了根据Run ID来找, 不过翻页了并没有加以处理.. 如果有这种需要(大家还是别交太快对吧), 可以去修改代码... 具体实现这里就不细讲了, 可以去看代码.
然后我们定位出状态所在的这一条之后, 什么内存 时间 代码长度 就都是小意思啦~

这样我们已经可以实现我们需求的功能了, 不过交题的话把code写在一个字符串里其实并不多么好看, 而且也不好调试对吧... 所以我们可以采用文件读写的技术来交题..
上面的实现了的话其实代码就非常的容易啦

fcode=open(filename)
code=fcode.read()
# 然后把code交上去就行啦

最后的代码我进行了一下封装, 这样以后如果还写了其它oj的可以串在一起用..
最后的实现结果:
技术分享图片

大约就是这样了. 详细的代码实现参见github..(大家要是觉得有那么一点意思, 希望大家能给个star, 大家的肯定是对一个萌新最大的鼓励^_^)

【颓废篇】Py:从零开始的poj自动提交

标签:文件   状态   zoj   csdn   href   pip   偏差   请求   .post   

原文地址:https://www.cnblogs.com/enzymii/p/8466201.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!