Skip to content

不做GPS也能同城匹配?IP定位的「附近的人」玩法

做社交、本地生活类产品,绕不开"同城"两个字。用户没开GPS的时候怎么办?总不能啥都不显示吧。其实有个成熟的办法:用IP定位兜底,做个"模糊同城"

这篇讲讲思路,以及我踩过的坑。

为什么需要IP定位兜底

做过社交App的都知道,很多用户是不愿意开定位权限的(怕被关联、怕耗电)。但"同城推荐"又确实有需求。

这时候IP归属地就派上用场了:

  • 用户开了GPS:用高精度定位;
  • 用户没开GPS:用IP归属地做个"城市级"匹配,虽然没那么准,但至少能把同城的圈子转起来。

很多平台的做法是"IP做默认,GPS做增强"。

核心实现:怎么算"同城"

思路很简单,三步:

  1. 查用户IP归属地,拿到城市;
  2. 把城市作为用户的一个标签存起来;
  3. 匹配时,相同城市的用户互相可见。
python
# 查询用户IP归属地
def get_user_city(ip):
    info = query_ip(ip)  # 查IP9
    if not info:
        return None
    # 国内用"省+市"作为同城key
    if info.get("country") == "中国" and info.get("city"):
        return f"{info['prov']}-{info['city']}"
    # 海外用国家
    return info.get("country")

存的时候,把城市ID写进用户表,检索时直接 WHERE city = ? 就能拉到同城用户。

更聪明一点:用经纬度做半径匹配

IP9 返回里有 lnglat(城市中心坐标)。可以基于这个做"半径"逻辑,比死板的"同城"更灵活:

python
import math

def distance(lat1, lng1, lat2, lng2):
    # 简化的球面距离
    R = 6371
    p1, p2 = math.radians(lat1), math.radians(lat2)
    dp = p2 - p1
    dl = math.radians(lng2 - lng1)
    a = math.sin(dp/2)**2 + math.cos(p1)*math.cos(p2)*math.sin(dl/2)**2
    return 2 * R * math.asin(math.sqrt(a))

注意:IP给的经纬度是城市中心点,用它算距离会得到"A用户的城市中心距B用户的城市中心多远"。这对同城匹配够用了,但别当成两个人的真实距离。

排序策略

匹配出来的"附近的人",排序别太死板。我建议加权:

  • 开了GPS的用户,按真实距离排;
  • 没开GPS的,用IP城市匹配,但排在后半段;
  • 别把"同城"变成唯一标准,结合活跃度、兴趣等一起排。

我踩过的坑

坑1:移动用户IP乱跳。 前面说过,手机流量IP经常飘。结果就是用户昨天还是"北京",今天就变"廊坊"。解决:城市标签不要天天更新,缓存个3~7天,稳定第一。

坑2:基站IP查不准。 蜂窝网络的IPv4出口IP集中在省会,小城市用户会被误判到省会。解决:优先查IPv6,准确性会高不少(IP9支持)。

坑3:海外用户显示"未知"。 只处理了国内城市,忘了海外。记得海外兜底用国家,至少别让人看到空白。

隐私红线

用IP做同城推荐,一定要克制:

  • 只展示到"城市级",不要展示用户精确位置;
  • IP数据别拿来"精确定位用户",用户会反感;
  • 给用户提供关闭同城/位置功能的开关。

说点实在的

IP定位的同城,体验上肯定不如GPS精确,但胜在零门槛、免授权。对很多产品来说,"先把同城跑起来"比"同城精确到百米"更重要。先用IP兜底把冷启动做了,等用户量上来,再引导他们开GPS提精度,这是很顺的路径。

免费接口:https://www.ip9.com.cn