去年年底岸啡,公司需要建個(gè)本地的手機(jī)號(hào)碼歸屬地庫(kù)原叮,因?yàn)橛悬c(diǎn)時(shí)間,又愛(ài)好python巡蘸,就主動(dòng)說(shuō)來(lái)搞定這個(gè)奋隶。活接下來(lái)了悦荒,那么怎么實(shí)施呢唯欣?分為四步:
- 所有手機(jī)號(hào)碼的獲取
- 歸屬地的查詢來(lái)源
- 請(qǐng)求數(shù)據(jù)的組裝,返回?cái)?shù)據(jù)的解析
- 有用數(shù)據(jù)的落地
一:號(hào)碼的獲取
國(guó)內(nèi)手機(jī)號(hào)碼十億級(jí)別的搬味,茫茫多的號(hào)碼境氢,一個(gè)一個(gè)獲取肯定是不現(xiàn)實(shí)的蟀拷,想想數(shù)據(jù)表得多大?
那怎么辦呢萍聊?通過(guò)百度百科確認(rèn)问芬,要查歸屬地,只要根據(jù)前七位就ok了寿桨。那么數(shù)據(jù)只要 ‘151 5220 XXXX’這樣就可以了此衅,這樣數(shù)據(jù)量可以壓縮一萬(wàn)倍!然后搜索到目前國(guó)內(nèi)三大運(yùn)營(yíng)商下面的手機(jī)號(hào)段分別有:
電信:
133亭螟、153挡鞍、180、181预烙、189墨微、177、173默伍、149
聯(lián)通:
130欢嘿、131、132也糊、155炼蹦、156、145狸剃、185掐隐、186、176钞馁、175
移動(dòng):
1340-1348虑省、135、136僧凰、137探颈、138、139训措、150伪节、151、152绩鸣、157怀大、158、159呀闻、182化借、183、184捡多、187蓖康、188铐炫、147、178
共37個(gè)號(hào)碼段钓瞭。所以我們只要37萬(wàn)條數(shù)據(jù)就ok了驳遵,而不是37億條!
二:歸屬地的查詢來(lái)源
國(guó)內(nèi)靠譜點(diǎn)的手機(jī)號(hào)碼歸屬地查詢網(wǎng)站是山涡?
國(guó)內(nèi)主要的有ip138堤结,114百事通,手機(jī)在線等鸭丛,有些是收費(fèi)的竞穷,有些返回整個(gè)html,綜合下來(lái):
適合我的是手機(jī)在線v.shouji.com鳞溉,可免費(fèi)且返回?cái)?shù)據(jù)量很旭!
三:請(qǐng)求數(shù)據(jù)的組裝熟菲,返回?cái)?shù)據(jù)的解析
然后在該網(wǎng)站上輸入手機(jī)號(hào)碼查詢歸屬地看政,并開(kāi)啟charles抓包。
通過(guò)抓包分析抄罕,請(qǐng)求為:
http://v.showji.com/Locating/showji.com2016234999234.aspx?m=13900008888&output=json&callback=querycallback×tamp=1493796438586
其中m為手機(jī)號(hào)碼允蚣,output為數(shù)據(jù)格式j(luò)son,callback為返回動(dòng)作呆贿,timestamp為時(shí)間戳嚷兔,so只要替換其中的m,就能獲取新的手機(jī)歸屬地了做入!
通過(guò)抓包分析冒晰,響應(yīng)為:
querycallback({
"Mobile": "13900008888",
"QueryResult": "True",
"TO": "中國(guó)移動(dòng)",
"Corp": "中國(guó)移動(dòng)",
"Province": "新疆",
"City": "烏魯木齊",
"AreaCode": "0991",
"PostCode": "830000",
"VNO": "",
"Card": ""
});
在querycallback()里面是一個(gè)json格式的數(shù)據(jù)包。對(duì)應(yīng)有手機(jī)號(hào)竟块、運(yùn)營(yíng)商壶运、省份、城市等有用信息浪秘,Nice扒巴洹!這就是我需要的秫逝。
四:有用數(shù)據(jù)的落地
重點(diǎn)是落地,落到哪里去询枚,最好的最便捷的還是使用python直接支持的sqlite3啦违帆,輕量快捷!
五:代碼實(shí)現(xiàn)
#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:
#因?yàn)橛?0次/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用于接上次異常退出前的號(hào)碼
last = 0
#自動(dòng)生成手機(jī)號(hào)碼刷后,后四位補(bǔ)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'
#要爬的號(hào)碼段
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()