python菜鳥開發日記-基於pyhon及django進行公司打卡系統的破解

weixin_34124651發表於2018-04-11
打卡打卡,忘記一次扣你一天工資沒商量,坑

在分公司領導及同事的強烈要求下,將公司總部的打卡系統進行破解。
破解歷程:
找出公司打卡的方式-----利用電腦每天打卡-------利用django進行手機打卡------自動打卡。

步驟1:

我公司利用移動的和我信app進行打卡,需要登入移動的和我信app,之後在裡面進行打卡。
分析如下:
1.我公司的打卡系統網頁直接和和我信的介面進行關聯,等於是登入和我信就等於登入我公司的打卡系統。
2.等於是打卡的cookie可能是固定的。


利用工具就行資料抓取,我這邊使用的是charle,軟體教程自己百度。通過電腦共享wifi,設定代理,通過手機連線該代理,連線完成,手機開啟公司軟體,進行打卡,點選開啟的時候抓取打卡地址,及post上傳的資料,及cookie。
抓取得資訊如下:

    http打卡post地址:http://******.******.com/DaKa/DaKaHome/DaKa
    data資料:
            var data = {
            time: 2018-03-08:15:23,
            address: *****,
            jingdu: "****",
            weidu: "*****"
        };
  網頁反饋的資料,通過分析js檔案得到資訊如下。
        反饋程式碼:
                ok001: 打卡成功
                ok002:打卡異常
                ok003:打卡異常
 反饋的cookie地址:
      UserloginNameCookie=18179*******

通過以上資訊得知結果如下:

  • 上傳打卡時間,地址,經度跟緯度。
  • 通過反饋的結果可以得知是否打卡成功。
  • 通過cookie得知,cookie值就是UserloginNameCookie=+手機號

資訊得到後,通過網址進行測試:
http://www.atool.org/httptest.php
輸入網址,引數,cookie,點選傳送請求,得出反饋結果為ok001。
打卡成功,執行一段時間後發現都沒有問題,

但是每次上班下班不可能開啟電腦進行打卡,特別麻煩。下面就是django打卡的開發。

首先,利用pycharm自動建立一個django框架。
建立完成後設定setting.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'dakamanager',
]
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'kamanager.urls'
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
WSGI_APPLICATION = 'kamanager.wsgi.application'
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}
LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_L10N = True

USE_TZ = True
STATIC_URL = '/static/'
# STATIC_ROOT = os.path.join(BASE_DIR, 'collectstatic')#此處必須,為新新增
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)
STATIC_ROOT = os.path.join(BASE_DIR, "static_all")

urls.py設定如下:

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r"^$", views.Index, name="index"),
    url(r"^login/",views.Login,name = "login"),
    #url(r"^ceshi/",views.ceshi,name = "ceshi"),
  #採用ajax非同步登入
    url(r"^login_daka_ajax/",views.login_daka_ajax,name = "login_daka_ajax"),
  #採用ajax非同步打卡
    #url(r"^yanzhengma_ajax/",views.yanzhengma_ajax,name = "yanzhengma_ajax"),
]

models.py檔案展示如下:

from django.db import models

# Create your models here.
class daka(models.Model):
    phone = models.CharField(max_length=12, verbose_name="手機號", blank=True)
    cookie = models.CharField(max_length=999, verbose_name="cookie", blank=True)
    name = models.CharField(max_length=999, verbose_name="姓名", blank=True)

views.py檔案如下:

from django.shortcuts import render

# Create your views here.
# -*- coding: utf-8 -*-
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
from django.template.loader import get_template
from django.shortcuts import render
from django.template import RequestContext, loader
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.db.models import Q
import json
from dakamanager import models
from dakamanager.get_jiancha import select_cookie,POST_daka
# Create your views here.
def Index(request):
    return render(request,"index.html")
def Login(request):
#查詢資料庫內是否存在手機號,不存在聯絡管理員,存在時反饋ok,跳出打卡按鈕
    ret = {"status": True, "error": None, "data": None,"cookie":True}
    if request.method == "POST":
        obj = models.daka.objects.filter(phone=request.POST.get("phone"))
        if not obj:
            ret["status"] = False
            ret["error"] = "請聯絡管理員"
        else:
            #查詢cookie是否可用,能否利用cookie登入網站。
            if select_cookie(obj[0].cookie):
                ret["cookie"] = True
            else:
                ret["cookie"] = False
    print(ret)
    return HttpResponse(json.dumps(ret))
#通過ajax非同步點選打卡,打卡反饋資料,成功或者失敗
def login_daka_ajax(request):
    ret = {"status": True, "error": None, "data": None, "cookie": True}
    if request.method == "POST":
        obj = models.daka.objects.filter(phone=request.POST.get("phone"))
        if POST_daka(obj[0].cookie):
            pass
        else:
            ret["status"] = False
    print(ret)
    return HttpResponse(json.dumps(ret))

最重要的打卡呼叫檔案get_jiancha.py

# -*- coding: UTF-8 -*-
import urllib
import http.cookiejar
import time,re,json
from pacong.zuobiao import zuobiao
def Re(res,total,id = "1"):
    if id == "1":
        data = re.findall(str(res),total)
    if id == "2":
        data = re.findall(str(res),total,re.S)
    return data
#打卡,傳入cookie
def POST_daka(cookie):
    a = zuobiao()
    URL_ROOT = 'http://******.&&&&&.com/DaKa/DaKaHome/DaKaRcsA'
    timename = time.strftime("%H:%M")
    values = {'time': str(timename), 'address': u'#########999號', "jingdu": str(a[0]), "weidu": str(a[1])}
    cookie_headers = {
        "Cookie": cookie,
    }
    URL_ROOT = 'http://******.YYYYYYY.com/DaKa/DaKaHome/DaKaRcsA'
    cookie = http.cookiejar.LWPCookieJar()
    handler = urllib.request.HTTPCookieProcessor(cookie)
    opener = urllib.request.build_opener(handler)
    postdata = urllib.parse.urlencode(values).encode()
    try:
        request = urllib.request.Request(URL_ROOT, postdata, cookie_headers)
        get_response1 = opener.open(request)
        # print(get_response1.read().decode(),type(get_response1.read().decode()))
        if Re("001",str(get_response1.read().decode())):
            ret = True
        else:
            ret = False
    except Exception as e:
        ret = False
    return ret
#檢視  cookie是否可用,可用的話 開始打卡
def select_cookie(cookie):
    ret = True
    cookie_headers = {
        "Cookie": cookie,
    }
    cookie = http.cookiejar.LWPCookieJar()
    handler = urllib.request.HTTPCookieProcessor(cookie)
    opener = urllib.request.build_opener(handler)
#利用cookie查詢網站是否能登入
    get_url = 'http://######.########.com/DaKa/DaKaHome/DaKaRCS'
    get_request = urllib.request.Request(get_url, headers=cookie_headers)
    try:
        get_response = opener.open(get_request)
        data = get_response.read().decode()
        k = Re("<p><b>請稍等...</b></p>",data)
        if k:
            ret = True
        else:
            ret = False
    except Exception as e:
        ret = False
    return ret

還有個座標隨機值zuobiao.py

#主要讓座標進行隨機生成,會在打卡位置的隨機100米範圍內,這樣每次打卡的位置都完全不一樣。
import random
def zuobiao():
    a = random.randint(11,99)
    b = random.randint(11,99)
    c =  format(str(*******) + str(a))
    d =format(str(*******) + str(b))
    return [c,d]

index.html檔案展示,裡面還設計擴充套件手機驗證碼登入,但用不上。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta content="text/html" charset="utf-8">
    <title>打卡系統</title>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    {#    <meta name="viewport" content="width=device-width, initial-scale=1">#}
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
    <link rel="stylesheet" type="text/css" href="/static/css/bootstrap.min.css">
</head>
<body>
<style>
    .hide{
        display:none;
    }


</style>

<div>
    <div class="col-md-offset-4 col-md-4 col-xs-12" style="margin-top: 10%">
        <div class="text-center">
            <h1>打卡系統</h1>
        </div>
        <div class="center-block">
            <input type="text" class="form-control" name="phone" id="phone">
        </div>
        <div>
            <h4 class="text-center bg-danger" id="error"></h4>
        </div>
        <div class="col-md-offset-5 col-md-4 col-xs-offset-4" style="margin-top: 30px">
            <button type="submit" class="btn btn-primary" id="dengru">登     入</button>
        </div>
        <div>
            <input type="text" id="yanzhengma" class="hide">
            <button type="submit" id="yzmdaoru" class="hide">獲 取 驗 證 碼</button>
            <button type="submit" id="dakadengru" class="hide">登入打卡系統</button>
        </div>
        <div class="col-md-offset-5 col-md-4 col-xs-offset-4" style="margin-top: 30px">
            <button type="submit" id="daka" class="hide btn btn-info ">打  卡</button>
        </div>
        <div id="app">
            <p>{{ message }}</p>
        </div>
    </div>
</div>

</body>
<script src="/static/js/jquery.min.js"></script>
<script>
    $("#dengru").click(function () {
        var phone = $("#phone").val()
        $.ajax({
            url: "{% url "login" %}",
            type: 'POST',
            data:{"phone":phone},
            success: function(data){
                var obj = JSON.parse(data);
                if(obj.status){
                    $("#dengru").addClass("hide")

                    if (obj.cookie){
                        $("#daka").removeClass("hide")
                        $("#error").text()
                    }else{
                        $("#yzmdaoru").removeClass("hide")
                        $("#yanzhengma").removeClass("hide")
                        $("#dakadengru").removeClass("hide")
                    }
                }else{
                    $("#error").text(obj.error)
                };
            }
        });
    });
    $("#daka").click(function () {
        var phone = $("#phone").val()
        $.ajax({
            url: "{% url "login_daka_ajax" %}",
            type: 'POST',
            data:{"phone":phone},
            success: function(data){
                var obj = JSON.parse(data);
                if(obj.status){
                    $("#error").text("打卡成功")
                }else{
                    $("#error").text("打卡失敗")
                };
            }
        });
    });
    $("#yanzhengma").click(function () {
        var phone = $("#phone").val()
        $.ajax({
            url: "{% url "yanzhengma_ajax" %}",
            type: 'POST',
            data:{"phone":phone},
            success: function(data){
                var obj = JSON.parse(data);
                if(obj.status){
                    $("#yzmdaoru").addClass("hide")
                }else{

                };
            }
        });
    });

</script>
</html>

關鍵程式碼基本已經完成,上圖。用的是bootstrap,所以會根據手機解析度進行自動響應,以後可以很happy的在家裡打卡在上班啦。


11172863-dabd4c0a2088dbc8.png
登入介面
11172863-1c900de59288413c.png
打卡介面

11172863-88ce3173a567baa1.png
打卡成功介面

後期擴充套件:
這個功能基本實現啦。但也有很多缺陷,比如忘記啦打卡。
後期有空擴充套件下:

  • 方法一:
    直接利用django celery每天定時任務打卡,這個功能很容易實現,傻瓜化,但哪天家裡的伺服器掛啦都不知道,導致沒打卡,不合適。
  • 方法二(還是利用celery,有空實現下,這個也簡單):
    每天在上班的前十分鐘對打卡記錄進行檢測,檢測沒打卡,則自動補上打卡記錄。只要每天打卡時自動生成一個時間。並且檢測的時候對時間進行比對,確認異常的進行打卡。
利用定時打卡,確實好用,又出啦一個關鍵的問題,定時打卡肯定不能在週末或者過節進行打卡啊。這個需要利用其他網站上的日曆,對每天的日曆資訊進行抓取,確認今天是否存在(休,節等等關鍵字),存在則不進行打卡檢測。

相關文章