一、照片的 EXIF信息
手机、相机拍摄的照片会自带一些诸如拍摄时间、地点、镜头型号、曝光度、图像尺寸等附加信息,在Windows上可以通过右键文件属性查看和修改相关参数。
EXIF (exchangeable image file format) 就是此类信息的简称。
Python第三方包 exifread 为读取 照片 EXIF信息提供方便。
二、 照片的 GPS信息
照片EXIF信息中记录了照片拍摄时的GPS 经纬度信息,通过高德提供的开发者工具可以进一步解析出具体的地址信息,具体方法实现如下:
# !/usr/bin/python3
# coding: utf-8
import json
import os
import traceback
import exifread
import requests
def parse_gps_express(gps_express):
'''
GPS坐标表达式转数值
:param gps_express: GPS坐标表达式 [1,2,3/4]
:return: GPS坐标数值 1.033542
'''
try:
express = str(gps_express).replace(" ", "").replace("[", "").replace("]", "")
parts = express.split(",")
subpart = parts[2].split("/")
degrees = float(parts[0])
minutes = float(parts[1])
seconds = float(subpart[0]) / float(subpart[1])
return degrees + minutes / 60 + seconds / 3600
except:
raise Exception("Error information for the picture")
def photo_gps(photo_path):
'''
照片拍摄地GPS坐标
:param photo_path: 照片的磁盘路径
:return: 照片的 (GPS经度,GPS纬度)
'''
if not os.path.isfile(photo_path):
raise Exception("File is not exist")
with open(photo_path, 'rb') as f:
exif_dict = exifread.process_file(f)
longitude_ref = str(exif_dict["GPS GPSLongitudeRef"]).strip()
longitude = parse_gps_express(str(exif_dict["GPS GPSLongitude"]))
latitude_ref = str(exif_dict["GPS GPSLatitudeRef"]).strip()
latitude = parse_gps_express(str(exif_dict["GPS GPSLatitude"]))
lng = longitude if "E" == longitude_ref else 0 - longitude
lat = latitude if "N" == latitude_ref else 0 - latitude
return lng, lat
def convert_gps(gps_coordinates):
'''
坐标转换:GPS转高德
:param gps_coordinates: 多个位置(GPS经度,GPS纬度)的集合
:return: 多个位置(高德经度,高德纬度)的集合
'''
try:
coordinates = "|".join(gps_coordinates) # 最多批量查询40个
token = "cb1c527f67df87bdc3a72f8a75987e62" # 自行申请,免费
url = "https://restapi.amap.com/v3/assistant/coordinate/convert" \
"?locations={0}&key={1}&coordsys=gps&output=json".format(coordinates, token)
response = requests.get(url) # 个人开发者访问限流:100000次/日
result = json.loads(response.text)
if "1" == result["status"]:
return result["locations"].split(";")
else:
raise Exception(result["info"])
except Exception as e:
raise e
def map_address(gd_coordinates):
'''
逆地理编码(高德坐标转地址)
:param gd_coordinates:多个位置(高德经度,高德纬度)的集合
:return:多个位置地址信息的集合
'''
try:
coordinates = "|".join(gd_coordinates) # 最多批量查询20个
token = "cb1c527f67df87bdc3a72f8a75987e62" # 自行申请,免费
batch = "true" if len(gd_coordinates) > 1 else "false"
url = "https://restapi.amap.com/v3/geocode/regeo" \
"?location={0}&key={1}&batch={2}&radius=500&extensions=base&output=json".format(coordinates, token, batch)
response = requests.get(url) # 个人开发者访问限流:6000次/日
result = json.loads(response.text)
if "1" == result["status"]:
address = []
if "true" == batch:
add_lst = list(result["regeocodes"])
for add in add_lst:
address.append(add["formatted_address"])
else:
fmt_add = result["regeocode"]["formatted_address"]
address.append(fmt_add)
return address
else:
raise Exception(result["info"])
except Exception as e:
raise e
if __name__ == '__main__':
try:
lng1, lat1 = photo_gps("d:/1.jpg")
lng2, lat2 = photo_gps("d:/2.jpg")
lng3, lat3 = photo_gps("d:/3.jpg")
gps_coordinates = list()
gps_coordinates.append("%s,%s" % (lng1, lat1))
gps_coordinates.append("%s,%s" % (lng2, lat2))
gps_coordinates.append("%s,%s" % (lng3, lat3))
gd_coordinates = convert_gps(gps_coordinates)
addresses = map_address(gd_coordinates)
for add in addresses:
print(add)
except:
traceback.print_exc()
代码中明示的token为我个人所有,仅供交流学习,不可用于任何商业活动。
实现细节的建议:高德限制用户日访问次数,为避免不必要麻烦,建议多用批量查询。
参考资料