1. python讀取圖片exif屬性中的GPS信息
- 智能手機或平板如果在拍照時開啟定位服務(wù)铜邮,照片中就會記錄拍照位置信息和拍攝時間。如果將原始照片直接發(fā)送發(fā)布到網(wǎng)上具则,無意中就泄漏了自己的位置信息衷咽,有惡意企圖的人可能會通過照片分析出你的家庭住址和工作單位。
- python有很多工具庫可以解析圖片的exif元數(shù)據(jù)信息污呼,筆者喜歡使用exifread這個庫。
2. 完整代碼(需要使用python3)
- 圖片exif屬性中的經(jīng)緯度是“度烫扼,分曙求,秒”的形式,如:[25, 34, 5927/100],需要轉(zhuǎn)換成類似“16.439683,39.941649999”這樣的形式悟狱。
- 除經(jīng)緯度外静浴,還要讀取GPS元數(shù)據(jù)中的東西半球和南北半球標(biāo)識。
- 經(jīng)緯度轉(zhuǎn)換成地理位置需要調(diào)用地圖服務(wù)接口挤渐,本程序代碼采用百度的逆地理編碼服務(wù)API接口苹享,調(diào)用接口需要申請服務(wù)密鑰。
- 筆者自己利用手機拍照測試浴麻,程序分析后得到的位置信息基本沒有誤差得问。
#!/bin/python
#coding:utf8
import os
import exifread
import re
import sys
import requests
import json
__author__ = 'DaDaLuLa'
#************************************************************************
#代碼功能: #
# 1.讀取所有圖片文件的exif信息 #
# 2.提取圖片中的經(jīng)緯度,將度软免、分宫纬、秒轉(zhuǎn)換為小數(shù)形式 #
# 3.利用百度地圖API接口將經(jīng)緯度轉(zhuǎn)換成地址形式 #
#************************************************************************
#遍歷文件夾及子文件夾中的所有圖片,逐個文件讀取exif信息
def get_pic_GPS(pic_dir):
items = os.listdir(pic_dir)
for item in items:
path = os.path.join(pic_dir, item)
if os.path.isdir(path):
get_pic_GPS(path)
else:
imageread(path)
#將經(jīng)緯度轉(zhuǎn)換為小數(shù)形式
def convert_to_decimal(*gps):
#度
if '/' in gps[0]:
deg = gps[0].split('/')
if deg[0] == '0' or deg[1] == '0':
gps_d = 0
else:
gps_d = float(deg[0]) / float(deg[1])
else:
gps_d = float(gps[0])
#分
if '/' in gps[1]:
minu = gps[1].split('/')
if minu[0] == '0' or minu[1] == '0':
gps_m = 0
else:
gps_m = (float(minu[0]) / float(minu[1])) / 60
else:
gps_m = float(gps[1]) / 60
#秒
if '/' in gps[2]:
sec = gps[2].split('/')
if sec[0] == '0' or sec[1] == '0':
gps_s = 0
else:
gps_s = (float(sec[0]) / float(sec[1])) / 3600
else:
gps_s = float(gps[2]) / 3600
decimal_gps = gps_d + gps_m + gps_s
#如果是南半球或是西半球
if gps[3] == 'W' or gps[3] == 'S' or gps[3] == "83" or gps[3] == "87":
return str(decimal_gps * -1)
else:
return str(decimal_gps)
#讀取圖片的經(jīng)緯度和拍攝時間
def imageread(path):
f = open(path,'rb')
GPS = {}
Data = ""
try:
tags = exifread.process_file(f)
except:
return
'''
for tag in tags:
print(tag,":",tags[tag])
'''
#南北半球標(biāo)識
if 'GPS GPSLatitudeRef' in tags:
GPS['GPSLatitudeRef'] = str(tags['GPS GPSLatitudeRef'])
else:
GPS['GPSLatitudeRef'] = 'N' #缺省設(shè)置為北半球
#東西半球標(biāo)識
if 'GPS GPSLongitudeRef'in tags:
GPS['GPSLongitudeRef'] = str(tags['GPS GPSLongitudeRef'])
else:
GPS['GPSLongitudeRef'] = 'E' #缺省設(shè)置為東半球
#海拔高度標(biāo)識
if 'GPS GPSAltitudeRef' in tags:
GPS['GPSAltitudeRef'] = str(tags['GPS GPSAltitudeRef'])
#獲取緯度
if 'GPS GPSLatitude' in tags:
lat = str(tags['GPS GPSLatitude'])
#處理無效值
if lat == '[0, 0, 0]' or lat == '[0/0, 0/0, 0/0]':
return
deg, minu, sec = [x.replace(' ', '') for x in lat[1:-1].split(',')]
#將緯度轉(zhuǎn)換為小數(shù)形式
GPS['GPSLatitude'] = convert_to_decimal(deg, minu, sec,GPS['GPSLatitudeRef'])
#獲取經(jīng)度
if 'GPS GPSLongitude' in tags:
lng = str(tags['GPS GPSLongitude'])
#處理無效值
if lng == '[0, 0, 0]' or lng == '[0/0, 0/0, 0/0]':
return
deg, minu, sec = [x.replace(' ', '') for x in lng[1:-1].split(',')]
#將經(jīng)度轉(zhuǎn)換為小數(shù)形式
GPS['GPSLongitude'] = convert_to_decimal(deg, minu, sec,GPS['GPSLongitudeRef'])#對特殊的經(jīng)緯度格式進行處理
#獲取海拔高度
if 'GPS GPSAltitude' in tags:
GPS['GPSAltitude'] = str(tags["GPS GPSAltitude"])
#獲取圖片拍攝時間
if 'Image DateTime' in tags:
GPS["DateTime"] = str(tags["Image DateTime"])
elif "EXIF DateTimeOriginal" in tags:
GPS["DateTime"] = str(tags["EXIF DateTimeOriginal"])
if 'GPSLatitude' in GPS:
#將經(jīng)緯度轉(zhuǎn)換為地址
convert_gps_to_address(GPS)
#利用百度全球逆地理編碼服務(wù)(Geocoder)Web API接口服務(wù)將經(jīng)緯轉(zhuǎn)換為位置信息
def convert_gps_to_address(GPS):
secret_key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'#百度密鑰
lat, lng = GPS['GPSLatitude'], GPS['GPSLongitude']
#注意coordtype為wgs84ll(GPS經(jīng)緯度),否則定位會出現(xiàn)偏差
baidu_map_api = "http://api.map.baidu.com/geocoder/v2/?coordtype=wgs84ll&location={0},{1}&output=json&pois=0&ak={2}".format(lat,lng,secret_key)
content = requests.get(baidu_map_api).text
gps_address = json.loads(content)
#結(jié)構(gòu)化的地址
formatted_address = gps_address["result"]["formatted_address"]
#國家(若需訪問境外POI,需申請逆地理編碼境外POI服務(wù)權(quán)限)
country = gps_address["result"]["addressComponent"]["country"]
#省
province = gps_address["result"]["addressComponent"]["province"]
#城市
city = gps_address["result"]["addressComponent"]["city"]
#區(qū)
district = gps_address["result"]["addressComponent"]["district"]
#語義化地址描述
sematic_description = gps_address["result"]["sematic_description"]
#將轉(zhuǎn)換后的信息寫入文件
with open("gps_address.csv","a+") as csv:
csv.write(GPS["DateTime"] + "|" + formatted_address + "|" + country + "|" + province + "|" + city + "|" + district + "|" + sematic_description + "\n")
if __name__ == "__main__":
get_pic_GPS("./photo/")
- 從網(wǎng)站下載多張照片膏萧,測試運行結(jié)果如下:
2017:07:27 22:02:52|天津市河?xùn)|區(qū)長征路8號|中國|天津市|天津市|河?xùn)|區(qū)|水利家園東79米
2018:10:28 17:53:32|廣東省廣州市天河區(qū)員村二橫路|中國|廣東省|廣州市|天河區(qū)|程界子富新村內(nèi)
2017:08:30 05:52:54|山東省濟南市濟陽縣經(jīng)四路|中國|山東省|濟南市|濟陽縣|嘉景苑南
3. 某色情網(wǎng)站照片GPS批量提取
-
筆者無意中發(fā)現(xiàn)漓骚,互聯(lián)網(wǎng)上傳播的一些色情圖片保留了完整的GPS等元數(shù)據(jù)信息。為了分析色情圖片的拍攝位置榛泛,從某網(wǎng)站爬取了34萬張少兒不宜的圖片蝌蹂。利用上文中的程序進行分析,共獲取了3000余張圖片包含的經(jīng)緯度信息曹锨,利用百度地圖API接口轉(zhuǎn)換成對應(yīng)的精確地理位置信息孤个。
- 經(jīng)程序分析后獲取的部分?jǐn)?shù)據(jù)如下(多數(shù)位置信息能夠精確所在的小區(qū)和酒店,以下結(jié)果對具體地址加*號處理):
2017:10:16 15:13:43|四川省成都市雙流縣華陽大道4段-200|中國|四川省|成都市|雙流縣|成都栢頓*大酒店內(nèi)
2017:10:16 15:43:39|四川省成都市雙流縣華陽大道4段-200|中國|四川省|成都市|雙流縣|泊爾*酒店
2017:10:24 19:41:37|四川省成都市雙流縣華陽大道4段-200|中國|四川省|成都市|雙流縣|泊爾*酒店
2017:08:31 22:04:58|山東省濰坊市諸城市|中國|山東省|濰坊市|諸城市|萬*家園內(nèi)
2017:08:31 22:05:20|山東省濰坊市諸城市|中國|山東省|濰坊市|諸城市|萬*家園內(nèi)
2017:08:31 22:04:29|山東省濰坊市諸城市|中國|山東省|濰坊市|諸城市|萬*家園內(nèi)
2017:08:31 22:07:36|山東省濰坊市諸城市|中國|山東省|濰坊市|諸城市|萬*家園內(nèi)
2018:01:24 23:21:23|河南省許昌市長葛市鐵東路|中國|河南省|許昌市|長葛市|幸*小區(qū)
2018:01:24 23:21:20|河南省許昌市長葛市鐵東路|中國|河南省|許昌市|長葛市|幸*小區(qū)
018:08:31 22:56:52|廣東省深圳市寶安區(qū)航城大道|中國|廣東省|深圳市|寶安區(qū)|南航明*花園內(nèi)
2018:11:14 21:43:42|廣東省深圳市寶安區(qū)航城大道|中國|廣東省|深圳市|寶安區(qū)|南航明*花園內(nèi)
2018:06:21 21:43:45|遼寧省沈陽市于洪區(qū)中央大街|中國|遼寧省|沈陽市|于洪區(qū)|沈陽世紀(jì)高爾*俱樂部內(nèi)
2018:08:23 19:04:38|遼寧省沈陽市大東區(qū)滂江街|中國|遼寧省|沈陽市|大東區(qū)|龍之*暢園內(nèi)
2018:10:24 23:16:13|遼寧省沈陽市于洪區(qū)十一號街|中國|遼寧省|沈陽市|于洪區(qū)|水墨*青內(nèi)
2018:10:24 23:12:40|遼寧省沈陽市于洪區(qū)十一號街|中國|遼寧省|沈陽市|于洪區(qū)|水墨*青內(nèi)
2018:10:24 23:34:06|遼寧省沈陽市于洪區(qū)十一號街|中國|遼寧省|沈陽市|于洪區(qū)|水墨*青內(nèi)
2018:10:24 23:12:30|遼寧省沈陽市于洪區(qū)十一號街|中國|遼寧省|沈陽市|于洪區(qū)|水墨*青內(nèi)
2017:10:10 07:37:31|廣東省深圳市寶安區(qū)澳桂路|中國|廣東省|深圳市|寶安區(qū)|尚品*居內(nèi)
2017:10:10 07:37:36|廣東省深圳市寶安區(qū)澳桂路|中國|廣東省|深圳市|寶安區(qū)|尚品*居內(nèi)
2017:10:21 20:28:06|江蘇省徐州市云龍區(qū)大工巷1號樓2樓|中國|江蘇省|徐州市|云龍區(qū)|建*小區(qū)內(nèi)
2017:10:21 20:22:25|江蘇省徐州市云龍區(qū)大工巷1號樓2樓|中國|江蘇省|徐州市|云龍區(qū)|建*小區(qū)內(nèi)
2017:11:07 16:02:51|廣東省深圳市寶安區(qū)澳桂路|中國|廣東省|深圳市|寶安區(qū)|尚品*居內(nèi)
2017:11:07 16:02:50|廣東省深圳市寶安區(qū)澳桂路|中國|廣東省|深圳市|寶安區(qū)|尚品*居內(nèi)
2018:04:04 15:40:21|上海市寶山區(qū)春雷路372號|中國|上海市|上海市|寶山區(qū)|上海中*醫(yī)院內(nèi)
2018:04:04 15:40:14|上海市寶山區(qū)春雷路372號|中國|上海市|上海市|寶山區(qū)|上海中*醫(yī)院內(nèi)
2017:10:16 22:42:54|浙江省溫州市永嘉縣|中國|浙江省|溫州市|永嘉縣|西后村附近37米
2018:11:14 21:44:13|廣東省深圳市寶安區(qū)寶安大道5005-9|中國|廣東省|深圳市|寶安區(qū)|匯*居內(nèi)
2013:05:13 00:20:17|四川省成都市成華區(qū)建設(shè)北路2段-4號|中國|四川省|成都市|成華區(qū)|電子科技大學(xué)(沙河校區(qū))內(nèi)
2017:10:30 11:47:33|廣東省汕頭市龍湖區(qū)長平路東段|中國|廣東省|汕頭市|龍湖區(qū)|汕頭龍光喜來*酒店內(nèi),龍光世紀(jì)大廈南59米
2017:10:30 11:35:11|廣東省汕頭市龍湖區(qū)金環(huán)南路|中國|廣東省|汕頭市|龍湖區(qū)|汕頭龍光喜來*酒店內(nèi),龍光世紀(jì)大廈內(nèi)0米
2017:07:28 23:11:27|山東省濟南市濟陽縣緯一路|中國|山東省|濟南市|濟陽縣|雅*園-四區(qū)內(nèi)
2017:07:29 05:20:51|山東省濟南市濟陽縣緯一路|中國|山東省|濟南市|濟陽縣|雅*園-四區(qū)內(nèi)
2017:07:28 23:12:03|山東省濟南市濟陽縣緯一路|中國|山東省|濟南市|濟陽縣|雅*園-四區(qū)內(nèi)
2018:01:09 13:14:27|河北省滄州市任丘市燕山南道|中國|河北省|滄州市|任丘市|源*美璟商業(yè)廣場內(nèi),源*大酒店內(nèi)
2017:12:31 11:28:04|浙江省杭州市江干區(qū)秋濤北路38號|中國|浙江省|杭州市|江干區(qū)|浙江大學(xué)醫(yī)學(xué)院附屬邵逸夫醫(yī)院(慶春院區(qū))西南298米
2017:12:31 11:24:09|浙江省杭州市江干區(qū)秋濤北路52號3023|中國|浙江省|杭州市|江干區(qū)|杭州錢*精品酒店內(nèi)
2018:01:13 10:47:13|浙江省杭州市上城區(qū)浣紗路18號|中國|浙江省|杭州市|上城區(qū)|浙江煙草大樓東54米
2017:12:31 11:30:59|浙江省杭州市江干區(qū)秋濤北路52號3023|中國|浙江省|杭州市|江干區(qū)|杭州錢*精品酒店內(nèi)
2018:06:21 21:43:45|遼寧省沈陽市于洪區(qū)中央大街|中國|遼寧省|沈陽市|于洪區(qū)|沈陽世紀(jì)高*俱樂部內(nèi)
2018:08:23 19:04:38|遼寧省沈陽市大東區(qū)滂江街|中國|遼寧省|沈陽市|大東區(qū)|龍之*暢園內(nèi)
2018:10:24 23:16:13|遼寧省沈陽市于洪區(qū)十一號街|中國|遼寧省|沈陽市|于洪區(qū)|水*丹青內(nèi)
2018:10:24 23:12:40|遼寧省沈陽市于洪區(qū)十一號街|中國|遼寧省|沈陽市|于洪區(qū)|水*丹青內(nèi)
2018:10:24 23:34:06|遼寧省沈陽市于洪區(qū)十一號街|中國|遼寧省|沈陽市|于洪區(qū)|水*丹青內(nèi)
2018:10:24 23:12:30|遼寧省沈陽市于洪區(qū)十一號街|中國|遼寧省|沈陽市|于洪區(qū)|水*丹青內(nèi)
2017:08:07 21:47:14|江蘇省蘇州市張家港市小河壩西路|中國|江蘇省|蘇州市|張家港市|尚*國際內(nèi)
2017:05:01 23:17:23|江蘇省蘇州市張家港市小河壩西路|中國|江蘇省|蘇州市|張家港市|尚*國際內(nèi)
2017:05:01 22:56:49|江蘇省蘇州市張家港市小河壩西路|中國|江蘇省|蘇州市|張家港市|尚*國際內(nèi)
2017:05:01 23:13:07|江蘇省蘇州市張家港市小河壩西路|中國|江蘇省|蘇州市|張家港市|尚*國際內(nèi)
2017:09:15 09:29:44|陜西省西安市未央?yún)^(qū)浐灞二路|中國|陜西省|西安市|未央?yún)^(qū)|滹*小區(qū)西69米
2017:09:15 09:25:36|陜西省西安市未央?yún)^(qū)浐灞二路|中國|陜西省|西安市|未央?yún)^(qū)|泘*小學(xué)內(nèi)
2017:09:15 09:27:12|陜西省西安市未央?yún)^(qū)浐灞二路|中國|陜西省|西安市|未央?yún)^(qū)|滹*錦繡-北區(qū)內(nèi)
2017:09:15 09:25:38|陜西省西安市未央?yún)^(qū)浐灞二路|中國|陜西省|西安市|未央?yún)^(qū)|泘沱小學(xué)內(nèi)
2018:08:23 23:06:26|福建省南平市建陽市黃溪路93號|中國|福建省|南平市|建陽市|金*大酒店(上水南路店)內(nèi)
2017:09:15 21:53:39|四川省成都市成華區(qū)和錦路|中國|四川省|成都市|成華區(qū)|成都*畔生活酒店(成都火車東站魅力店)
2017:06:30 23:22:51|福建省福州市閩侯縣廣賢路|中國|福建省|福州市|閩侯縣|福建華南*職業(yè)學(xué)院(旗山校區(qū))內(nèi)
2017:12:04 00:32:06|福建省福州市倉山區(qū)永南路|中國|福建省|福州市|倉山區(qū)|領(lǐng)*新城內(nèi)
2017:08:06 10:07:41|四川省成都市新都區(qū)詹家灣路|中國|四川省|成都市|新都區(qū)|潤*花園內(nèi)
4. 拍攝位置分析
-
拍攝地分析
- 利用python的科學(xué)庫numpy、數(shù)據(jù)分析庫panda沛简、繪圖庫matplotlib和數(shù)據(jù)可視化庫pyecharts,對獲取的不良圖片拍攝位置數(shù)據(jù)進行處理齐鲤,分析不良圖片拍攝地分布情況。
- 本文進對數(shù)據(jù)進行粗略分析椒楣,展示結(jié)果僅作一般性觀察分析佳遂,不代表筆者任何觀點和傾向。
#代碼在notebook中執(zhí)行
%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif'] = ['Simhei']
df = pd.read_csv('gps_address.csv',sep='|')
fig = plt.figure(figsize=(15,20))
data = df["province"].value_counts()
num_of_province = data.values
plt.barh(range(len(num_of_province),0,-1),num_of_province,height=0.7,color='steelblue',alpha=0.8)
plt.title("各省分布情況",fontsize=20)
plt.xlabel("數(shù)量",fontsize=15)
plt.ylim(0,len(num_of_province)+1)
plt.yticks(range(len(num_of_province),0,-1),data.index,fontsize=15)
for x,y in enumerate(np.sort(num_of_province)):
plt.text(y + 0.5,x + 0.9,'%s' % y,fontsize=18 )
plt.show()
fig = plt.figure(figsize=(15,40))
data = df["city"].value_counts()
num_of_city = data.values
plt.barh(range(len(num_of_city),0,-1),num_of_city,height=0.8,color='steelblue',alpha=0.8)
plt.title("城市分布情況",fontsize=20)
plt.xlabel("數(shù)量",fontsize=15)
plt.yticks(range(len(num_of_city),0,-1),data.index,fontsize=15)
plt.ylim(0,len(num_of_city)+2)
for x,y in enumerate(np.sort(num_of_city)):
plt.text(y +0.2,x + 0.8,'%s' % y,fontsize=18 )
plt.show()
-
各省分布情況地圖展示
from pyecharts import Map, Geo
import re
provinces = list(df["province"].value_counts().index)
provinces = [re.sub("壯族自治區(qū)|自治區(qū)|省|市","",x) for x in provinces]
print(provinces)
pro_values = list(df["province"].value_counts().values)
city = list(df["province"].value_counts().index)
city_values = list(df["province"].value_counts().values)
geo = Geo("各省分布情況", "", title_color="#fff",
title_pos="center", width=1000,
height=600, background_color='#404a59')
geo.add("", provinces, pro_values, visual_range=[0, 200], maptype='china',visual_text_color="#fff",
symbol_size=10, is_visualmap=True)
geo
-
城市分布情況地圖展示
city = list(df["city"].value_counts().index)
city= [re.sub("白族自治州|市","",x) for x in city]
city_values = list(df["city"].value_counts().values)
geo = Geo("城市分布情況", "", title_color="#fff",title_pos="center", width=1000,height=600, background_color='#404a59')
geo.add("", city, city_values, visual_range=[0, 200], maptype='china',visual_text_color="#fff", symbol_size=10, is_visualmap=True)
geo
[原創(chuàng)文章撒顿,轉(zhuǎn)載文章內(nèi)容和程序代碼,請注明本文鏈接]