使用php-curl模擬登錄中國田徑協會查詢本身的馬拉松成績

一、線上demo

http://demo.blueyian.top/mara...
完整的代碼包請上gayhub取用。以爲有用的能夠給個star :)
地址:https://github.com/KongYian/m...php

二、截圖

2.一、首頁

這裏寫圖片描述

2.二、查詢結果

這裏寫圖片描述

三、實現

3.一、分析目標網站

咱們的目標是http://www.runchina.org.cn/po... 所以先來分析一下此網站是如何實現成績查詢。
多嘗試輸入幾回本身的查詢信息,打開F12觀察NetWork和Application裏面的數據,咱們能夠簡單的判斷出查詢的大體流程以下圖:
這裏寫圖片描述
在反覆試驗的過程和檢查中,咱們會發現這個網站木有什麼CRSF等保護,除了一個+-*/的驗證碼,其餘就是一個赤裸裸的接口了。html

3.二、流程

在實際作的過程當中,我將第一步和第二步放在一塊兒做爲了一個接口(命名爲-- 接口1)。獲取驗證碼圖片和PHPSESSIONID,代碼以下:
其中關鍵操做在代碼註釋中--前端

<?php
$verify_code_url = "http://www.runchina.org.cn/template/default/public/js/securimage/securimage_show.php";
$query_url = "http://www.runchina.org.cn/portal.php?mod=score&ac=personal";
$cookie_file = "../tmp.cookie";
showAuthcode($verify_code_url,$cookie_file);
$handle = fopen($cookie_file,'r');
$line= '';
while (!feof($handle))
{
    $line .= fgets($handle);
}
preg_match("/PHPSESSID(?<right>.*)/",$line,$sessionArr);
fclose($handle);
$session = trimall($sessionArr['right'],' ');
$sessionString = "PHPSESSID=".$session.';';
$res = curlLogin($query_url,$cookie_file,$sessionString);

preg_match_all('/Set-Cookie:(.*);/iU',$res,$out);
$tmp = implode(';',$out[1]);

$cookieString = $sessionString.$tmp; //此變量圍第二次請求使用的cookie值
echo json_encode(['data'=>$cookieString]);
exit;

function trimall($str)//刪除空格
{
    $oldchar=array(" "," ","\t","\n","\r");
    $newchar=array("","","","","");
    return
        str_replace($oldchar,$newchar,$str);
}

function showAuthcode( $authcode_url,$cookieFile)
{
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $authcode_url);
    curl_setopt($curl, CURLOPT_COOKIEJAR, $cookieFile);
    //將獲取的cookie以文件的形式保存
    curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36');
    curl_setopt($curl, CURLOPT_HEADER, 0);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    $img = curl_exec($curl);
    curl_close($curl);
    $fp = fopen("../image/verifyCode.jpg","w");
    //獲取驗證碼的圖片
    fwrite($fp,$img);
    fclose($fp);
}

function curlLogin($url,$cookiefile,$session)
{
    $headers = [
        "Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "Accept-Encoding:gzip, deflate",
        "Accept-Language:zh-CN,zh;q=0.9",
        "Connection:keep-alive",
        "Cookie:".$session,
        "Host:www.runchina.org.cn",
        "Upgrade-Insecure-Requests:1",
        "User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36",
    ];
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_ACCEPT_ENCODING, "gzip, deflate, sdch");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0");
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
    curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiefile);
    //用請求驗證碼接口獲取的cookie做爲本次請求的set-cookie 獲取新的cookie文件,可是這裏咱們沒有以文件形式存儲而是直接輸出,這樣避免了屢次文件IO的消耗。
    curl_setopt($ch, CURLOPT_NOBODY, true);
    curl_setopt($ch, CURLOPT_HEADER, true);
    $contents = curl_exec($ch);
    curl_close($ch);
    return $contents;
}

咱們從接口一獲取到了要用的cookieString和驗證碼的圖片,下面就來模擬表單提交了,模擬提交的代碼以下:vue

$query_url = "http://www.runchina.org.cn/portal.php?mod=score&ac=personal";
$idnum = $_POST['idnum'];
$name = $_POST['name'];
$code = $_POST['code'];
$cookie = $_POST['cookie'];
$params = [
    'idnum'=>$idnum,
    'name'=>$name,
    'captcha_code'=>$code
];
$https = query($query_url,$params,$cookie);

function query($query_url,$params,$cookie){
    $headers = [
        "Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "Accept-Encoding:gzip, deflate",
        "Accept-Language:zh-CN,zh;q=0.9",
        "Connection:keep-alive",
        "Cookie:".$cookie,
        "Host:www.runchina.org.cn",
        "Upgrade-Insecure-Requests:1",
        "User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36",
    ];

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $query_url);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    $resp = curl_exec($ch);
    curl_close($ch);
    return $resp;
}

function trimall($str)//刪除空格
{
    $oldchar=array(" "," ","\t","\n","\r");
    $newchar=array("","","","","");
    return
        str_replace($oldchar,$newchar,$str);
}

變量$https即是咱們請求的結果了,若是正確的話是一個結果頁面,若是沒有數據或者出錯的話則沒有數據了。
拿到頁面以後,咱們就能夠來操做dom了,這裏我用的是‘simple_html_dom’,具體如何食用能夠google一下。如下是我操做的具體代碼:git

require_once 'simple_html_dom.php';
$htmlDom = str_get_html($https);

$out = [];
foreach($htmlDom->find('.myScore tbody tr') as $kk => $e) {
    if($kk != 0){
        foreach ($e->children as $k => $child) {
            switch ($k){
                case 0: $out[$kk]['date'] = $child->plaintext ;break;
                case 1: $out[$kk]['name'] = trimall($child->plaintext) ;break;
                case 2: $out[$kk]['type'] = trimall($child->plaintext) ;break;
                case 3:
                    $out[$kk]['raceNetTime'] = $child->plaintext ;
                    if(strpos($out[$kk]['raceNetTime'],'PB') !== false){
                        $out[$kk]['pbColor'] = 'pink';
                    }else{
                        $out[$kk]['pbColor'] = '';
                    }
                    break;
                case 4:$out[$kk]['raceTrueTime'] = $child->plaintext ;break;
//                case 5: $out[$kk]['raceDetailTime'] = trimall($child->innertext) ;break;
            }
        }
    }
}
//釋放資源對象,會很佔用內存
$htmlDom->clear();
unset($htmlDom);

最後咱們獲得的數據結構以下:
這裏寫圖片描述github

前端的話,用的很亂,vue,jq,layer,妹子UI都用了,正真的demo...
放一些JS代碼吧:web

<script>
    var vm = new Vue({
        el:'#app',
        data:{
            name:localStorage.getItem('name')=='undefined'?'':localStorage.getItem('name'),
            idnum:localStorage.getItem('idnum')=='undefined'?'':localStorage.getItem('idnum'),
            code:'',
            showSearch : 1,
            result:'',
            imageSrc : 'image/verifyCode.jpg',
            isPBColor :'pink'
        },
        beforeCreate:function(){
            cookie = init();
        },
        filters:{

        },
        methods:{
            query:function () {
                if(!(this.name && this.idnum && this.code && cookie)){
                    layer.msg('每一項都要填寫:)');
                    return false;
                }
                var load = layer.load();
                $.ajax({
                    url:'action/search.php',
                    data:{
                        name:this.name,
                        idnum:this.idnum,
                        code:this.code,
                        cookie:cookie,
                    },
                    dataType:'json',
                    type:'post',
                    success:function (response) {
                        if(response.status == 1){
                            vm.result = response.data;
                            vm.showSearch = 0;
                            localStorage.setItem('name',vm.name);
                            localStorage.setItem('idnum',vm.idnum);
                        }else{
                            layer.msg('未查詢到成績,再試試吧QAQ');
                            vm.reload();
                            return false;
                        }
                    },
                    error:function () {
                        layer.msg('服務器開小差啦,稍後再試');
                    },
                    complete:function () {
                        layer.close(load)
                    }
                })
            },
            reload:function () {
                window.location.reload();
            }
        }
    })

    function init() {
        var  cookieString;
        $.ajax({
            url:'action/init.php',
            dataType:'json',
            type:'post',
            async:false,
            success:function (response) {
                cookieString = response.data
            },
            error:function () {

            }
        })
        return cookieString;
    }
</script>
相關文章
相關標籤/搜索