python题库刷题训练源码_教你用python写:HDU刷题神器

声明:本文以学习为目的,请不要影响他人正常判题

HDU刷题神器,早已被前辈们做出来了,不过没有见过用python写的。大一的时候见识了学长写这个,当时还是一脸懵逼,只知道这玩意儿好屌…。时隔一年,决定自己实现这个功能。

刷到第13名,AC率不高,因为,搜索引擎搜到的结果,往后就很难找到正确的代码了

首先对辛苦刷题的acmer和hdu的管理员道歉,各位,抱歉。

介绍整体思路:

整体用多线程:线程执行从爬代码到提交的全部过程

分层次:对搜索引擎搜索的结果,进行划分,分层爬取

局部思路:

爬取搜索引擎得到的与题目相关的url,得到url_list

爬取url_list中的url,扒到代码就提交

检查提交结果,WA之后继续爬取url_list中的代码

循环,直到列表为空或者AC

相关模块:

threadpool线程池,分配线程任务,多线程并发提交代码

用requests模块发送请求

正则爬取url和代码

Sqlite存放AC代码(打表啊,再申请个账号从数据库中提交代码100%AC)

1)采用线程池实现多线程,注意控制最大并发数量

搜索引擎使用CSDN的搜索,因为我们爬取的代码全都来自CSDN的博客,可以看一下其他论坛,博客的代码:

(右键,在新标签页中打开查看高清图片)

(右键,在新标签页中打开查看高清图片)

哦,这实在太不友好了,而CSDN博客的代码就好很多了(尽管很友好了,class和name有些先后顺序不一样,也会添乱)

所以,我们决定扒CSDN博客的代码。

搜索引擎的选择,CSDN(部分搜索结果是百度提供的)

其实,第一想到的是百度的,然而。。。

加密了,增大了我们的工作量,所以,就直接用CSDN的(也有百度的结果)

在CSDN搜索结果的最下方,我们可以看到上图中有14W结果(好唬人啊),其实事情是这样的:

这是一个搜索hdu 1000的url,我们注意到用的get()方法传数据,发现只有p=?,试一下就知道,这个是页码。如果页码改为200呢?

100?

开玩笑啊,14W结果呢?最后我们得出结论:搜索结果只有76页,而且越往后,得到我们想要代码的可能性就越小,所以我只爬到20页就结束程序

关于线程池的部分,在大牛博客说的很清楚,通过threadpool模块的源码,可以理解的很清楚

注意线程池添加任务,给任务传递多参数,需要查看源码,理解参数传递的过程,

1 #coding :utf-8

2 #@Time : 2017/8/7 11:24

3 #@Author : Yong-life

4 #@File : crawling_hdu.py

5

6 importrequests7 importre8 from headers_cookies import *

9 importthreadpool10 from searching_code importsubmit_code_from_url11

12 '''

13 我要AK HDU14

15 需要安装threadpool,requests,pywin32模块16 先打开chrome浏览器登录hdu(cookies是从chrome拿的,刚登陆后可能因为cookie的问题程序抛出ValueError的异常,多启动几次就好了)17 '''

18

19

20 defsearch_pid():21 problem_list =[]22 '''共52页题目'''

23 page_number = 52 + 1

24 for i inrange(page_number):25 '''请求url'''

26 url = 'http://acm.hdu.edu.cn/listproblem.php?vol=' +str(i)27 response = requests.get(url, headers=get_headers(), cookies=get_cookie_from_chrome())28 '''抓取题目信息'''

29 patternPidList = r'>'

30 problems = re.search(patternPidList, response.text).group(1).split(';')31 for problem inproblems:32 try:33 pid = int(problem[4:8])34 status = int(problem[9])35 problem_list.append((pid, status))36 exceptValueError:37 '''ValueError'''

38 print(type(pid), pid, type(status), status)39

40 returnproblem_list41

42

43 defstart_crawling():44 pid_list =[]45 '''最大并发数量,超过10就很影响别人,相当于同时有5个人在提交代码,提交一次判断完成后才会继续提交其他代码'''

46 THREAD_NUMBER = 5

47 '''从搜索到的第crawl_level_begin页继续开始扒代码'''

48 crawl_level_begin = 1

49 '''分段式扒代码'''

50 crawl_level = 4

51 END_MARK =True52 whileEND_MARK:53 print("正在爬取题目信息……")54 for problem insearch_pid():55 pid, status =problem56 if status != 5:57 '''多参数构造'''

58 pid_list.append(([pid, crawl_level_begin, crawl_level], None)) #必须封装为元组,否则会给参数再封装一层列表,也可以改目标函数

59 if len(pid_list) ==THREAD_NUMBER:60 '''定义线程池大小'''

61 task_pool =threadpool.ThreadPool(THREAD_NUMBER)62 '''任务列表'''

63 request_task =[]64 '''构造任务列表'''

65 request_task =threadpool.makeRequests(submit_code_from_url, pid_list)66 '''将每个任务放到线程池中,等待线程池中线程各自读取任务'''

67 [task_pool.putRequest(req) for req inrequest_task]68 '''等待所有任务处理完成,则返回,如果没有处理完,则一直阻塞'''

69 task_pool.wait()70

71 pid_list =[]72 '''判断是否全对,全对结束'''

73 END_MARK =False74 print('正在搜索AC情况,,,')75 for status in search_pid()[1]:76 if status != 5:77 END_MARK =True78 print('未AK...')79 '''增加搜索范围'''

80 crawl_level_begin =crawl_level81 crawl_level += 4

82 print('增大搜索范围继续搜索...')83 print('当前搜索范围:', crawl_level_begin, crawl_level)84 break

85

86 '''CSDN搜索最搜索到30页数据,而且部分是百度提供的结果'''

87 if crawl_level > 30:88 break

89

90 print('AK!')91

92

93 if __name__ == '__main__':94 start_crawling()

2)线程开始跑了:分布式思想,分块,分层,完成AK任务

爬取crawl_level_begin-crawl_level页搜索结果的url

按照url_list爬取代码

提交代码

每轮爬完6000+题后,判断是否AK,AK则结束程序,否则增加crawl_level继续查找代码提交

经过剪枝优化,代码更快了

1 #coding :utf-8

2 #@Time : 2017/8/7 15:06

3 #@Author : Yong-life

4 #@File : searching_code.py

5

6 from urllib importrequest7 importurllib8 from headers_cookies importget_headers9 importre10 importsqlite311 from sqlite_hdu importSql12 from submit_codes import *

13 importthreading14 from submit_codes importSubmitCode15 importsys16

17

18 defsubmit_code_from_url(pid, crawl_level_begin, crawl_level):19 '''爬取url_list,提交代码'''

20 url_list =code_url_list(str(pid), crawl_level_begin, crawl_level)21 for url inurl_list:22 '''仅爬取博客链接'''

23 if url[7:11] != 'blog': #删选url

24 continue

25 code =crawling_code(pid, url)26 if code == '':27 '''未查找到代码'''

28 continue

29 submit =SubmitCode(pid, code)30 ifsubmit.submit_manager():31 '''AC,保存代码'''

32 sql_save_code =Sql()33 if sql_save_code.query_pid(pid) isNone:34 sql_save_code.insert_msg(pid, 5, code)35 else:36 sql_save_code.update_problem_code(pid, code)37 sql_save_code.sql_close()38 return

39

40 print("爬取代码完毕,任务结束:" + str(pid) + "提交尚未成功!")41 return

42

43

44 def code_url_list(problem_msg, crawl_level_begin, crawl_level): #题号和其他信息

45 '''爬取题目链接'''

46 url_list =[]47 '''页码,根据爬虫等级,扩大搜索范围'''

48 page_number =crawl_level_begin49 '''最大页码'''

50 MAX_PAGE =crawl_level51 while page_number <52>

53 url = 'http://so.csdn.net/so/search/s.do?p=' + str(page_number) + '&q=' + 'hdu' +request.quote(problem_msg)54 req = request.Request(url, headers=get_headers())55 try:56 respongse = request.urlopen(req).read().decode('utf-8')57 excepturllib.error.HTTPError:58 continue

59 '''爬取url链接'''

60 pattern_problem_url = '

[\s]*? '52>

61 '''url的title中没有发现题目信息,删去'''

62 result_list =re.findall(pattern_problem_url, respongse)63 for i inresult_list:64 if i[1].find(problem_msg) == -1:65 result_list.remove(i)66 result =result_list[:]67 result_list =[]68 result_list.extend(url[0] for url inresult)69 url_list.extend(result_list)70

71 print(problem_msg + ':' + str(page_number) + '页已搜索完毕!')72 page_number += 1

73

74 print('题目url列表爬取完毕!!!')75 returnurl_list76

77

78 defcrawling_code(pid, code_url):79 '''爬代码'''

80 req = request.Request(code_url, headers=get_headers())81 response = ''

82 try:83 response = request.urlopen(req).read().decode('utf-8')84 excepturllib.error.HTTPError as e:85 print(e)86

87 '''查找C,C++代码'''

88 pattern_code_cpp = 'class="cpp">([\s\S]*?)'

89 code =re.search(pattern_code_cpp, response)90 if code is not None and code.group(1).find('include') != -1:91 print(str(pid) + 'cpp, 已找到!')92 '''对代码中html元素进行处理'''

93 code = '0' + code.group(1)94 code =translate_code(code)95 returncode96

97 '''查找JAVA代码'''

98 pattern_code_java = 'class="java">([\s\S]*?)'

99 code =re.search(pattern_code_java, response)100 if code is not None and code.group(1).find('import') != -1:101 print(str(pid) + 'java, 已找到!')102 code = '5' + code.group(1)103 code =translate_code(code)104 returncode105 return ''

3)对代码中的html元素处理

Compilation Error次数多了就知道什么元素没处理了

1 #coding :utf-8

2 #@Time : 2017/8/7 19:08

3 #@Author : Yong-life

4 #@File : translate_code.py

5

6 deftranslate_code(code):7 '''转化代码中的html元素'''

8 code = code.replace('<', '')10 code = code.replace('"', '"')11 code = code.replace('&', '&')12 code = code.replace('+', '+')13 code = code.replace(''', '\'')14 code = code.replace(' ', ' ')15 code = code.replace(' ', ' ')16 '''替换'''

17 code = code.replace('', ' ')18 code = code.replace('

', ' ')19 code = code.replace('
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值