最近今日头条上线了在创作者个人主页“更多信息”里显示创作者的地理位置。今日头条是为了加强建设健康、优质、有益、多元的网络生态。但功能上线后曝光了一些人性虚伪的层面。有些V账号的个人主页的地理位置与创作内容说的地理位置不同。让大众着实笑笑解千仇了一下。今天为大家介绍PHP/Python两种编程语言利用二分查找法获取IP地理位置。功能考虑IP段和指定IP两种情况的地理位置处理。
一、PHP二分查找法获取IP地理位置
1、PHP获取用户客户端IP地址
<?php
function getClientIp() {
$strUip = '';
if (isset($_SERVER['HTTP_X_BD_USERIP']) && $_SERVER['HTTP_X_BD_USERIP'] && strcasecmp($_SERVER['HTTP_X_BD_USERIP'], 'unknown')) {
$strUip = $_SERVER['HTTP_X_BD_USERIP'];
} else if (!empty($_SERVER['HTTP_CLIENTIP6'])) {
$strUip = $_SERVER['HTTP_CLIENTIP6'];
} else if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) && strcasecmp($_SERVER['HTTP_X_FORWARDED_FOR'], 'unknown')) {
$strUip = $_SERVER['HTTP_X_FORWARDED_FOR'];
strpos($strUip, ',') && list($strUip) = explode(',', $strUip);
} else if (!empty($_SERVER['HTTP_CLIENT_IP']) && strcasecmp($_SERVER['HTTP_CLIENT_IP'], 'unknown')) {
$strUip = $_SERVER['HTTP_CLIENT_IP'];
} else if (!empty($_SERVER['REMOTE_ADDR']) && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
$strUip = $_SERVER['REMOTE_ADDR'];
}
return $strUip;
}
$strUip = getClientIp();
var_dump($strUip);
执行结果:
string(15) "183.199.168.188"
2、PHP二分查找法获取IP地理位置
<?php
function search_ip_addr_recursion($arrIp, $intLow, $intHigh, $intIp) {
$intMiddle = intval(($intLow + $intHigh) / 2);
if ($intLow > $intHigh) {
return -1;
}
//处理指定ip逻辑
if (isset($arrIp[$intMiddle]['ip'])) {
$intMiddleIp = ip2long($arrIp[$intMiddle]['ip']);
} else {
//处理ip段逻辑
$intMiddleStartIp = ip2long($arrIp[$intMiddle]['range']['s']);
$intMiddleEndIp = ip2long($arrIp[$intMiddle]['range']['e']);
}
if (isset($intMiddleIp) && $intMiddleIp == $intIp) {
return $intMiddle;
}
if (isset($intMiddleStartIp) && $intIp >= $intMiddleStartIp && $intIp <= $intMiddleEndIp) {
return $intMiddle;
}
//处理指定ip逻辑
if (isset($intMiddleIp) && $intIp > $intMiddleIp) {
return search_ip_addr_recursion($arrIp, $intMiddle + 1, $intHigh, $intIp);
} elseif (isset($intMiddleIp) && $intIp < $intMiddleIp) {
return search_ip_addr_recursion($arrIp, $intLow, $intMiddle - 1, $intIp);
}
//处理ip段逻辑
if (isset($intMiddleEndIp) && $intIp > $intMiddleEndIp) {
return search_ip_addr_recursion($arrIp, $intMiddle + 1, $intHigh, $intIp);
} elseif (isset($intMiddleEndIp) && $intIp < $intMiddleEndIp) {
return search_ip_addr_recursion($arrIp, $intLow, $intMiddle - 1, $intIp);
}
//if代码是一条垂线下来
}
//ip测试
$arrIp = array(
array('ip' => '202.132.13.12', 'addr' => '北京'),
array('range' => array('s' => '212.12.24.12', 'e' => '212.13.25.14'), 'addr' => '山西'),
array('range' => array('s' => '212.13.25.15', 'e' => '212.15.25.14'), 'addr' => '河北'),
);
$intIp = ip2long('212.12.24.13');
//$intIp = ip2long('202.132.13.12');
$intIndex = search_ip_addr_recursion($arrIp, 0, count($arrIp), $intIp);
var_dump($intIndex);
if (-1 === $intIndex) {
var_dump('None');
} else {
var_dump($arrIp[$intIndex]);
}
执行结果:
int(1)
array(2) {
["range"]=>
array(2) {
["s"]=>
string(12) "212.12.24.12"
["e"]=>
string(12) "212.13.25.14"
}
["addr"]=>
string(6) "山西"
}
二、Python二分查找法获取IP地理位置
1、Python获取用户客户端IP地址
import requests
def getClientIp(res):
strUip = '';
if res.headers.get('HTTP_CLIENTIP6') is not None:
strUip = res.headers.get('HTTP_CLIENTIP6')
elif res.headers.get('HTTP_X_FORWARDED_FOR') is not None and res.headers.get('HTTP_X_FORWARDED_FOR') != 'unknown':
strUip = res.headers.get('HTTP_X_FORWARDED_FOR')
elif res.headers.get('HTTP_CLIENT_IP') is not None and res.headers.get('HTTP_CLIENT_IP') != 'unknown':
strUip = res.headers.get('HTTP_CLIENT_IP')
elif res.headers.get('REMOTE_ADDR') is not None and res.headers.get('REMOTE_ADDR') != 'unknown':
strUip = res.headers.get('REMOTE_ADDR')
elif res.headers.get('HTTP_X_BD_USERIP') and res.headers.get('HTTP_X_BD_USERIP') != 'unknown':
strUip = res.headers.get('HTTP_X_BD_USERIP')
return strUip;
res = requests.get('#39;)
strUip = getClientIp(res);
print(strUip);
执行结果:
183.199.168.188
2、Python二分查找法获取IP地理位置
import socket, struct
def isset(arr, key):
try:
type(arr[key])
except:
return False
return True
def ip2long(strIp):
return struct.unpack("!L", socket.inet_aton(strIp))[0]
def search_ip_addr_recursion(arrIp, intLow, intHigh, intIp):
intMiddle = int((intLow + intHigh) / 2)
if intLow > intHigh:
return -1
if isset(arrIp[intMiddle], 'ip'):
intMiddleIp = ip2long(arrIp[intMiddle]['ip'])
if intMiddleIp == intIp:
return intMiddle
if intIp > intMiddleIp:
return search_ip_addr_recursion(arrIp, intMiddle + 1, intHigh, intIp)
elif intIp < intMiddleIp:
return search_ip_addr_recursion(arrIp, intLow, intMiddle - 1, intIp)
else:
intMiddleStartIp = ip2long(arrIp[intMiddle]['range']['s'])
intMiddleEndIp = ip2long(arrIp[intMiddle]['range']['e'])
if intIp >= intMiddleStartIp and intIp <= intMiddleEndIp:
return intMiddle
if intIp > intMiddleEndIp:
return search_ip_addr_recursion(arrIp, intMiddle + 1, intHigh, intIp)
elif intIp < intMiddleEndIp:
return search_ip_addr_recursion(arrIp, intLow, intMiddle - 1, intIp)
arrIp = [
{'ip': '202.132.13.12', 'addr':'北京'},
{'range': {'s': '212.12.24.12', 'e': '212.13.25.14'}, 'addr': '山西'},
{'range': {'s': '212.13.25.15', 'e': '212.15.25.14'}, 'addr': '河北'},
]
intIp = ip2long('212.12.24.13');
#intIp = ip2long('202.132.13.12');
intIndex = search_ip_addr_recursion(arrIp, 0, len(arrIp), intIp);
print(intIndex)
if -1 == intIndex:
print('None')
else:
print(arrIp[intIndex])
执行结果:
1
{'range': {'s': '212.12.24.12', 'e': '212.13.25.14'}, 'addr': '山西'}
三、总结
- Python的代码是根据PHP代码平移过来的。PHP函数用Python函数替换或def定义。语言语法按标准替换就行。
- 查找方法需要将ip段按从小到大排好顺序可以写入内存中减少不必要的查询。
- 头条有定义“I P属地以运营商信息为准,境内显示到省(区、市),境外显示到国家(地区) ”。表示IP需要实时或定时的与运营商IP信息同步。数据上可能存在时差的情况。
- IP信息的定义可以更丰富更全个人只是测试代码用。
大家有什么更好的解决方案或算法可以发评论沟通。业务上都是调别人的接口像百度都是调用百度地图的开放API接口。
Go语言的等我把Golang学的再深入一点再介绍给大家[呲牙]。