一、背景:
最近工作中做了一个小功能,目的是为了分析注册用户区域分布和订单的区域分布情况。所以需要将其对应的IP信息解析为归属地,并同步每天同步更新。
线上跑起来效率还是有优化的空间,优化的方向:在调用IP查询API过程可以调整为多线程并行解析IP。后续会更新这方便的调整。
技术: Pyhton3
postgreSQL
env配置文件 附加信息:iP地址查询(iP138官方企业版):https://market.aliyun.com/products/56928004/cmapi015606.html#sku=yuncode960600002
.可提供免费的IP查询API. 二、实现思路: 1、 读取数据库IP信息
2、 调用第三方IP解析API进行解析
3、 将解析归属地信息存入数据库
三、几点说明: 1、环境信息等参数配置
2、日志输出
3、异常处理: 数据库连接异常
请求连接查询IP的URL异常:HTTP ERROR 503
4、json,字典,数组等类型数据输入输出
5、分页查询并批量解析
5.功能实现很简单,所以就没有做详细的介绍了。详情可直接看完整代码,有详细的备注。 四、步骤简单介绍:
针对实现思路的3个步骤写了3个函数,彼此调用执行。
函数:
def get_ip_info(table_name):
def get_ip_area(table_name):
def ip_write_db(table_name):
调用:
ip_write_db("h_user_stat") 五、关键代码说明:
语法:urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
 # 对从数据库表中出查询的IP进行解析
querys = 'callback&datatype=jsonp&ip=' + get_ip
bodys = {}
url = host + path + '?' + querys
request = urllib.request.Request(url)
request.add_header('Authorization', 'APPCODE ' + appcode) # 连接url时可能会出现 ERROR: HTTP Error 503: Service Unavailable
try:
response = urllib.request.urlopen(request)
except Exception as e:
logging.error(e) # 输出异常日志信息
time.sleep(5)
response = urllib.request.urlopen(request)
finally:
content = response.read()
ip_area = content.decode('utf8')
ip_area = json.loads(ip_area)['data'] # json类型转字典类型并取'data'健值
arr.append([get_ip, ip_area]) # 将结果集存于二元数组
说明:从数据库分页查询固定数量的IP存入数组,并遍历该数组并将解析后的地区信息data健值存于二元数组中。

 
六、Python代码实现如下:
 # 导入psycopg2包
import psycopg2, time,datetime,sys
import json
import urllib, urllib.request
import os
import configparser
import logging
# purpose: 连接数据库读取表IP信息
def get_ip_info(table_name):
# 全局变量作用局部作用域
global pagesize # 每页查询数据条数
global rows_count # 测试1
starttime_1 = time.time()
# 建立游标,用来执行数据库操作
cur = conn.cursor()
# 执行SQL命令
cur.execute("SELECT remote_ip FROM (select remote_ip,min(created_at) from " + table_name + " group by remote_ip) h1 where remote_ip is not null and remote_ip <> '' and not exists (select 1 from d_ip_area_mapping h2 where h1.remote_ip = h2.remote_ip) limit " + str(pagesize) + ";") # 获取结果集条数
rows_count = cur.rowcount # print('解析用户IP的总数:' + str(rows_count)) # 当有未解析的用户的IP,返回元组,否则退出程序
if rows_count > 0:
# 获取SELECT返回的元组
rows = cur.fetchall() # all rows in table for row in rows:
tuple = rows conn.commit()
# 关闭游标
cur.close() else:
tuple = []
logging.info('每页查询秒数:' + str(time.time() - starttime_1))
return tuple
# 调用解析函数 def get_ip_area(table_name):
# 内包含用户ID和IP的数组的元组
tuple = get_ip_info(table_name) # 测试2
starttime_2 = time.time()
host = 'http://ali.ip138.com'
path = '/ip/'
method = 'GET'
appcode = '917058e6d7c84104b7cab9819de54b6e'
arr = []
for row in tuple: get_ip = row[0]
#get_user = "".join(str(row))
#get_user = row[0] # 对从数据库表中出查询的IP进行解析
querys = 'callback&datatype=jsonp&ip=' + get_ip
bodys = {}
url = host + path + '?' + querys
request = urllib.request.Request(url)
request.add_header('Authorization', 'APPCODE ' + appcode) # 连接url时可能会出现 ERROR: HTTP Error 503: Service Unavailable
try:
response = urllib.request.urlopen(request)
except Exception as e:
logging.error(e) # 输出异常日志信息
time.sleep(5)
response = urllib.request.urlopen(request)
finally:
content = response.read()
ip_area = content.decode('utf8')
ip_area = json.loads(ip_area)['data'] # json类型转字典类型并取'data'健值
arr.append([get_ip, ip_area]) # 将结果集存于二元数组
logging.info('每页解析秒数:' + str(time.time() - starttime_2))
return arr def ip_write_db(table_name): write_ip = get_ip_area(table_name) # 内包含用户ID和IP的数组的元组 # 测试1
starttime_3 = time.time() # 建立游标,用来执行数据库操作
cur = conn.cursor()
for row in write_ip:
# get_user = row[0] # 获取用户ID
get_ip = row[0] # 获取用户对应的IP
country = row[1][0] # 获取IP解析后的地区:国家
province = row[1][1] # 获取IP解析后的地区:省
city = row[1][2] # 获取IP解析后的地区:市
isp = row[1][3] # 获取IP解析后的服务提供商 # 执行SQL命令
sql = "insert into d_ip_area_mapping(remote_ip,country,province,city,isp,created_at,updated_at,job_id) values (%s,%s,%s,%s,%s,%s,%s,%s);"
val = [get_ip, country, province, city, isp, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),time.strftime("%Y-%m-%d",time.localtime())] cur.execute(sql, val)
conn.commit()
# 关闭游标
cur.close()
logging.info('每页插入秒数:' + str(time.time() - starttime_3)) # 1.程序开始执行计时
starttime = time.time() # 读取配置文件环境信息 # 项目路径
rootDir = os.path.split(os.path.realpath(__file__))[0] ############################### config.env文件路径 ############################################################# configFilePath = os.path.join(rootDir, 'db_udw.env')
config = configparser.ConfigParser()
config.read(configFilePath) # 读取数据库环境信息
db_database = config.get('postgresql','database')
db_user = config.get('postgresql','user')
db_password = config.get('postgresql','password')
db_host = config.get('postgresql','host')
db_port = config.get('postgresql','port') # 读取输出日志路径
log = config.get('log','log_path') # 每页查询数据条数
pagesize = config.get('page','pagesize') # 读取解析IP条数限制
ip_num_limit = config.get('ip_num','ip_num_limit') # 配置输出日志格式
logging.basicConfig(level=logging.DEBUG,#控制台打印的日志级别
filename='{my_log_path}/ip_analyzer.log'.format(my_log_path=log), # 指定日志文件及路径
filemode='a',##模式,有w和a,w就是写模式,每次都会重新写日志,覆盖之前的日志 #a是追加模式,默认如果不写的话,就是追加模式
format='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s'#日志格式
) ############################### 程序开始执行 #############################################################
try: # 连接到一个给定的数据库
conn = psycopg2.connect(database=db_database, user=db_user, password=db_password, host=db_host, port=db_port)
except Exception as e:
logging.error(e) # 输出连接异常日志信息 # 返回查询行数 默认为0
rows_count = 0
# 用户表IP解析总数
user_ip_num = 0
# 订单表IP解析总数
order_ip_num = 0 try: # 解析用户表注册IP信息
while user_ip_num <= eval(ip_num_limit):
i = 1 # 循环次数
ip_write_db("h_user_stat")
user_ip_num = user_ip_num + rows_count*i
i = i + 1
if rows_count == 0 :
break # 解析订单表下单IP信息
while user_ip_num <= eval(ip_num_limit):
# 解析用户表注册IP信息
i = 1 # 循环次数
ip_write_db("h_order")
order_ip_num = order_ip_num + rows_count*i
i = i + 1
if rows_count == 0 :
break
except Exception as e:
logging.error(e) # 输出异常日志信息
finally:
# 关闭数据库连接
conn.close() # 2 程序结束执行计时
endtime = time.time() # print('解析用户IP的总数:' + str(user_ip_num))
# print('解析订单IP的总数:' + str(order_ip_num))
# # 打印程序执行总耗时
# print('解析总耗时秒数:' + str(endtime - starttime))
logging.info('解析用户IP的总数:' + str(user_ip_num))
logging.info('解析订单IP的总数:' + str(order_ip_num))
logging.info('解析总耗时秒数:' + str(endtime - starttime))

环境配置db_udw.envdb_udw.env 如下:

# 数据库环境信息
[postgresql]
database = ahaschool_udw
user = admin
password = 123456
host = 127.0.0.0
port = 5432 # 设置日志文件路径
[log]
log_path = /home/hjmrunning/bi_etl_product/scripts/log # 每页查询数据条数
[page]
pagesize = 1000 # IP解析条数限制
[ip_num]
ip_num_limit = 150000

最后

我接触Python时间也不是很久,实现方法可能会有疏漏。如果有什么疑问和见解,欢迎评论区交流。

 

Python 实现批量查询IP并解析为归属地的更多相关文章

  1. 【Python】批量查询-提取站长之家IP批量查询的结果加强版本v3.0

    1.工具说明 写报告的时候为了细致性,要把IP地址对应的地区给整理出来.500多条IP地址找出对应地区复制粘贴到报告里整了一个上午. 为了下次更好的完成这项重复性很高的工作,所以写了这个小的脚本. 某 ...

  2. 【Python】批量查询-提取站长之家IP批量查询的结果v1.0

    0 前言 写报告的时候为了细致性,要把IP地址对应的地区给整理出来.500多条IP地址找出对应地区复制粘贴到报告里整了一个上午. 为了下次更好的完成这项重复性很高的工作,所以写了这个小的脚本. 1 使 ...

  3. python实现批量ping IP,并将结果写入

    最近工作需要,写了一个Python小脚本,分享给大家,因为公司的IP用的差不多了,然后离职人员的IP有没有及时删除,导致没多少IP用了,所以做了一个python脚本跑了跑,清出来一堆ping不通的IP ...

  4. Python + MySQL 批量查询百度收录

    做SEO的同学,经常会遇到几百或几千个站点,然后对于收录情况去做分析的情况 那么多余常用的一些工具在面对几千个站点需要去做收录分析的时候,那么就显得不是很合适. 在此特意分享给大家一个批量查询百度收录 ...

  5. python爬虫学习之查询IP地址对应的归属地

    话不多说,直接上代码吧. import requests def getIpAddr(url): response = requests.get(url) response.encoding=resp ...

  6. 提取站长之家IP批量查询

    1.工具说明 写报告的时候为了细致性,要把IP地址对应的地区给整理出来.500多条IP地址找出对应地区复制粘贴到报告里整了一个上午. 为了下次更好的完成这项重复性很高的工作,所以写了这个小的脚本. 使 ...

  7. 利用撒旦搜索引擎查询ip个数,批量下载ip

    利用撒旦搜索引擎查询ip个数,批量下载ip,使用语言python3.x 批量测试时,为了方便直接撸下ip,所以用python写了个GUI撒旦利用工具,写的不是很好,但能用,最下面有下载. from t ...

  8. 利用Dnspod api批量更新添加DNS解析【python脚本】 - 推酷

    利用Dnspod api批量更新添加DNS解析[python脚本] - 推酷 undefined

  9. shell脚本和python脚本实现批量ping IP测试

    先建一个存放ip列表的txt文件: [root@yysslopenvpn01 ~]# cat hostip.txt 192.168.130.1 192.168.130.2 192.168.130.3 ...

随机推荐

  1. AIZU AOJ 2309 Vector Compression 最小树形图(朱—刘算法)

    题意简述:给定若干个相同维度的向量,寻找一种排序方法,使得所有向量的表示长度总和最低. 所谓表示长度为(Aj-r*Ai)^2,其中i<j  数据范围:向量总数和维度均小于100 思路:(1)首先 ...

  2. 如何给mysql用户分配权限+增、删、改、查mysql用户

    在mysql中用户权限是一个很重析 参数,因为台mysql服务器中会有大量的用户,每个用户的权限需要不一样的,下面我来介绍如何给mysql用户分配权限吧,有需要了解的朋友可参考. 1,Mysql下创建 ...

  3. Tomcat + solr5.2.1环境搭建

    1. 下载solr并解压后的目录为:E:\solr-5.2.1   ,  http://lucene.apache.org/solr/downloads.html 2. 将solr部署到Tomcat中 ...

  4. deepin 安装 idea

    1.su root 2.sudo apt install idea 3.sudo vi /etc/hosts 最后一行添加 0.0.0.0 account.jetbrains.com 4.注册码 N7 ...

  5. 二分搜索 HDOJ 2675 Equation Again

    题目传送门 /* 二分搜索:式子两边取对数,将x提出来,那么另一边就是一个常数了,函数是:lnx/x.二分搜索x,注意要两次 */ #include <cstdio> #include & ...

  6. ACM_01背包

    背包1 Time Limit: 2000/1000ms (Java/Others) Problem Description: 有n个重量和价值分别为Wi,Vi的物品,现从这些物品中挑选出总量不超过 W ...

  7. 《编写可维护的Javascript》学习总结

    第一部分 一.基本规范 1.缩进:一般以四个空格为一个缩进. 2.语句结尾:最好加上分号,因为虽然“自动分号插入(ASI)”机制在没有分号的位置会插入分号,但是ASI规则复杂而且会有特殊情况发生 // ...

  8. Java 8 (10) CompletableFuture:组合式异步编程

    随着多核处理器的出现,提升应用程序的处理速度最有效的方式就是可以编写出发挥多核能力的软件,我们已经可以通过切分大型的任务,让每个子任务并行运行,使用线程的方式,分支/合并框架(java 7) 和并行流 ...

  9. Objective-C设计模式——外观Faced(接口适配)

    外观模式 外观设计模式和适配器差不多,不过它门对对象控制的粒度不同,适配器一般只是控制一个系统和客户端的对接.外观则是用来抽象多个系统一起工作. 外观一般具有多个子系统,所以外观应持有多个子系统的引用 ...

  10. Django--4、认证系统

    cookie与session 概念 因http协议无法保存状态,但是又需要保存状态,所以有了cookie.它不属于http协议范畴 工作原理:相当于一段标识数据.在访问服务器产生标识内容(cookie ...