LBS:利用IP地址,获取地理位置

工作上的任务:依据客户的IP地址,获取其IP对应的经纬度,从而得到其地理位置。最好精确到市、区、镇、街道、门牌号。代码如下。

原始的表格文件如下所示:、

logindate	      loginip	    customerid
2018-7-18 23:46	223.72.61.201	97873941
2018-7-18 23:46	222.36.47.36	97599064
2018-7-18 23:46	159.226.179.90	108089419
2018-7-18 23:47	124.126.157.119	97973378
2018-7-18 23:47	122.70.145.67	108453307
2018-7-18 23:47	39.155.214.154	105427809
2018-7-18 23:47	114.242.248.135	108861637
2018-7-18 23:47	120.221.20.195	107031927
2018-7-18 23:47	117.136.38.176	105815735
2018-7-18 23:47	223.72.89.235	107899331
2018-7-18 23:47	118.168.148.250	95506679
2018-7-18 23:47	223.72.61.201	97873941
2018-7-18 23:47	114.250.102.31	108732919
2018-7-18 23:47	111.199.221.83	98066595
2018-7-18 23:48	223.72.60.17	98440300
2018-7-18 23:48	223.72.81.86	108860194
2018-7-18 23:48	119.6.87.59	    105401342
2018-7-18 23:48	223.72.65.44	97918361
2018-7-18 23:48	223.72.47.104	108620068
2018-7-18 23:48	223.72.89.235	107899331
2018-7-18 23:48	223.72.61.201	97873941
2018-7-18 23:49	115.171.133.45	107136147
2018-7-18 23:51	114.248.187.60	105501306

代码如下:

# -*- coding: utf-8 -*-

import requests
from lxml import etree
from pandas import read_csv
import pandas as pd

# 从本地csv文件读取到python中,转换为pandas对象
df = read_csv(open('123456-copy-test.csv','r'))
data = pd.DataFrame(df)
#print(data)

# data_drop为去重之后的列表,去掉customerid中有重复数字的行,且保留重复的第一行
data_drop = data.drop_duplicates(['customerid'])
#print(data_drop)
#print(data_drop.customerid.is_unique)
#print(len(data_drop.index))

# 对上述dataframe删除原来索引,建立从0开始的新索引
data_drop_re = data_drop.reset_index(drop=True)
#print(data_drop_re)

#接下来将表格中的ip导入脚本中,查询地址

header = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64\
         AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'}

# Get_Position函数,输入IP地址,输出其对应的经度和纬度
def GetInfo_Position(ip):
    web_IP = 'http://www.882667.com/ip_' + ip + '.html' # 调用查询经纬度的网址
    response = requests.get(web_IP, headers = header)
    Position_xml = etree.HTML(response.text)
    info_Position = Position_xml.xpath('//span[@class="lansezi"]')
    info_Dimension = info_Position[1].xpath('string(.)').strip() # 获取经度
    info_Longitude = info_Position[-1].xpath('string(.)').strip() # 获取纬度
    #print(info_Dimension, info_Longitude)
    return (info_Dimension, info_Longitude) #在Console窗体输出经度、纬度
 
#Get_Geography函数,输入经纬度,输出其地理位置
def Get_Geography(ip):
    GetInfo_Position(ip)
    dimension = GetInfo_Position(ip)[0]
    longitude = GetInfo_Position(ip)[1]
    # 通过百度API得到地理位置
    items = {'location':str(dimension) + ',' + str(longitude), 'ak':'ov2Gp9rYiXpsQEl0EMYqg2HZ5MSLe3Uz', 'output':'json'} 
    res = requests.get('http://api.map.baidu.com/geocoder/v2/', params=items)
    result = res.json()
    result = result['result']['formatted_address'] + ' ' \
          + result['result']['business']+ ' ' \
          + result['result']['sematic_description']
    #print(GetInfo_Position(ip))
    print('该IP的经纬度大致为:' + GetInfo_Position(ip)[0] + ' , ' + GetInfo_Position(ip)[1])
    print(result)
    print('\t')

# 最后的地理位置,可以与http://www.gpsspg.com/maps.htm网址进行对比验证
for i in range(0,len(data_drop_re.index)):
    print('第' + i +'次测量')
    IP = str(data_drop_re.loginip[i])
#    print(data_drop_re.loginip[i])
    print('待测IP为:' + IP)
    Get_Geography(IP)
    
print('OK')

经测试,由于国内大多数使用的是动态IP,因此这种定位地理位置的方法很不准确。


更新:找到了一个国外的网站,通过IP定位到经纬度,比较准确,查询次数在1000次以上就会被封禁。另外,京东万象上也提供了Ip精准定位的API借口,但是需要付费。详细代码如下:

# -*- coding: utf-8 -*-

# 作者:yangsong
# 功能:根据IP地址,获得其地理地址
# 时间:2018-7-30 15:53:59
# 思路:	1.读取csv文件,删除重复的行数据;
# 		2.爬取https://db-ip.com/,利用此网站将Ip批量转化经纬度,并将经纬度提取出来
# 		3.利用百度地图API,通过经纬度批量得到地理位置
# 		4.将上述经纬度、地理位置导出到另外的csv文件中
# Bug:由于调用网站在域外,程序运行速度较慢,且每日爬一千次以上就会封IP


import requests
import pandas as pd
from lxml import etree
from pandas import read_csv


# 导入本地csv文件中的数据
df = read_csv(open('123456-copy.csv','r'))
data = pd.DataFrame(df)
# 数据清洗,去除重复数据
data_drop = data.drop_duplicates(['customerid'])
#print(data_drop.customerid.is_unique) # 若输出为True,表名DataFrame类中没有重复数据

# 对上述dataframe删除原来索引,建立从0开始的新索引
data_drop_re = data_drop.reset_index(drop=True)

# 添加三个新列,并重新命名
data_drop_re['Latitude'] = None # 纬度
data_drop_re['Longitude'] = None # 经度
data_drop_re['Geography'] = None # 地理位置

# 新建三个列对象,用于存储纬度、经度、地理位置数据
Latitude = []
Longitude = []
Geography = []

header = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64\
         AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.35'}

# 定义Get_Lat_Lon函数:输入IP地址,输出其对应的纬度和经度
def Get_Lat_Lon(ip):
    web_IP = 'https://db-ip.com/' + ip
    response = requests.get(web_IP, headers = header)
    Position_xml = etree.HTML(response.text)
    info_Coordinates = Position_xml.xpath('//tr/td')[-5].xpath('string(.)').strip()
    Coordinates = info_Coordinates.replace(',','').split()
    info_Latitude = Coordinates[0]  # 获得纬度
    info_Longitude = Coordinates[1]  # 获得经度
    
    Latitude.append(info_Latitude) # 将每个IP对应的纬度加到Latitude[]中
    Longitude.append(info_Longitude) # 将每个IP对应的经度加到Longitude[]中
    
    return (info_Latitude, info_Longitude)

# 定义Get_Geography函数:输入IP,调用Get_Lat_Lon(ip),输出其地理位置
def Get_Geography(ip):
    Get_Lat_Lon(ip)
    latitude = Latitude[-1]
    longitude = Longitude[-1]
    
    # 通过百度API得到地理位置
    items = {'location':str(latitude) + ',' + str(longitude), 'ak':'ov2Gp9rYiXpsQEl0EMYqg2HZ5MSLe3Uz', 'output':'json'} 
    res = requests.get('http://api.map.baidu.com/geocoder/v2/', params=items)
    result = res.json()
    # result为详细的地理位置
    result = result['result']['formatted_address'] + ' ' \
          + result['result']['business']+ ' ' \
          + result['result']['sematic_description']
    
    #Geography.append(result) # 将每个IP对应的地理位置加到Geography[]中
    return (result)

# 执行循环语句,将IP地址批量转化为地理位置
for i in range(0,len(data_drop_re.index)):
    IP = str(data_drop_re.loginip[i])
    Geography.append(Get_Geography(IP))

    # 将纬度、经度、地理位置写入dataframe对象当中
    data_drop_re.iloc[i, 3] = Latitude[i] 
    data_drop_re.iloc[i, 4] = Longitude[i]
    data_drop_re.iloc[i, 5] = Geography[i]
    
    # 写入csv,在循环体内写入。保证即使程序中断,也能有数据录入csv
    data_drop_re.to_csv('Get_Geography.csv')
    
    print('第' + str(i+1) +'次测量') 
    print('待测IP为:' + IP)
    print(Geography[i])
    print(data_drop_re)
    print('\t')
    
print('-------------------------------------OK------------------------------------')

你可能感兴趣的:(python)