人行征信第三張報告的信息提取


提取第三張報告的各種信息。使用正則和xpath方法。

 

# coding=utf8

import re,json,os
from lxml import etree
from collections import OrderedDict
from common import html,LoggerUntil,handle_parse_exception
from html_processor import  HtmlProcessor

logger = LoggerUntil(name="crcc_paser").getlog(logfilename='crcc_paser.log',loglevel=2,add_StreamHandler=1)
class HtmlFileMixin(object):
    def save_to_file(self):
        with open(self.create_file(),'wb') as f:
          f.write(self.html)

    def create_file(self):
        if not os.path.exists('htmldir'):
            os.mkdir('htmldir')
        html_file_name = 'htmldir' + '/' + self.name + '.html'
        return  html_file_name


class CrccPaser(HtmlFileMixin):
    def __init__(self,html,name):
        self.html = html
        self.name = name
        self.data = OrderedDict()
        self.data['name'] = name
        self.selector = None
        self.text =  self._get_text()
        self.get_selector()

    def _get_text(self):
        text = self.html.decode('utf8')
        return text

    def get_selector(self):
        self.selector = etree.HTML(self.text)

    def extract_user_info(self):
        self.data['report_no'] = re.search(u'報告編號:(.*?)</strong>', self.text).group(1).strip()
        self.data['query_time'] = re.search(u'查詢時間:(.*?)</strong>', self.text).group(1).strip()
        self.data['report_time'] = re.search(u'報告時間:(.*?)</strong>', self.text).group(1).strip()
        self.data['crcc_name'] = re.search(u'姓名:(.*?)</strong>', self.text).group(1).strip()
        self.data['id_type'] = re.search(u'證件類型:(.*?)</strong>', self.text).group(1).strip()
        self.data['id_no'] = re.search(u'證件號碼:(.*?)</strong>', self.text).group(1).strip()


    def extract_summary_information(self):
        account_num = re.search(
            u'<tr>\s*?<td align="left" class="p">\s*?&nbsp;賬戶數\s*?</td>\s*?<td align="center" class="p">\s*(.*?)\s*?</td>\s*?<td align="center" class="p">\s*(.*?)\s*?</td>\s*?<td align="center" class="p">\s*(.*?)\s*?</td>\s*?</tr>',
            self.text).groups()
        self.data['account_num'] = self._init_num_dict(account_num)

        uncleared_num = re.search(
                u'<tr>\s*?<td align="left" class="p">\s*?&nbsp;&nbsp;&nbsp;未結清/未銷戶賬戶數\s*?</td>\s*?<td align="center" class="p">\s*(.*?)\s*?</td>\s*?<td align="center" class="p">\s*(.*?)\s*?</td>\s*?<td align="center" class="p">\s*(.*?)\s*?</td>\s*?</tr>',
                self.text).groups()
        self.data['uncleared_num'] = self._init_num_dict(uncleared_num)

        overdue_num = re.search(
                u'<tr>\s*?<td align="left" class="p">\s*?&nbsp;發生過逾期的賬戶數\s*?</td>\s*?<td align="center" class="p">\s*(.*?)\s*?</td>\s*?<td align="center" class="p">\s*(.*?)\s*?</td>\s*?<td align="center" class="p">\s*(.*?)\s*?</td>\s*?</tr>',
                self.text).groups()
        self.data['overdue_num'] = self._init_num_dict(overdue_num)

        overdue90_num = re.search(
                u'<tr>\s*?<td align="left" class="p">\s*?&nbsp;&nbsp;&nbsp;發生過90天以上逾期的賬戶數\s*?</td>\s*?<td align="center" class="p">\s*(.*?)\s*?</td>\s*?<td align="center" class="p">\s*(.*?)\s*?</td>\s*?<td align="center" class="p">\s*(.*?)\s*?</td>\s*?</tr>',
                self.text).groups()
        self.data['overdue90_num'] = self._init_num_dict(overdue90_num)

        assure_num = re.search(
                u'<tr>\s*?<td align="left" class="p">\s*?&nbsp;為他人擔保筆數\s*?</td>\s*?<td align="center" class="p">\s*(.*?)\s*?</td>\s*?<td align="center" class="p">\s*(.*?)\s*?</td>\s*?<td align="center" class="p">\s*(.*?)\s*?</td>\s*?</tr>',
                self.text).groups()
        self.data['assure_num'] = self._init_num_dict(assure_num)

    @staticmethod
    def _init_num_dict(num_tuple):
        num_dict = {}
        num_dict['credit_card'],num_dict[' home_loans'],num_dict['other_loans'] = num_tuple
        return  num_dict

    def extract_all_loan_information(self):
        all_loan_information = re.findall(u'<li\s*?style="list-style-type: decimal; list-style-position: outside">\s*?(\S*?)\s*?</li>', self.text)
        self.data['all_loan_information'] = all_loan_information

    def extract_public_records(self):
        if not  re.search(u'系統中沒有您最近5年內的欠稅記錄、民事判決記錄、強制執行記錄、行政處罰記錄及電信欠費記錄。',self.text):
            public_records=self.selector.xpath('//table[@align="center"]//table[5]/tbody/tr[3]/td')[0].strip()   # 還不能確定具體格式,有可能造成解析中斷出錯   #TODO
        else:
            public_records=[u'系統中沒有您最近5年內的欠稅記錄、民事判決記錄、強制執行記錄、行政處罰記錄及電信欠費記錄。']
        self.data['public_records'] = public_records


    def extract_query_records(self):
        if  not  re.search(u'系統中沒有您的信用報告最近2年被查詢的記錄。',self.text):
            #query_records=selector.xpath('//table[@align="center"]//table[6]/tbody/tr[3]/td')[0].strip()
            query_records = re.findall(
                u'<tr align="center">[\s\S]*?td class="p">\s*(.*?)\s*?</td>[\s\S]*?<td class="p">\s*(.*?日)\s*?</td>[\s\S]*?<td class="p">\s*(.*?)\s*?</td>[\s\S]*?<td class="p">\s*(.*?)\s*?</td>[\s\S]*?</tr>',
                self.text)
            query_records = self._init_query_records(query_records)
        else:
            query_records =[u'系統中沒有您的信用報告最近2年被查詢的記錄。']

        self.data['query_records'] = query_records


    @staticmethod
    def _init_query_records(query_records):
        """
        :type query_records : list
        """
        query_records_list = []
        for record_tuple in query_records:
            query_record_dict = OrderedDict()
            query_record_dict['no'], query_record_dict['query_date'], query_record_dict['query_person'],query_record_dict['query_reason']  = record_tuple
            query_records_list.append(query_record_dict)
        return query_records_list

    @handle_parse_exception
    def extract_all(self):
        self.extract_user_info()
        self.extract_summary_information()
        self.extract_all_loan_information()
        self.extract_public_records()
        self.extract_query_records()



def extract_crcc(html_str,name):

    htmlProcessor = HtmlProcessor(html_str,name)
    htmlProcessor.save_to_file()   # 保存html文件


    crccPaser = CrccPaser(html_str, name)
    # crccPaser.save_to_file()
    crccPaser.extract_all()
    logger.info(json.dumps(crccPaser.data, ensure_ascii=False)) # TODO
    return json.dumps(crccPaser.data, ensure_ascii=False)

if __name__ == '__main__':
    extract_crcc(html,'小明5')

 

其中html第三張報告的頁面源碼字符串。

 

結果是

{"name": "小明5", "report_no": "2017122200004891965680", "query_time": "2017.12.22 11:12:32", "report_time": "2017.12.22 18:38:18", "crcc_name": "小明5", "id_type": "身份證", "id_no": "**************4337", "account_num": {" home_loans": "0", "other_loans": "2", "credit_card": "0"}, "uncleared_num": {" home_loans": "0", "other_loans": "0", "credit_card": "0"}, "overdue_num": {" home_loans": "0", "other_loans": "0", "credit_card": "0"}, "overdue90_num": {" home_loans": "0", "other_loans": "0", "credit_card": "0"}, "assure_num": {" home_loans": "0", "other_loans": "0", "credit_card": "0"}, "all_loan_information": ["2012年8月23日國家開發銀行湖北省分行發放的6,000元(人民幣)個人助學貸款,2014年10月已結清。", "2011年11月19日國家開發銀行湖北省分行發放的6,000元(人民幣)個人助學貸款,2014年10月已結清。"], "public_records": ["系統中沒有您最近5年內的欠稅記錄、民事判決記錄、強制執行記錄、行政處罰記錄及電信欠費記錄。"], "query_records": [{"no": "1", "query_date": "2017年12月4日", "query_person": "本人", "query_reason": "本人查詢(互聯網個人信用信息服務平台)"}, {"no": "2", "query_date": "2017年11月20日", "query_person": "本人", "query_reason": "本人查詢(互聯網個人信用信息服務平台)"}, {"no": "3", "query_date": "2017年11月6日", "query_person": "本人", "query_reason": "本人查詢(互聯網個人信用信息服務平台)"}, {"no": "4", "query_date": "2017年10月20日", "query_person": "本人", "query_reason": "本人查詢(互聯網個人信用信息服務平台)"}, {"no": "5", "query_date": "2017年10月10日", "query_person": "本人", "query_reason": "本人查詢(互聯網個人信用信息服務平台)"}, {"no": "6", "query_date": "2017年9月27日", "query_person": "本人", "query_reason": "本人查詢(互聯網個人信用信息服務平台)"}, {"no": "7", "query_date": "2017年9月18日", "query_person": "本人", "query_reason": "本人查詢(互聯網個人信用信息服務平台)"}]}

 

 

可以發送到后端py java提取,也可以在webview客戶端提取,客戶端提取js代碼如下。

/**
 * Created by wj49476 on 201/3/20.
 */

function extractReport() {

    //消除空格
    String.prototype.trim = function()
    {
    return this.replace(/(^\s*)|(\s*$)/g, "");
    };


    //正則防止出錯
    String.prototype.match2 = function(regObj) {
        var matchArray = this.match(regObj);
        if (matchArray && matchArray.length == 2){
            return matchArray[1];
        }
        else{
            return '';
        }
    };

    //數組取下標,使值不為undefined
    Array.prototype.get = function(n) {
        value = this[n];
        if (value === undefined){
            console.debug("取下標錯誤");
            value = '';
        }
        return value;
    };


    //css選擇器
    function getInnerText( cssselector){
        var element = document.querySelector(cssselector);
        if(element){
            return element.innerText;
        }
        else {
            console.warn("沒有找到 " + cssselector + " 的元素");
            return "";
        }
    }

    var data = {};
    data['SummaryInformation'] = {};
    var htmlStr = document.body.outerHTML;


    function  extractUserInfo() {
        data["reportNo"] = htmlStr.match2(/報告編號:(.*?)<\/strong>/);
        data["queryTime"] = htmlStr.match2(/查詢時間:(.*?)<\/strong>/);
        data['reportTime'] = htmlStr.match2(/報告時間:(.*?)<\/strong>/);
        data['crccName'] = htmlStr.match2(/姓名:(.*?)<\/strong>/);
        data['idType'] = htmlStr.match2(/證件類型:(.*?)<\/strong>/);
        data['idNo'] = htmlStr.match2(/證件號碼:(.*?)<\/strong>/);
    }

    function extractSummaryInformation() {
        var accountNum = htmlStr.match(/<tr>\s*?<td align="left" class="p">\s*?&nbsp;賬戶數\s*?<\/td>\s*?<td align="center" class="p">\s*(.*?)\s*?<\/td>\s*?<td align="center" class="p">\s*(.*?)\s*?<\/td>\s*?<td align="center" class="p">\s*(.*?)\s*?<\/td>\s*?<\/tr>/);
        data['SummaryInformation']['accountNum'] = _initNumDict(accountNum);

        var unclearedNum = htmlStr.match(/<tr>\s*?<td align="left" class="p">\s*?&nbsp;&nbsp;&nbsp;未結清\/未銷戶賬戶數\s*?<\/td>\s*?<td align="center" class="p">\s*(.*?)\s*?<\/td>\s*?<td align="center" class="p">\s*(.*?)\s*?<\/td>\s*?<td align="center" class="p">\s*(.*?)\s*?<\/td>\s*?<\/tr>/);
        data['SummaryInformation']['unclearedNum'] = _initNumDict(unclearedNum);

        var overdueNum = htmlStr.match(/<tr>\s*?<td align="left" class="p">\s*?&nbsp;發生過逾期的賬戶數\s*?<\/td>\s*?<td align="center" class="p">\s*(.*?)\s*?<\/td>\s*?<td align="center" class="p">\s*(.*?)\s*?<\/td>\s*?<td align="center" class="p">\s*(.*?)\s*?<\/td>\s*?<\/tr>/);
        data['SummaryInformation']['overdueNum'] = _initNumDict(overdueNum);

        var overdue90Num = htmlStr.match(/<tr>\s*?<td align="left" class="p">\s*?&nbsp;&nbsp;&nbsp;發生過90天以上逾期的賬戶數\s*?<\/td>\s*?<td align="center" class="p">\s*(.*?)\s*?<\/td>\s*?<td align="center" class="p">\s*(.*?)\s*?<\/td>\s*?<td align="center" class="p">\s*(.*?)\s*?<\/td>\s*?<\/tr>/);
        data['SummaryInformation']['overdue90Num'] = _initNumDict(overdue90Num);

        var assureNum = htmlStr.match(/<tr>\s*?<td align="left" class="p">\s*?&nbsp;為他人擔保筆數\s*?<\/td>\s*?<td align="center" class="p">\s*(.*?)\s*?<\/td>\s*?<td align="center" class="p">\s*(.*?)\s*?<\/td>\s*?<td align="center" class="p">\s*(.*?)\s*?<\/td>\s*?<\/tr>/);
        data['SummaryInformation']['assureNum'] = _initNumDict(assureNum);

    }

    function  _initNumDict(array) {
        numDict = {};
        numDict["creditCard"] = array.get(1);
        numDict["homeLoans"] = array.get(2);
        numDict["othreLoans"] = array.get(3);
        return numDict;
    }

    function extractAllLoanInformation(){
        var allLoanInformationG = htmlStr.match(/<li\s*?style="list-style-type: decimal; list-style-position: outside">\s*?(\S*?)\s*?<\/li>/g);
        var allLoanInformation = [];
        for (var i=0; i< allLoanInformationG.length; i++){
            allLoanInformation.push(allLoanInformationG[i].match(/<li\s*?style="list-style-type: decimal; list-style-position: outside">\s*?(\S*?)\s*?<\/li>/).get(1));
        }
        data['allLoanInformation'] = allLoanInformation;
    }

    function extractPublicRecords() {
        var publicRecords ;
        if (!(htmlStr.match(/系統中沒有您最近5年內的欠稅記錄、民事判決記錄、強制執行記錄、行政處罰記錄及電信欠費記錄。/))){    //沒有具體的東西,可能不確定。
            publicRecords = getInnerText('body > div > div > table > tbody > tr:nth-child(2) > td > table:nth-child(11)');

        }else{
            publicRecords='系統中沒有您最近5年內的欠稅記錄、民事判決記錄、強制執行記錄、行政處罰記錄及電信欠費記錄。';
        }
        data['publicRecords'] = publicRecords;
    }

    function extractQueryRecords() {
        if (!(htmlStr.match(/系統中沒有您的信用報告最近2年被查詢的記錄。/))){
            queryRecordsG = htmlStr.match(/<tr align="center">[\s\S]*?td class="p">\s*(.*?)\s*?<\/td>[\s\S]*?<td class="p">\s*(.*?日)\s*?<\/td>[\s\S]*?<td class="p">\s*(.*?)\s*?<\/td>[\s\S]*?<td class="p">\s*(.*?)\s*?<\/td>[\s\S]*?<\/tr>/g);
            //console.debug(queryRecordsG);
            queryRecords = [];
            for (var i=0; i<queryRecordsG.length; i++){
                queryRecords.push(queryRecordsG[i].match(/<tr align="center">[\s\S]*?td class="p">\s*(.*?)\s*?<\/td>[\s\S]*?<td class="p">\s*(.*?日)\s*?<\/td>[\s\S]*?<td class="p">\s*(.*?)\s*?<\/td>[\s\S]*?<td class="p">\s*(.*?)\s*?<\/td>[\s\S]*?<\/tr>/));
            }
            //console.debug(queryRecords);
            data['queryRecords'] = _initQueryRecords(queryRecords);
        }else{
            data['queryRecords'] = ['系統中沒有您的信用報告最近2年被查詢的記錄。'];
        }

    }

    function _initQueryRecords(queryRecords) {
        queryRecordsArray = [];
        for (var i=0; i<queryRecords.length; i++){
            queryRecordDict = {};
            queryRecordDict['no'] = queryRecords[i].get(1);
            queryRecordDict['queryDate'] = queryRecords[i].get(2);
            queryRecordDict['queryPerson'] = queryRecords[i].get(3);
            queryRecordDict['queryReason'] = queryRecords[i].get(4);
            queryRecordsArray.push(queryRecordDict);
        }
        return queryRecordsArray;
    }

    function  extractReportInner() {
        extractUserInfo();
        extractSummaryInformation();
        extractAllLoanInformation();
        extractPublicRecords();
        extractQueryRecords();
    }
    extractReportInner();
    data['htmlStr'] = Base64.encode(htmlStr);
    return JSON.stringify(data);
}


var Base64 = {

    // private property
    _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

    // public method for encoding
    encode: function(input) {
        var output = "";
        var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
        var i = 0;

        input = Base64._utf8_encode(input);

        while (i < input.length) {

            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);

            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;

            if (isNaN(chr2)) {
                enc3 = enc4 = 64;
            } else if (isNaN(chr3)) {
                enc4 = 64;
            }

            output = output + this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) + this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);

        }

        return output;
    },

    // public method for decoding
    decode: function(input) {
        var output = "";
        var chr1, chr2, chr3;
        var enc1, enc2, enc3, enc4;
        var i = 0;

        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

        while (i < input.length) {

            enc1 = this._keyStr.indexOf(input.charAt(i++));
            enc2 = this._keyStr.indexOf(input.charAt(i++));
            enc3 = this._keyStr.indexOf(input.charAt(i++));
            enc4 = this._keyStr.indexOf(input.charAt(i++));

            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;

            output = output + String.fromCharCode(chr1);

            if (enc3 != 64) {
                output = output + String.fromCharCode(chr2);
            }
            if (enc4 != 64) {
                output = output + String.fromCharCode(chr3);
            }

        }

        output = Base64._utf8_decode(output);

        return output;

    },

    // private method for UTF-8 encoding
    _utf8_encode: function(string) {
        string = string.replace(/\r\n/g, "\n");
        var utftext = "";

        for (var n = 0; n < string.length; n++) {

            var c = string.charCodeAt(n);

            if (c < 128) {
                utftext += String.fromCharCode(c);
            } else if ((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            } else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }

        }

        return utftext;
    },

    // private method for UTF-8 decoding
    _utf8_decode: function(utftext) {
        var string = "";
        var i = 0;
        var c = c1 = c2 = 0;

        while (i < utftext.length) {

            c = utftext.charCodeAt(i);

            if (c < 128) {
                string += String.fromCharCode(c);
                i++;
            } else if ((c > 191) && (c < 224)) {
                c2 = utftext.charCodeAt(i + 1);
                string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                i += 2;
            } else {
                c2 = utftext.charCodeAt(i + 1);
                c3 = utftext.charCodeAt(i + 2);
                string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                i += 3;
            }

        }

        return string;
    }

};

 

 

 

這個是js版本,由於央行征信報告頁面是拼接的,css取值不能一步到位,還必須再用正則細取,再者頁面元素沒有很好的標記,所以js版也是正則為主。js的match對應py的search,js的macth加g模式對應py的findall。js的search是返回個數字,要先弄清楚py和js的正則api的區別。

 

2、另外,使用js版本的用法是,要配合app的webview。在f12的console欄里面可以調試測試js,但那不是自動化的,尤其在多個頁面跳轉情況下,使用webview注入js非常方便。也可以直接在app端用httpclient對淘寶網發請求,但是征信類的項目,一般需要先登錄,不依賴webview直接使用httpcliet請求淘寶登錄接口的方式大批量登錄任意明文的賬號 密碼,而不是復制ua cookie什么的(復制沒什么鳥用,用戶根本不知道cookie是什么,更沒不用說ua參數是什么了),搞定它是天方夜譚,我沒見過任何人搞定過,難度指數是五顆星。有興趣的可以試試,不要只是嘴炮說抓包模擬就完了這么簡單。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM