瘦鱼-博客

从身份证号码中获取性别、出生日期、籍贯,并更新mongodb

  有这样的需求,人员信息是存在mongodb中,需要存放人员的身份证、性别、出生日期、籍贯等信息。通过脚本导入这些信息,但是只导入了身份证号码,其他信息空缺。现在需要补全其他信息。

  其实身份证信息就包含了性别、出生日期、籍贯信息。公民身份号码是特征组合码,由前十七位数字本体码和最后一位数字校验码组成。排列顺序从左至右依次为六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码

  地址码: 表示编码对象常住户口所在县(市、旗、区)的行政区划代码。

  出生日期码:表示编码对象出生的年、月、日,年、月、日代码之间不用分隔符,格式为YYYYMMDD,如19880328。

  顺序码: 表示在同一地址码所标识的区域范围内,对同年、同月、同日出生的人编定的顺序号,顺序码的奇数分配给男性,偶数分配给女性。

  校验码: 根据本体码,通过采用ISO 7064:1983,MOD 11-2校验码系统计算出校验码。前面有提到数字校验码,我们知道校验码也有X的,实质上为罗马字符X,相当于10.

  实现思路很简单了,就是得到所有有身份证号码等纪录,解析身份证号码,获取性别、出生日期、籍贯信息,再更新mongodb。

想到了两种技术方案解决:python脚本和JavaScript。

1、python脚本

  python需要使用pymongo,用于操作mongodb,需要引入。python代码直接在终端执行就行。python test.py

  1 # encoding=utf-8
  2 
  3 '''
  4 Created on 2017年12月22日
  5 mongodb中存放人像信息,有身份证号码,无性别、籍贯、出生日期,需要根据mongodb中身份证字段,获取性别、籍贯、出生日期,更新到mongodb中
  6 
  7 @author: tim
  8 '''
  9 
 10 import re
 11 from pymongo import MongoClient  #需要引入pymongo,用于连接mongodb
 12 from datetime import datetime
 13 
 14 logPath = "/Users/tim/updatemongo/log/log.txt" #日志
 15 
 16 #身份证前两位代表的省市,作为籍贯
 17 area = {"11":"北京", "12":"天津", "13":"河北", "14":"山西", "15":"内蒙古", "21":"辽宁", "22":"吉林", "23":"黑龙江", "31":"上海", "32":"江苏", "33":"浙江", "34":"安徽", "35":"福建", "36":"江西", "37":"山东", "41":"河南", "42":"湖北", "43":"湖南", "44":"广东", "45":"广西", "46":"海南", "50":"重庆", "51":"四川", "52":"贵州", "53":"云南", "54":"西藏", "61":"陕西", "62":"甘肃", "63":"青海", "64":"宁夏", "65":"新疆", "71":"台湾", "81":"香港", "82":"澳门", "91":"国外"}
 18 
 19 
 20 # 身份证有效性校验
 21 def checkIdcard(idcard):
 22     Messages = ['验证通过!', '身份证号码位数不对!', '身份证号码出生日期超出范围或含有非法字符!', '身份证号码校验错误!', '身份证地区非法!']
 23     
 24     idcard = str(idcard) #身份证号码转成字符串
 25     idcard = idcard.strip() #移除字符串头尾指定的字符(默认为空格)
 26     idcard_list = list(idcard) #转成列表
 27     
 28     # 地区校验
 29     if(not area[(idcard)[0:2]]):
 30         return Messages[4]
 31         
 32     # 15位身份号码检测
 33     if(len(idcard) == 15):
 34         if((int(idcard[6:8]) + 1900) % 4 == 0 or((int(idcard[6:8]) + 1900) % 100 == 0 and (int(idcard[6:8]) + 1900) % 4 == 0)):
 35             ereg = re.compile('[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}$')
 36         else:
 37             ereg = re.compile('[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}$')
 38         
 39         # 测试出生日期的合法性
 40         if(re.match(ereg, idcard)):
 41             return Messages[0]
 42         else:
 43             return Messages[2]
 44             
 45     # 18位身份号码检测
 46     elif(len(idcard) == 18):
 47         # 出生日期的合法性检查
 48         # 闰年月日:((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))
 49         # 平年月日:((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))
 50         if(int(idcard[6:10]) % 4 == 0 or (int(idcard[6:10]) % 100 == 0 and int(idcard[6:10]) % 4 == 0)):
 51             ereg = re.compile('[1-9][0-9]{5}19[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}[0-9Xx]$')  # //闰年出生日期的合法性正则表达式
 52         else:
 53             ereg = re.compile('[1-9][0-9]{5}19[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}[0-9Xx]$')  # //平年出生日期的合法性正则表达式
 54     
 55         # 测试出生日期的合法性
 56         if(re.match(ereg, idcard)):
 57             # 计算校验位
 58             S = (int(idcard_list[0]) + int(idcard_list[10])) * 7 + (int(idcard_list[1]) + int(idcard_list[11])) * 9 + (int(idcard_list[2]) + int(idcard_list[12])) * 10 + (int(idcard_list[3]) + int(idcard_list[13])) * 5 + (int(idcard_list[4]) + int(idcard_list[14])) * 8 + (int(idcard_list[5]) + int(idcard_list[15])) * 4 + (int(idcard_list[6]) + int(idcard_list[16])) * 2 + int(idcard_list[7]) * 1 + int(idcard_list[8]) * 6 + int(idcard_list[9]) * 3
 59             Y = S % 11
 60             M = "F"
 61             JYM = "10X98765432"
 62             M = JYM[Y]  # 判断校验位
 63             if(M == idcard_list[17]):  # 检测ID的校验位
 64                 return Messages[0]
 65             else:
 66                 return Messages[3]
 67         else:
 68             return Messages[2]
 69     else:
 70         return Messages[1]
 71 
 72 
 73 # 获取身份证信息
 74 def getIdInfo(idcard):
 75     checkresult = checkIdcard(idcard)
 76     if checkresult == '验证通过!':    
 77         idcard = str(idcard)
 78         idcard = idcard.strip()
 79         ID_address = (idcard)[0:2]  # 前两位是籍贯
 80         ID_sex = idcard[14:17]  # 14位之后表示性别
 81         
 82         if(len(idcard) == 15):
 83             ID_birth = '19' + idcard[6:12]  # 获取15位身份证出生年月日,补全19
 84         else:    
 85             ID_birth = idcard[6:14]  # 获取18位身份证出生年月日
 86     
 87         strAddress = area[ID_address]  # 籍贯
 88         strGender = 'male'  # 性别
 89         
 90         year = ID_birth[0:4]
 91         moon = ID_birth[4:6]
 92         day = ID_birth[6:8]
 93         strBirthDate = year + '-' + moon + '-' + day  # 出生日期
 94     
 95         if int(ID_sex) % 2 == 0:
 96             strGender = 'female'
 97         else:
 98             strGender = 'male'
 99             
100         # print '籍贯', strAddress
101         # print '性别', strGender
102         # print '出生日期', strBirthDate
103         
104         idInfo = [strAddress, strGender, strBirthDate]
105         
106         return idInfo
107     else:
108         writeLog("异常:"+idcard+checkresult)
109             
110         print idcard, checkresult
111         return 0;
112 
113 
114 # 读取mongodb身份证信息,更新mongodb
115 # serverIp mongodb服务器IP
116 # port mongodb服务器端口
117 # dbName 要连接的数据库名称
118 # collectionName 数据库集合名称
119 def updateMongoInfo(serverIp, port, dbName, collectionName):
120     client = MongoClient(serverIp, port)  # 连接mongodb数据库
121     db = client[dbName]  # 指定数据库名称
122     collection = db[collectionName]  # 获取集合名
123     
124     log = open(logPath, 'a')
125     log.writelines([datetime.now().strftime('%Y-%m-%d %H:%M:%S'), ",开始更新……", "\n"])
126     print datetime.now().strftime('%Y-%m-%d %H:%M:%S'), ",开始更新……", "\n"
127 
128     # 查找身份证号码不为空的记录,才执行
129     for i in collection.find({'id_card':{"$ne":""}}):
130         result = getIdInfo(i['id_card'])
131         if(result != 0):
132             log.writelines([datetime.now().strftime('%Y-%m-%d %H:%M:%S'), ",更新,", i['idcard'], result[0], result[1], result[2], "\n"])
133             print i['id_card'], result
134             collection.update({"id_card":i['id_card']}, {"$set":{"address":result[0], "gender":result[1], "birth_date":result[2]}})
135             
136     log.writelines([datetime.now().strftime('%Y-%m-%d %H:%M:%S'), ",更新结束……", "\n"])
137     log.close()
138     print datetime.now().strftime('%Y-%m-%d %H:%M:%S'), ",更新结束……", "\n"
139  
140 
141 # 写日志
142 def writeLog(content):
143     with open(logPath, 'w+') as log:
144         log.writelines([datetime.now().strftime('%Y-%m-%d %H:%M:%S'), " ", content, "\n"])
145             
146 
147 # 入口函数
148 def start(logPath,serverIp, port, dbName, collectionName):
149     logPath=logPath
150     updateMongoInfo(serverIp, port, dbName, collectionName)
151 
152 
153 # 测试
154 start('/Users/tim/updatemongo/log/log.txt','127.0.0.1', 27017, 'tim', 'person')
155         
View Code

 

2、javascript代码

   mongodb是支持Javascript代码的,见我的另一篇博客:Mongodb常用操作

  1 //----------------------------------------------------------
  2 //    功能:检查身份证号码
  3 //    参数:idcard
  4 //    返回值:检验信息
  5 //----------------------------------------------------------
  6 function checkIdCard(idcard){ 
  7   var Errors=new Array( 
  8     "验证通过!", 
  9     "身份证号码位数不对!", 
 10     "身份证号码出生日期超出范围或含有非法字符!", 
 11     "身份证号码校验错误!", 
 12     "身份证地区非法!" 
 13   );
 14 
 15   var area={11:"北京",12:"天津",13:"河北",14:"山西",15:"内蒙古",21:"辽宁",22:"吉林",23:"黑龙江",
 16       31:"上海",32:"江苏",33:"浙江",34:"安徽",35:"福建",36:"江西",37:"山东",
 17       41:"河南",42:"湖北",43:"湖南",44:"广东",45:"广西",46:"海南",50:"重庆",51:"四川",52:"贵州",53:"云南",54:"西藏",
 18       61:"陕西",62:"甘肃",63:"青海",64:"宁夏",65:"新疆",71:"台湾",81:"香港",82:"澳门",91:"国外"};
 19 
 20   var idcard,Y,JYM; 
 21   var S,M; 
 22   var idcard_array = new Array(); 
 23   idcard_array = idcard.split(""); 
 24   //地区检验 
 25   if(area[parseInt(idcard.substr(0,2))]==null) return Errors[4]; 
 26   //身份号码位数及格式检验 
 27   switch(idcard.length){ 
 28     case 15: 
 29       if ( (parseInt(idcard.substr(6,2))+1900) % 4 == 0 || ((parseInt(idcard.substr(6,2))+1900) % 100 == 0 && 
 30           (parseInt(idcard.substr(6,2))+1900) % 4 == 0 )){ 
 31         ereg=/^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}$/;//测试出生日期的合法性 
 32       } else { 
 33         ereg=/^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}$/;//测试出生日期的合法性 
 34       } 
 35       if(ereg.test(idcard)) return Errors[0]; 
 36       else return Errors[2]; 
 37 
 38       break; 
 39     case 18: 
 40   //18位身份号码检测 
 41   //出生日期的合法性检查 
 42   //闰年月日:((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9])) 
 43   //平年月日:((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8])) 
 44       if ( parseInt(idcard.substr(6,4)) % 4 == 0 || (parseInt(idcard.substr(6,4)) % 100 == 0 && 
 45           parseInt(idcard.substr(6,4))%4 == 0 )){ 
 46         ereg=/^[1-9][0-9]{5}19[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}[0-9Xx]$/;//闰年出生日期的合法性正则表达式 
 47       } else { 
 48         ereg=/^[1-9][0-9]{5}19[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}[0-9Xx]$/;//平年出生日期的合法性正则表达式 
 49       } 
 50       if(ereg.test(idcard)){//测试出生日期的合法性 
 51       //计算校验位 
 52       S = (parseInt(idcard_array[0]) + parseInt(idcard_array[10])) * 7 
 53         + (parseInt(idcard_array[1]) + parseInt(idcard_array[11])) * 9 
 54         + (parseInt(idcard_array[2]) + parseInt(idcard_array[12])) * 10 
 55         + (parseInt(idcard_array[3]) + parseInt(idcard_array[13])) * 5 
 56         + (parseInt(idcard_array[4]) + parseInt(idcard_array[14])) * 8 
 57         + (parseInt(idcard_array[5]) + parseInt(idcard_array[15])) * 4 
 58         + (parseInt(idcard_array[6]) + parseInt(idcard_array[16])) * 2 
 59         + parseInt(idcard_array[7]) * 1 
 60         + parseInt(idcard_array[8]) * 6 
 61         + parseInt(idcard_array[9]) * 3 ; 
 62         Y = S % 11; 
 63         M = "F"; 
 64         JYM = "10X98765432"; 
 65         M = JYM.substr(Y,1);//判断校验位 
 66       if(M == idcard_array[17]) return Errors[0]; //检测ID的校验位 
 67       else return Errors[3]; 
 68     } 
 69     else return Errors[2]; 
 70     break; 
 71     default: 
 72     return Errors[1]; 
 73     break; 
 74   } 
 75 
 76 }
 77 
 78 //----------------------------------------------------------
 79 //    功能:根据身份证号获得出生日期
 80 //    参数:身份证号 psidno
 81 //    返回值:出生日期
 82 //----------------------------------------------------------
 83  function getBirthday(psidno){
 84     var birthdayno,birthdaytemp;
 85     if(psidno.length==18){
 86         birthdayno=psidno.substring(6,14);
 87     }else if(psidno.length==15){
 88         birthdaytemp=psidno.substring(6,12);
 89         birthdayno="19"+birthdaytemp;
 90     }else{
 91         print("错误的身份证号码,请核对!");
 92         return false;
 93     }
 94 
 95     var birthday=birthdayno.substring(0,4)+"-"+birthdayno.substring(4,6)+"-"+birthdayno.substring(6,8);
 96     return birthday;    
 97 }
 98 
 99 //----------------------------------------------------------
100 //    功能:根据身份证号获得性别
101 //    参数:身份证号 psidno
102 //    返回值:性别
103 //----------------------------------------------------------
104 function getGender(psidno){
105     var sexno,sex;
106     if(psidno.length==18){
107         sexno=psidno.substring(16,17);
108     }else if(psidno.length==15){
109         sexno=psidno.substring(14,15);
110     }else{
111         print(psidno+"错误的身份证号码,请核对!");
112         return false;
113     }
114     var tempid=sexno%2;
115     if(tempid==0){
116         sex='female';
117     }else{
118         sex='male';
119     }
120 
121     return sex;
122 }
123 
124 //----------------------------------------------------------
125 //     功能:获取籍贯
126 //     参数:身份证号 psidno
127 //     返回值:籍贯
128 function getProvinceNameByIdNo(idcard) {
129     var area = { 11: "北京", 12: "天津", 13: "河北", 14: "山西", 15: "内蒙古",
130         21: "辽宁", 22: "吉林", 23: "黑龙江", 31: "上海", 32: "江苏",
131         33: "浙江", 34: "安徽", 35: "福建", 36: "江西", 37: "山东", 41: "河南", 42: "湖北",
132         43: "湖南", 44: "广东", 45: "广西",
133         46: "海南", 50: "重庆", 51: "四川", 52: "贵州", 53: "云南", 54: "西藏", 61: "陕西",
134         62: "甘肃", 63: "青海", 64: "宁夏",
135         65: "新疆", 71: "台湾", 81: "香港", 82: "澳门", 91: "国外"
136     };
137 
138     var provinceName = "";
139     var provinceNo = idcard.substr(0, 2);
140     if (area[parseInt(provinceNo)] != null) {
141         provinceName = area[parseInt(provinceNo)];
142     }
143 
144     return provinceName;
145 }
146 
147 //去掉空格
148 function trim(s) { 
149     return s.replace(/^\s+|\s+$/g, ""); 
150 }
151 
152 //入口函数
153 //查询mongodb,根据身份证号码,先检验身份证,再提取性别、出生日期、籍贯,再更新mongodb
154 function start(collectionName){
155   var cursor = db.getCollection(collectionName).find({'id_card':{'$ne':''}});//查询身份证号码不为空的集合
156   while (cursor.hasNext()) {
157       var strCardId=cursor.next()["id_card"];
158       var card_id=trim(strCardId);//去掉空格后
159       
160       if (card_id.length > 0) {
161         var checkResult=checkIdCard(card_id);
162         if (checkResult!='验证通过!') {
163             print(strCardId+checkResult);
164             continue;
165          }
166          else {
167             var birthday = getBirthday(card_id);
168             var provinceName = getProvinceNameByIdNo(card_id);
169             var gender=getGender(card_id);
170             print(strCardId+":"+birthday+","+provinceName+","+gender);
171 
172             //更新mongodb
173             //这里的id_card使用原始的,避免原始的身份证号码带空格,update找不到记录
174             db.getCollection(collectionName).updateMany({"id_card":strCardId}, {"$set":{"address":provinceName, "gender":gender, "birth_date":birthday}});
175          }
176        }
177   }
178 }
179 
180 //入口,传入集合名称
181 start('person');
View Code

 

posted @ 2018-02-26 18:16  瘦鱼  阅读(1902)  评论(0编辑  收藏  举报