PS: Online directly to find, paste out, convenient to use at any time, thanks to the people who share.
#!/usr/bin/python#encoding:utf-8import socketimport codecsimport mmapfrom struct import pack, Unpackdef decode_str (old ): "Specifically for pure GBK encoded string decompression returns UTF8 string ' ' Try:return Unicode (old, ' GBK '). Encode (' Utf-8 ') except: # when the string decoding fails, and the most byte value is ' \x96 ', remove it, and then resolve if old[-1] = = ' \x96 ': Try:return Unicode (old[:-1], ' GBK '). Encode (' utf-8 ') + '? ' Except:pass return ' Invalid ' class Qqwry (object): Def __init__ (self, path): Self.path = PA Th self.db = None self.open_db () self.idx_start, self.idx_end = Self._read_idx () # IP Index Total Self.total = (Self.idx_end-self.idx_start)/7 + 1 def open_db (self): if not self.db:self.db = Open (Self.path, ' rb ') self.db = Mmap.mmap (Self.db.fileno (), 0, Access = 1) return self.db def _read_i DX (self): ' Read the IP index start and end offset values in the database ' ' Self.db.seek (0) Start = unpack (' I ', SELf.db.read (4)) [0] end = Unpack (' I ', Self.db.read (4)) [0] return start, End Def version (self): " Returns the version information format of the pure IP library such as "Pure Network August 5, 2014 IP data" ' Ip_end_offset = Self.read_offset (Self.idx_end + 4) A_raw, B_raw = Self.read_record (ip_end_offset+4) return decode_str (A_raw + b_raw) def read_ip (self, off, see K=true): ' Read IP value (4 byte integer value) return IP value ' if Seek:self.db.seek (off) buf = Self.db.read (4) Return unpack (' I ', buf) [0] def read_offset (self, Off, seek=true): ' reads 3 bytes of offset value Returns the integer value of the offset "if Seek:self.db.seek (off) buf = Self.db.read (3) Return unpack (' I ', buf+ ') [0] def read_string (self, offset): ' reads the original string (ends with "\") returns the tuple: string "if offset = = 0: Return ' N/A1 ' flag = self.get_flag (offset) if flag = = 0:return ' n/a2 ' elif fl AG = = 2: # 0x02 indicates that the information is still required to redirect offset = Self.read_offset (offset+1) return self.read_string (offset) Self.db.seek (offset) raw_string = "while true:x = Self.db.read (1) if x = = ' ': ' break raw_string + = x return raw_string def get_flag (self, offset): ' ' Reading the 1-byte integer value at offset qqwry the first byte value of the address information string may be a flag bit, which is a common function. "' Self.db.seek (offset) c = self.db.read (1) if not C:return 0 return ord (c) de F Read_record (self, offset): Self.db.seek (offset) # reads flag flag = Ord (Self.db.read (1)) if FLA G = = 1: # 0x01 indicates that the record area record (country, region) information is redirected # Note: Once redirected, the record may also be a redirect (its flag=0x02) buf = Self.db.rea D (3) A_offset = Unpack (' I ', buf+ ') [0] A_raw = self.read_string (a_offset) # Judging the flag of the new record is No for 0x02, if yes, indicates: #-Country Info redirect Additional address #-region information for new recordStart Address offset 4 bytes A_flag = Self.get_flag (a_offset) if A_flag = = 2:b_raw = Self.read_string (A _offset+4) Else:b_raw = self.read_string (A_offset+len (A_raw) +1) elif flag = = 2: # 0x02 indicates only country record redirection # region information Offset 4 bytes buf = self.db.read (3) A_offset = Unpack (' I ', buf+ ' ") [0 ] A_raw = self.read_string (a_offset) B_raw = self.read_string (offset+4) Else: # Normal Information record A_raw = self.read_string (offset) B_raw = self.read_string (Offset+len (A_raw) +1) return a _raw, B_raw def output (self, output_file= ' ip.txt '): ' Output all IP information to file ' fp = Codecs.open (ou Tput_file, ' w ', ' UTF8 ') idx = self.idx_start while idx <= self.idx_end:ip_int = self.read_ip ( IDX) Ip_start = Socket.inet_ntoa (Pack ('! I ', ip_int)) Ip_end_offset = Self.read_offset (idx + 4) Ip_int = Self.read_ip (ip_end_offset) ip_end = Socket.inet_ntoa (Pack ('! I ', ip_int)) A_raw, B_raw = Self.read_record (ip_end_offset+4) A_info = Decode_str (A_raw) B_info = Decode_str (B_raw) fp.write (U '%15s\t%15s\t%s,%s\n '% (Ip_start, Ip_end, a _info.decode (' UTF8 '), b_info.decode (' UTF8 ')) # Step 7 bytes: 4 byte starting IP value + 3 byte end IP Offset value idx + = 7 Fp.clo SE () def find (self, IP, L, R): "Use dichotomy to find the index record of network byte-encoded IP address" if r-l <= 1: return l m = (L + r)/2 offset = Self.idx_start + M * 7 new_ip = self.read_ip (offset) If IP < New_ip:return self.find (IP, L, m) else:return self.find (IP, M, r) def query (self, I p): "Query IP Information '" # Using network byte encoding IP Address IP = unpack ('! I ', Socket.inet_aton (IP)) [0] # Find the index offset of the IP using the self.find function i = self.find (IP, 0, self.total-1) # get indexed Records o = Self.idx_start + i * 7 # Index record format is: first 4 bytes IP information + 3 byte offset to IP record information # Here is the use of the last 3 bytes as an offset to get its regular representation (QQWry.Dat with characters String representation value) O2 = Self.read_offset (O + 4) # IP record offset value +4 can discard the first 4 bytes of IP address information. (c, a) = Self.read_record (O2 + 4) return (DECODE_STR (c), Decode_str (a)) def __del__ (self): if self.db: Self.db.close () def main (): DBPath = "C:\ipdata\qqwry.dat" IP = "183.61.60.23" Qqwry = Qqwry (dbpath) C , a = Qqwry.query (IP) print '%s%s--%s '% (IP, c.decode (' Utf-8 '), A.decode (' Utf-8 ')) if __name__ = = ' __main__ ': Main ( )
Result:
Python uses the Pure Age database Qqwry.dat to convert physical locations