去年年底,公司需要建個本地的手機號碼歸屬地庫,因為有點時間,又愛好python,就主動說來搞定這個?;罱酉聛砹?,那么怎么實施呢?分為四步:
- 所有手機號碼的獲取
- 歸屬地的查詢來源
- 請求數據的組裝,返回數據的解析
- 有用數據的落地
一:號碼的獲取
國內手機號碼十億級別的,茫茫多的號碼,一個一個獲取肯定是不現實的,想想數據表得多大?
那怎么辦呢?通過百度百科確認,要查歸屬地,只要根據前七位就ok了。那么數據只要 ‘151 5220 XXXX’這樣就可以了,這樣數據量可以壓縮一萬倍!然后搜索到目前國內三大運營商下面的手機號段分別有:
電信:
133、153、180、181、189、177、173、149
聯通:
130、131、132、155、156、145、185、186、176、175
移動:
1340-1348、135、136、137、138、139、150、151、152、157、158、159、182、183、184、187、188、147、178
共37個號碼段。所以我們只要37萬條數據就ok了,而不是37億條!
二:歸屬地的查詢來源
國內靠譜點的手機號碼歸屬地查詢網站是?
國內主要的有ip138,114百事通,手機在線等,有些是收費的,有些返回整個html,綜合下來:
適合我的是手機在線v.shouji.com,可免費且返回數據量很??!
三:請求數據的組裝,返回數據的解析
然后在該網站上輸入手機號碼查詢歸屬地,并開啟charles抓包。

手機在線查詢結果.png

Request.png

Response.png
通過抓包分析,請求為:
http://v.showji.com/Locating/showji.com2016234999234.aspx?m=13900008888&output=json&callback=querycallback×tamp=1493796438586
其中m為手機號碼,output為數據格式json,callback為返回動作,timestamp為時間戳,so只要替換其中的m,就能獲取新的手機歸屬地了!
通過抓包分析,響應為:
querycallback({
"Mobile": "13900008888",
"QueryResult": "True",
"TO": "中國移動",
"Corp": "中國移動",
"Province": "新疆",
"City": "烏魯木齊",
"AreaCode": "0991",
"PostCode": "830000",
"VNO": "",
"Card": ""
});
在querycallback()里面是一個json格式的數據包。對應有手機號、運營商、省份、城市等有用信息,Nice?。∵@就是我需要的。
四:有用數據的落地
重點是落地,落到哪里去,最好的最便捷的還是使用python直接支持的sqlite3啦,輕量快捷!
五:代碼實現
#coding:utf-8
import sys
import urllib2
import sqlite3
import json
import time
import re
class SQLITETool:
def __init__(self,databaseName):
self.databaseName = databaseName
self.create_db()
def create_db(self):
conn = sqlite3.connect(self.databaseName)
conn.close();
def execute_table(self,sql):
conn = sqlite3.connect(self.databaseName);
cursor = conn.cursor();
try:
cursor.execute(sql)
except Exception, e:
print(Exception,":",e)
finally:
cursor.close()
conn.commit()
conn.close()
class PhoneInfoSpider:
def __init__(self,databaseName,phoneSections):
self.phoneSections = phoneSections
self.sqlTool = SQLITETool(databaseName)
def phoneInfoHandler(self,jsonData):
mobile = jsonData['Mobile'];
corp = jsonData['Corp'];
province = jsonData['Province'];
city = jsonData['City'];
try:
sql = 'insert into phone_info_table (mobile, corp, province, city) values(\'{0}\',\'{1}\',\'{2}\',\'{3}\')'.format(mobile,corp,province,city);
self.sqlTool.execute_table(sql)
except Exception,e:
print(Exception,":",e)
def requestPhoneInfo(self,phoneNum):
print(phoneNum);
try:
#因為有20次/min的ip限制,所以sleep 3s
time.sleep(3);
response = urllib2.urlopen('http://v.showji.com/Locating/showji.com2016234999234.aspx?m={0}&output=json&callback=querycallback×tamp=1484546664567'.format(phoneNum))
resStr = response.read()
jsonStr = re.search(r'querycallback\((.*?)\);',resStr,re.S).group(1)
jsonData = json.loads(jsonStr)
self.phoneInfoHandler(jsonData)
except Exception,e:
print(Exception,":",e)
def requestAllSections(self):
#last用于接上次異常退出前的號碼
last = 0
#自動生成手機號碼,后四位補0
for head in self.phoneSections:
for i in range(last,10000):
middle = str(i).zfill(4)
phoneNum = head+middle+"0000"
self.requestPhoneInfo(phoneNum)
last = 0
if __name__ == '__main__':
reload(sys);
sys.setdefaultencoding('utf-8');
#134,135 '136','137','138','139','150','151','152',133','153','180','181','189','177',173','149','182','183','184','178'
#'157','158','159','187','188','147', '130','131','132','155','156','185','186','145','176'
#要爬的號碼段
yys = ['153','180','181','189','177','173','149','182','183','184','178'];
spider = PhoneInfoSpider('phoneInfo.db',yys)
sql = 'CREATE TABLE phone_info_table (mobile varchar(11) primary key,corp varchar(32),province varchar(16), city varchar(32));'
spider.sqlTool.execute_table(sql)
spider.requestAllSections()