基于百度地图开放接口做的访客地图——点聚合

今天周日,闲下来突然想给自己的博客加个访客地图,目的是想要大概知道访客来源的地区。这里选用了百度地图开放平台的功能——点聚合。

由于之前没有做访客的ip记录,所以需要新增记录功能(这里不详细写过程),一般来说打开页面需要授权定位的都比较反感,所以我采用不太准确的方式:IP转经纬度。

步骤:

①在百度地图控制台新建应用——javascriptApi应用;

②在获取应用的ak,为了防止被恶意使用,一定要设置好白名单;

微信截图_20200816210011.png

③在自己的博客网站后台记录访客的IP地址,顺便用百度的ip转经纬度接口把经纬度转换好存储起来。

2020-08-16 14:47:07|ios|119.39.248.35
2020-08-16 14:47:33|ios|113.218.4.224
2020-08-16 14:47:45|ios|117.136.79.220
2020-08-16 14:49:00|ios|113.242.192.251
2020-08-16 14:49:35|ios|124.229.77.235


查询记录并在web端展示效果。


Screenshot_20200818_221844_w2a.W2Awxauth.alipay168.cn.jpg

php简单代码:

<?php

class Baidu_map
{
    const BAIDU_MAP_AK = 'xxxxxxx';

    public static function get_ip()
    {
        static $ip = '';
        $ip = $_SERVER['REMOTE_ADDR'];
        if (isset($_SERVER['HTTP_CDN_SRC_IP'])) {
            $ip = $_SERVER['HTTP_CDN_SRC_IP'];
        } elseif (isset($_SERVER['HTTP_CLIENT_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CLIENT_IP'])) {
            $ip = $_SERVER['HTTP_CLIENT_IP'];
        } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR']) AND preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) {
            foreach ($matches[0] AS $xip) {
                if (!preg_match('#^(10|172\.16|192\.168)\.#', $xip)) {
                    $ip = $xip;
                    break;
                }
            }
        }
        return $ip;
    }

    public static function get_latlng($ip = '')
    {
        $get_ip = $ip ? $ip : self::get_ip();
        $data = [
            'ip' => $get_ip,
            'ak' => self::BAIDU_MAP_AK,
            'coor' => 'bd09ll'
        ];
        $header = ['content-type:text/html;charset=utf-8'];
        $res = self::http_get('http://api.map.baidu.com/location/ip', $data, $header);
        if (!empty($res['status'])) {
            return ['code' => -1, 'msg' => '转换失败', 'res' => $res];
        }
        return ['code' => 0, 'msg' => 'ok', 'point' => $res['content']['point'], 'res' => $res];
    }


    public static function http_get($url, $data = [], $headers = [])
    {

        if (!empty($data)) {
            if (stripos($url, '?') === false) {
                $url = $url . '?' . http_build_query($data);
            } else {
                $url = $url . '&' . http_build_query($data);
            }
        }

        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_POST, 0);
        curl_setopt($curl, CURLOPT_HEADER, 0);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);

        if (!empty($headers)) {
            curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        }

        $response = curl_exec($curl);
        $result = json_decode($response, true);
        $error = curl_error($curl);
        return $error ? $error : $result;
    }

    public static function test()
    {
        $ips = [];
        $data = [];
        $log = file_get_contents(__DIR__ . '/log1.txt');
        $arr = explode(PHP_EOL, $log);
        foreach ($arr as $item) {
            $ips[] = explode('|', $item)[2];
        }
        $ips = array_unique($ips);
        $has = @file_get_contents(__DIR__.'/check.json');
        if (!empty($has)){
            $hasData = json_decode($has,true);
            $hasIps = array_column($hasData,'ip');
            if (!empty($hasIps)){
                $ips = array_filter(array_diff($ips,$hasIps));//找到不在已经获取过的地址
            }
            foreach ($hasData as $value){
                $data[] = [
                    $value['lng'],
                    $value['lat']
                ];
            }
        }


        $db = !empty($hasData)?$hasData: [];
        if (!empty($ips)){
            foreach ($ips as $ip) {
                $lnglat = self::get_latlng($ip);
                if ($lnglat['code']==0){
                    $data[] = [
                        $lnglat['point']['x'],
                        $lnglat['point']['y']
                    ];
                    $db[] = ['ip'=>$ip,'lat'=>$lnglat['point']['y'],'lng'=>$lnglat['point']['x']];
                }
            }
            file_put_contents(__DIR__.'/check.json',json_encode($db,JSON_UNESCAPED_UNICODE));
        }

        return $data;
    }
}


html :

<?php
require __DIR__.'/map.php';
$data = Baidu_map::test();

?>


<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
    <style type="text/css">
        body, html {width: 100%;height: 100%;margin:0;font-family:"微软雅黑";}
        #allmap{width:100%;height:100%;}
        p{margin-left:5px; font-size:14px;}
    </style>
    <script type="text/javascript" src="http://api.map.baidu.com/getscript?v=2.0&ak=自己的ak&services=&t=20200327103013"></script>
    
    <script type="text/javascript" src="http://api.map.baidu.com/library/TextIconOverlay/1.2/src/TextIconOverlay_min.js"></script>
    <script type="text/javascript" src="http://api.map.baidu.com/library/MarkerClusterer/1.2/src/MarkerClusterer_min.js"></script>
    <title>点聚合</title>
</head>
<body>
<div id="allmap"></div>
<p>缩放地图,查看点聚合效果</p>
</body>
</html>
<script type="text/javascript">
    // 百度地图API功能
    var map = new BMap.Map("allmap");
    map.centerAndZoom(new BMap.Point(112.0,29.0), 5);
    map.enableScrollWheelZoom();


    var MAX = '<?php echo count($data)?>';
    var data = <?php echo json_encode($data)?>;
    var markers = [];
    var pt = null;

    console.log(data)
    var len = data.length
    for(var i = 0; i < len; i++) {
        pt = new BMap.Point(data[i][0],data[i][1]);
        markers.push(new BMap.Marker(pt));
    }

    /*var i = 0;
    for (; i < MAX; i++) {

        pt = new BMap.Point(112,34);
        // pt = new BMap.Point(Math.random() * 40 + 85, Math.random() * 30 + 21);

        markers.push(new BMap.Marker(pt));
    }*/

    //最简单的用法,生成一个marker数组,然后调用markerClusterer类即可。
    var markerClusterer = new BMapLib.MarkerClusterer(map, {markers:markers});
</script>


用到的文件在附件中:

demo_2020.08.16.7z


根据自己的需要调整逻辑即可。我在tp里面放了一个,感觉效果不错。

评论/留言