我正在运行 Streamlit 应用程序,尝试在 Streamlit 中检索用户的地理位置。 然而,当使用geocoder.ip("me")时,返回的坐标是45、-121,它指向美国俄勒冈州,而不是我的实际位置。
这是我使用的功能:
def get_lat_lon():
# Use geocoder to get the location based on IP
g = geocoder.ip('me')
if g.ok:
lat = g.latlng[0] # Latitude
lon = g.latlng[1] # Longitude
return lat, lon
else:
st.error("Could not retrieve location from IP address.")
return None, None
我想找到一个可以在 Streamlit 应用程序中工作的解决方案,因此通过单击
st.button
我可以调用一个函数来检索我的经纬度。
考虑以下简单的 Streamlit 应用程序:
import streamlit as st
import requests
import geocoder
from typing import Optional, Tuple
def get_location_geocoder() -> Tuple[Optional[float], Optional[float]]:
"""
Get location using geocoder library
"""
g = geocoder.ip('me')
if g.ok:
return g.latlng[0], g.latlng[1]
return None, None
def get_location_ipapi() -> Tuple[Optional[float], Optional[float]]:
"""
Fallback method using ipapi.co service
"""
try:
response = requests.get('https://ipapi.co/json/')
if response.status_code == 200:
data = response.json()
lat = data.get('latitude')
lon = data.get('longitude')
if lat is not None and lon is not None:
# Store additional location data in session state
st.session_state.location_data = {
'city': data.get('city'),
'region': data.get('region'),
'country': data.get('country_name'),
'ip': data.get('ip')
}
return lat, lon
except requests.RequestException as e:
st.error(f"Error retrieving location from ipapi.co: {str(e)}")
return None, None
def get_location() -> Tuple[Optional[float], Optional[float]]:
"""
Tries to get location first using geocoder, then falls back to ipapi.co
"""
# Try geocoder first
lat, lon = get_location_geocoder()
# If geocoder fails, try ipapi
if lat is None:
st.info("Primary geolocation method unsuccessful, trying alternative...")
lat, lon = get_location_ipapi()
return lat, lon
def show_location_details():
"""
Displays the additional location details if available
"""
if 'location_data' in st.session_state:
data = st.session_state.location_data
st.write("Location Details:")
col1, col2 = st.columns(2)
with col1:
st.write("📍 City:", data['city'])
st.write("🏘️ Region:", data['region'])
with col2:
st.write("🌍 Country:", data['country'])
st.write("🔍 IP:", data['ip'])
def main():
st.title("IP Geolocation Demo")
st.write("This app will attempt to detect your location using IP geolocation.")
if st.button("Get My Location", type="primary"):
with st.spinner("Retrieving your location..."):
lat, lon = get_location()
if lat is not None and lon is not None:
st.success("Location retrieved successfully!")
# Create two columns for coordinates
col1, col2 = st.columns(2)
with col1:
st.metric("Latitude", f"{lat:.4f}")
with col2:
st.metric("Longitude", f"{lon:.4f}")
# Show additional location details if available
show_location_details()
# Display location on a map
st.write("📍 Location on Map:")
st.map(data={'lat': [lat], 'lon': [lon]}, zoom=10)
else:
st.error("Could not determine your location. Please check your internet connection and try again.")
if __name__ == "__main__":
main()
上面的应用程序允许用户单击按钮以使用
geocoder
库生成他们的位置。我添加了一个备份,以防 geocoder
无法按预期工作,使用 ipapi.co api,它已被证明有时更准确。这种方法会有一些限制,相对于浏览器地理定位 API 替代方案来说,它的准确性会较低。尽管如此,它适用于所有设备并且不需要权限,而浏览器地理定位 api 版本则需要权限。下面是上面的应用程序的一些图片。地理定位按钮:
结果输出:
根据位置要求的精确程度,可能值得探索浏览器地理定位 API 替代方案。