python访问纯真IP数据库的代码
核心代码:
#!/usr/bin/env python # -*- coding: utf-8 -*- from bisect import bisect _LIST1, _LIST2 = [], [] _INIT = False ip2int = lambda ip_str: reduce(lambda a, b: (a << 8) + b, [int(i) for i in ip_str.split('.')]) def _init(): global _LIST, _INIT if not _INIT: for l in open('ipdata.txt', 'rb'): ip1, ip2 = l.split()[:2] addr = ' '.join(l.split()[2:]) ip1, ip2 = ip2int(ip1), ip2int(ip2) _LIST1.append(ip1) _LIST2.append((ip1, ip2, addr)) _INIT = True def ip_from(ip): _init() i = ip2int(ip) idx = bisect(_LIST1, i) assert(idx > 0) if len(_LIST1) <= idx: return u'unknown ip address %s' % ip else: frm, to ,addr = _LIST2[idx - 1] if frm <= i <= to: return addr else: return u'unknown ip address %s' % ip if __name__ == '__main__': print ip_from('115.238.54.106') print ip_from('220.181.29.160') print ip_from('115.238.54.107') print ip_from('8.8.8.8')
代码打包下载 http://xiazai.bitsCN.com/201105/yuanma/ipaddress.7z
接下来为大家分享更完美的代码:
#!/usr/bin/env python # coding: utf-8 '''用Python脚本查询纯真IP库 QQWry.Dat的格式如下: +----------+ | 文件头 | (8字节) +----------+ | 记录区 | (不定长) +----------+ | 索引区 | (大小由文件头决定) +----------+ 文件头:4字节开始索引偏移值+4字节结尾索引偏移值 记录区: 每条IP记录格式 ==> IP地址[国家信息][地区信息] 对于国家记录,可以有三种表示方式: 字符串形式(IP记录第5字节不等于0x01和0x02的情况), 重定向模式1(第5字节为0x01),则接下来3字节为国家信息存储地的偏移值 重定向模式(第5字节为0x02), 对于地区记录,可以有两种表示方式: 字符串形式和重定向 最后一条规则:重定向模式1的国家记录后不能跟地区记录 索引区: 每条索引记录格式 ==> 4字节起始IP地址 + 3字节指向IP记录的偏移值 索引区的IP和它指向的记录区一条记录中的IP构成一个IP范围。查询信息是这个 范围内IP的信息 ''' import sys import socket from struct import pack, unpack class IPInfo(object): '''QQWry.Dat数据库查询功能集合 ''' def __init__(self, dbname): ''' 初始化类,读取数据库内容为一个字符串, 通过开始8字节确定数据库的索引信息''' self.dbname = dbname # f = file(dbname, 'r') # Demon注:在Windows下用'r'会有问题,会把\r\n转换成\n # 详见http://demon.tw/programming/python-open-mode.html # 还有Python文档中不提倡用file函数来打开文件,推荐用open f = open(dbname, 'rb') self.img = f.read() f.close() # QQWry.Dat文件的开始8字节是索引信息,前4字节是开始索引的偏移值, # 后4字节是结束索引的偏移值。 # (self.firstIndex, self.lastIndex) = unpack('II', self.img[:8]) # Demon注:unpack默认使用的endian是和机器有关的 # Intel x86和AMD64(x86-64)是little-endian # Motorola 68000和PowerPC G5是big-endian # 而纯真数据库全部采用了little-endian字节序 # 所以在某些big-endian的机器上原代码会出错 (self.firstIndex, self.lastIndex) = unpack('<II', self.img[:8]) # 每条索引长7字节,这里得到索引总个数 self.indexCount = (self.lastIndex - self.firstIndex) / 7 + 1 def getString(self, offset = 0): ''' 读取字符串信息,包括"国家"信息和"地区"信息 QQWry.Dat的记录区每条信息都是一个以'\0'结尾的字符串''' o2 = self.img.find('\0', offset) #return self.img[offset:o2] # 有可能只有国家信息没有地区信息, gb2312_str = self.img[offset:o2] try: utf8_str = unicode(gb2312_str,'gb2312').encode('utf-8') except: return '未知' return utf8_str def getLong3(self, offset = 0): '''QQWry.Dat中的偏移记录都是3字节,本函数取得3字节的偏移量的常规表示 QQWry.Dat使用“字符串“存储这些值''' s = self.img[offset: offset + 3] s += '\0' # unpack用一个'I'作为format,后面的字符串必须是4字节 # return unpack('I', s)[0] # Demon注:和上面一样,强制使用little-endian return unpack('<I', s)[0] def getAreaAddr(self, offset = 0): ''' 通过给出偏移值,取得区域信息字符串,''' byte = ord(self.img[offset]) if byte == 1 or byte == 2: # 第一个字节为1或者2时,取得2-4字节作为一个偏移量调用自己 p = self.getLong3(offset + 1) return self.getAreaAddr(p) else: return self.getString(offset) def getAddr(self, offset, ip = 0): img = self.img o = offset byte = ord(img[o]) if byte == 1: # 重定向模式1 # [IP][0x01][国家和地区信息的绝对偏移地址] # 使用接下来的3字节作为偏移量调用字节取得信息 return self.getAddr(self.getLong3(o + 1)) if byte == 2: # 重定向模式2 # [IP][0x02][国家信息的绝对偏移][地区信息字符串] # 使用国家信息偏移量调用自己取得字符串信息 cArea = self.getAreaAddr(self.getLong3(o + 1)) o += 4 # 跳过前4字节取字符串作为地区信息 aArea = self.getAreaAddr(o) return (cArea, aArea) if byte != 1 and byte != 2: # 最简单的IP记录形式,[IP][国家信息][地区信息] # 重定向模式1有种情况就是偏移量指向包含国家和地区信息两个字符串 # 即偏移量指向的第一个字节不是1或2,就使用这里的分支 # 简单地说:取连续取两个字符串! cArea = self.getString(o) #o += 2*len(cArea) + 1 # 我们已经修改cArea为utf-8字符编码了,len取得的长度会有变, # 用下面方法得到offset o = self.img.find('\0',o) + 1 aArea = self.getString(o) if aArea == "?": aArea = "电信" if aArea == "信": aArea = "" if aArea == "[": aArea = "联通" return (cArea, aArea) def find(self, ip, l, r): ''' 使用二分法查找网络字节编码的IP地址的索引记录''' if r - l <= 1: return l m = (l + r) / 2 o = self.firstIndex + m * 7 #new_ip = unpack('I', self.img[o: o+4])[0] # Demon注:和上面一样,强制使用little-endian new_ip = unpack('<I', self.img[o: o+4])[0] if ip <= new_ip: return self.find(ip, l, m) else: return self.find(ip, m, r) def getIPAddr(self, ip): ''' 调用其他函数,取得信息!''' # 使用网络字节编码IP地址 ip = unpack('!I', socket.inet_aton(ip))[0] # 使用 self.find 函数查找ip的索引偏移 i = self.find(ip, 0, self.indexCount - 1) # 得到索引记录 o = self.firstIndex + i * 7 # 索引记录格式是: 前4字节IP信息+3字节指向IP记录信息的偏移量 # 这里就是使用后3字节作为偏移量得到其常规表示(QQWry.Dat用字符串表示值) o2 = self.getLong3(o + 4) # IP记录偏移值+4可以丢弃前4字节的IP地址信息。 (c, a) = self.getAddr(o2 + 4) return (c, a) def output(self, first, last): for i in range(first, last): o = self.firstIndex + i * 7 ip = socket.inet_ntoa(pack('!I', unpack('I', self.img[o:o+4])[0])) offset = self.getLong3(o + 4) (c, a) = self.getAddr(offset + 4) print "%s %d %s/%s" % (ip, offset, c, a) def getIP(ip): import os _localDir=os.path.dirname(__file__) _curpath=os.path.normpath(os.path.join(os.getcwd(),_localDir)) curpath=_curpath i = IPInfo(curpath+'/qqwry.dat') (c, a) = i.getIPAddr(ip) return c+a def main(): import os _localDir=os.path.dirname(__file__) _curpath=os.path.normpath(os.path.join(os.getcwd(),_localDir)) curpath=_curpath i = IPInfo(curpath+'/qqwry.dat') if os.path.exists(sys.argv[1]): for line in open(sys.argv[1],"r").readlines(): line = line.replace("\r","").replace("\n","") (c, a) = i.getIPAddr(line) # Demon注:如果是在Windows命令行中运行把编码转回gb2312以避免乱码 if sys.platform == 'win32': c = unicode(c, 'utf-8').encode('gb2312') a = unicode(a, 'utf-8').encode('gb2312') print '%s %s/%s' % (line, c, a) else: (c, a) = i.getIPAddr(sys.argv[1]) # Demon注:如果是在Windows命令行中运行把编码转回gb2312以避免乱码 if sys.platform == 'win32': c = unicode(c, 'utf-8').encode('gb2312') a = unicode(a, 'utf-8').encode('gb2312') print '%s %s/%s' % (sys.argv[1], c, a) if __name__ == '__main__': main()
用Python脚本查询纯真IP库QQWry.dat(Demon修改版)
由于要用 Python 读取一个和纯真IP数据库 QQWry.dat 格式差不多的 IPv6 数据库,所以在网上搜索了一下,在 LinuxTOY 看到了一个 Python 脚本,发现有一些小小的问题,于是修改了一下。
#!/usr/bin/env python # coding: utf-8 # from: http://linuxtoy.org/files/pyip.py # Blog: http://linuxtoy.org/archives/python-ip.html # Modified by Demon # Blog: http://demon.tw/programming/python-qqwry-dat.html '''用Python脚本查询纯真IP库 QQWry.Dat的格式如下: +----------+ | 文件头 | (8字节) +----------+ | 记录区 | (不定长) +----------+ | 索引区 | (大小由文件头决定) +----------+ 文件头:4字节开始索引偏移值+4字节结尾索引偏移值 记录区: 每条IP记录格式 ==> IP地址[国家信息][地区信息] 对于国家记录,可以有三种表示方式: 字符串形式(IP记录第5字节不等于0x01和0x02的情况), 重定向模式1(第5字节为0x01),则接下来3字节为国家信息存储地的偏移值 重定向模式(第5字节为0x02), 对于地区记录,可以有两种表示方式: 字符串形式和重定向 最后一条规则:重定向模式1的国家记录后不能跟地区记录 索引区: 每条索引记录格式 ==> 4字节起始IP地址 + 3字节指向IP记录的偏移值 索引区的IP和它指向的记录区一条记录中的IP构成一个IP范围。查询信息是这个 范围内IP的信息 ''' import sys import socket from struct import pack, unpack class IPInfo(object): '''QQWry.Dat数据库查询功能集合 ''' def __init__(self, dbname): ''' 初始化类,读取数据库内容为一个字符串, 通过开始8字节确定数据库的索引信息''' self.dbname = dbname # f = file(dbname, 'r') # Demon注:在Windows下用'r'会有问题,会把\r\n转换成\n # 详见http://demon.tw/programming/python-open-mode.html # 还有Python文档中不提倡用file函数来打开文件,推荐用open f = open(dbname, 'rb') self.img = f.read() f.close() # QQWry.Dat文件的开始8字节是索引信息,前4字节是开始索引的偏移值, # 后4字节是结束索引的偏移值。 # (self.firstIndex, self.lastIndex) = unpack('II', self.img[:8]) # Demon注:unpack默认使用的endian是和机器有关的 # Intel x86和AMD64(x86-64)是little-endian # Motorola 68000和PowerPC G5是big-endian # 而纯真数据库全部采用了little-endian字节序 # 所以在某些big-endian的机器上原代码会出错 (self.firstIndex, self.lastIndex) = unpack('<II', self.img[:8]) # 每条索引长7字节,这里得到索引总个数 self.indexCount = (self.lastIndex - self.firstIndex) / 7 + 1 def getString(self, offset = 0): ''' 读取字符串信息,包括"国家"信息和"地区"信息 QQWry.Dat的记录区每条信息都是一个以'\0'结尾的字符串''' o2 = self.img.find('\0', offset) #return self.img[offset:o2] # 有可能只有国家信息没有地区信息, gb2312_str = self.img[offset:o2] try: utf8_str = unicode(gb2312_str,'gb2312').encode('utf-8') except: return '未知' return utf8_str def getLong3(self, offset = 0): '''QQWry.Dat中的偏移记录都是3字节,本函数取得3字节的偏移量的常规表示 QQWry.Dat使用“字符串“存储这些值''' s = self.img[offset: offset + 3] s += '\0' # unpack用一个'I'作为format,后面的字符串必须是4字节 # return unpack('I', s)[0] # Demon注:和上面一样,强制使用little-endian return unpack('<I', s)[0] def getAreaAddr(self, offset = 0): ''' 通过给出偏移值,取得区域信息字符串,''' byte = ord(self.img[offset]) if byte == 1 or byte == 2: # 第一个字节为1或者2时,取得2-4字节作为一个偏移量调用自己 p = self.getLong3(offset + 1) return self.getAreaAddr(p) else: return self.getString(offset) def getAddr(self, offset, ip = 0): img = self.img o = offset byte = ord(img[o]) if byte == 1: # 重定向模式1 # [IP][0x01][国家和地区信息的绝对偏移地址] # 使用接下来的3字节作为偏移量调用字节取得信息 return self.getAddr(self.getLong3(o + 1)) if byte == 2: # 重定向模式2 # [IP][0x02][国家信息的绝对偏移][地区信息字符串] # 使用国家信息偏移量调用自己取得字符串信息 cArea = self.getAreaAddr(self.getLong3(o + 1)) o += 4 # 跳过前4字节取字符串作为地区信息 aArea = self.getAreaAddr(o) return (cArea, aArea) if byte != 1 and byte != 2: # 最简单的IP记录形式,[IP][国家信息][地区信息] # 重定向模式1有种情况就是偏移量指向包含国家和地区信息两个字符串 # 即偏移量指向的第一个字节不是1或2,就使用这里的分支 # 简单地说:取连续取两个字符串! cArea = self.getString(o) #o += len(cArea) + 1 # 我们已经修改cArea为utf-8字符编码了,len取得的长度会有变, # 用下面方法得到offset o = self.img.find('\0',o) + 1 aArea = self.getString(o) return (cArea, aArea) def find(self, ip, l, r): ''' 使用二分法查找网络字节编码的IP地址的索引记录''' if r - l <= 1: return l m = (l + r) / 2 o = self.firstIndex + m * 7 #new_ip = unpack('I', self.img[o: o+4])[0] # Demon注:和上面一样,强制使用little-endian new_ip = unpack('<I', self.img[o: o+4])[0] if ip <= new_ip: return self.find(ip, l, m) else: return self.find(ip, m, r) def getIPAddr(self, ip): ''' 调用其他函数,取得信息!''' # 使用网络字节编码IP地址 ip = unpack('!I', socket.inet_aton(ip))[0] # 使用 self.find 函数查找ip的索引偏移 i = self.find(ip, 0, self.indexCount - 1) # 得到索引记录 o = self.firstIndex + i * 7 # 索引记录格式是: 前4字节IP信息+3字节指向IP记录信息的偏移量 # 这里就是使用后3字节作为偏移量得到其常规表示(QQWry.Dat用字符串表示值) o2 = self.getLong3(o + 4) # IP记录偏移值+4可以丢弃前4字节的IP地址信息。 (c, a) = self.getAddr(o2 + 4) return (c, a) def output(self, first, last): for i in range(first, last): o = self.firstIndex + i * 7 ip = socket.inet_ntoa(pack('!I', unpack('I', self.img[o:o+4])[0])) offset = self.getLong3(o + 4) (c, a) = self.getAddr(offset + 4) print "%s %d %s/%s" % (ip, offset, c, a) def main(): i = IPInfo('QQWry.Dat') (c, a) = i.getIPAddr(sys.argv[1]) # Demon注:如果是在Windows命令行中运行把编码转回gb2312以避免乱码 if sys.platform == 'win32': c = unicode(c, 'utf-8').encode('gb2312') a = unicode(a, 'utf-8').encode('gb2312') print '%s %s/%s' % (sys.argv[1], c, a) if __name__ == '__main__': main() # changelog # 时间:2009年5月29日 # 1. 工具下面网友的建议,修改"o += len(cArea) + 1" # http://linuxtoy.org/archives/python-ip.html#comment-113960 # 因为这个时候我已经把得到的字符串变成utf-8编码了,长度会有变化!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











Go 언어는 효율적이고 간결하며 배우기 쉬운 프로그래밍 언어입니다. 동시 프로그래밍과 네트워크 프로그래밍의 장점 때문에 개발자들이 선호합니다. 실제 개발에서 데이터베이스 작업은 필수적인 부분입니다. 이 기사에서는 Go 언어를 사용하여 데이터베이스 추가, 삭제, 수정 및 쿼리 작업을 구현하는 방법을 소개합니다. Go 언어에서는 일반적으로 사용되는 SQL 패키지, Gorm 등과 같은 타사 라이브러리를 사용하여 데이터베이스를 운영합니다. 여기서는 sql 패키지를 예로 들어 데이터베이스의 추가, 삭제, 수정 및 쿼리 작업을 구현하는 방법을 소개합니다. MySQL 데이터베이스를 사용하고 있다고 가정합니다.

MySQLi를 사용하여 PHP에서 데이터베이스 연결을 설정하는 방법: MySQLi 확장 포함(require_once) 연결 함수 생성(functionconnect_to_db) 연결 함수 호출($conn=connect_to_db()) 쿼리 실행($result=$conn->query()) 닫기 연결( $conn->close())

Hibernate 다형성 매핑은 상속된 클래스를 데이터베이스에 매핑할 수 있으며 다음 매핑 유형을 제공합니다. Join-subclass: 상위 클래스의 모든 열을 포함하여 하위 클래스에 대한 별도의 테이블을 생성합니다. 클래스별 테이블: 하위 클래스별 열만 포함하는 하위 클래스에 대한 별도의 테이블을 만듭니다. Union-subclass: Joined-subclass와 유사하지만 상위 클래스 테이블이 모든 하위 클래스 열을 통합합니다.

Apple의 최신 iOS18, iPadOS18 및 macOS Sequoia 시스템 릴리스에는 사진 애플리케이션에 중요한 기능이 추가되었습니다. 이 기능은 사용자가 다양한 이유로 손실되거나 손상된 사진과 비디오를 쉽게 복구할 수 있도록 설계되었습니다. 새로운 기능에는 사진 앱의 도구 섹션에 '복구됨'이라는 앨범이 도입되었습니다. 이 앨범은 사용자가 기기에 사진 라이브러리에 포함되지 않은 사진이나 비디오를 가지고 있을 때 자동으로 나타납니다. "복구된" 앨범의 출현은 데이터베이스 손상으로 인해 손실된 사진과 비디오, 사진 라이브러리에 올바르게 저장되지 않은 카메라 응용 프로그램 또는 사진 라이브러리를 관리하는 타사 응용 프로그램에 대한 솔루션을 제공합니다. 사용자는 몇 가지 간단한 단계만 거치면 됩니다.

HTML은 데이터베이스를 직접 읽을 수 없지만 JavaScript 및 AJAX를 통해 읽을 수 있습니다. 단계에는 데이터베이스 연결 설정, 쿼리 보내기, 응답 처리 및 페이지 업데이트가 포함됩니다. 이 기사에서는 JavaScript, AJAX 및 PHP를 사용하여 MySQL 데이터베이스에서 데이터를 읽는 실제 예제를 제공하고 쿼리 결과를 HTML 페이지에 동적으로 표시하는 방법을 보여줍니다. 이 예제에서는 XMLHttpRequest를 사용하여 데이터베이스 연결을 설정하고 쿼리를 보내고 응답을 처리함으로써 페이지 요소에 데이터를 채우고 데이터베이스를 읽는 HTML 기능을 실현합니다.

MySQL 데이터베이스 관리 시스템의 기본 원리 분석 MySQL은 데이터 저장 및 관리를 위해 구조화된 쿼리 언어(SQL)를 사용하는 일반적으로 사용되는 관계형 데이터베이스 관리 시스템입니다. 이 글에서는 데이터베이스 생성, 데이터 테이블 설계, 데이터 추가, 삭제, 수정 및 쿼리 등을 포함한 MySQL 데이터베이스 관리 시스템의 기본 원리를 소개하고 구체적인 코드 예제를 제공합니다. 1. 데이터베이스 생성 MySQL에서는 먼저 데이터를 저장할 데이터베이스 인스턴스를 생성해야 합니다. 다음 코드는 "my

PHP는 웹사이트 개발에 널리 사용되는 백엔드 프로그래밍 언어로, 강력한 데이터베이스 운영 기능을 갖추고 있으며 MySQL과 같은 데이터베이스와 상호 작용하는 데 자주 사용됩니다. 그러나 한자 인코딩의 복잡성으로 인해 데이터베이스에서 잘못된 한자를 처리할 때 문제가 자주 발생합니다. 이 기사에서는 잘못된 문자의 일반적인 원인, 솔루션 및 특정 코드 예제를 포함하여 데이터베이스에서 중국어 잘못된 문자를 처리하기 위한 PHP의 기술과 사례를 소개합니다. 문자가 왜곡되는 일반적인 이유는 잘못된 데이터베이스 문자 집합 설정 때문입니다. 데이터베이스를 생성할 때 utf8 또는 u와 같은 올바른 문자 집합을 선택해야 합니다.

PHP에서 데이터베이스 연결 오류를 처리하려면 다음 단계를 사용할 수 있습니다. mysqli_connect_errno()를 사용하여 오류 코드를 얻습니다. 오류 메시지를 얻으려면 mysqli_connect_error()를 사용하십시오. 이러한 오류 메시지를 캡처하고 기록하면 데이터베이스 연결 문제를 쉽게 식별하고 해결할 수 있어 애플리케이션이 원활하게 실행될 수 있습니다.
