免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2938 | 回复: 0
打印 上一主题 下一主题

ruby 查询 QQwry.dat ip 库的 IpLocationSeeker 类 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-01-14 13:29 |只看该作者 |倒序浏览
ruby 查询 QQwry.dat ip 库的类
使用的是 QQwry.dat 的IP库, 网上貌似可以下载这个库, 不过已经是exe格式了, 汗. 还是喜欢以前的 压缩格式
  1. #!/usr/bin/env ruby
  2. # coding: utf-8
  3. # jianglibo(jianglibo@gmail.com)
  4. # website: http://www.g0574.com
  5. # =KK= 修改
  6. #

  7. require 'iconv'

  8. class IpLocationSeeker
  9.   def initialize()
  10.     fQQwry='D:\QQWry.Dat'
  11.     #@datafile = File.open(fQQwry,"r:utf-8")
  12.     @datafile = File.open(fQQwry,"rb")
  13.     @first_index_pos,@last_index_pos  = @datafile.read(8).unpack('L2')
  14.     @index_num = (@last_index_pos - @first_index_pos)/7 + 1
  15.   end

  16.   def renamed_eump(number=100)
  17.     p 'renamed eump' if $DEBUG
  18.     last_index_pos = number * 7
  19.     last_index_pos = @last_index_pos if last_index_pos > @last_index_pos
  20.     current_num = 0
  21.     error_num = 0
  22.     @first_index_pos.step(last_index_pos,7) do |a_pos|
  23.         begin
  24.           current_num +=1
  25.           @datafile.seek(a_pos)
  26.           ip_int = @datafile.read(4).unpack('L1')
  27.           @ip_record_pos = three_bytes_long_int(@datafile.read(3).unpack('C3'))
  28.           puts ip_int.to_s + "***"+get_country_string + '***' + get_area_string
  29.         rescue
  30.           err
  31.           puts "error at " + current_num.to_s
  32.           error_num += 1
  33.         end
  34.       end
  35.     return "total num:%s,error_num:%s  " %[current_num,error_num]
  36.   end

  37.   def seek(ip_str) #查询IP
  38.     p ' seek' if $DEBUG
  39.     @ip_str = ip_str
  40.     @ip_record_pos = get_ip_record_pos
  41.     begin #错误处理
  42.       return get_country_string + get_area_string
  43.     rescue Interrupt
  44.       return ip_str
  45.     rescue Exception => detail
  46.       err
  47.       return ip_str
  48.     #~ retry
  49.     end
  50.   end

  51.   def half_find(ip_want_int,index_lowest,index_highest) #二分
  52.      if index_highest - index_lowest == 1
  53.           index_lowest
  54.      else
  55.         index_middle = (index_lowest + index_highest)/2
  56.         file_offset = @first_index_pos + index_middle * 7
  57.         @datafile.seek(file_offset)
  58.         ip_middle_int = @datafile.read(4).unpack("L")[0]
  59.         if ip_want_int == ip_middle_int
  60.            index_lowest
  61.         elsif ip_want_int > ip_middle_int
  62.            index_lowest = index_middle
  63.            half_find(ip_want_int,index_lowest,index_highest)
  64.         else
  65.            index_highest = index_middle
  66.            half_find(ip_want_int,index_lowest,index_highest)
  67.         end
  68.      end
  69.   end

  70.   def three_bytes_long_int(three_byte)
  71.     (three_byte[2] << 16) + (three_byte[1]<<8) + three_byte[0]
  72.   end

  73.   def get_ip_record_pos()
  74.     p 'get ip record pos' if $DEBUG
  75.     ip_record_pos_pos = @first_index_pos + half_find(my_inet_aton(@ip_str),0,@index_num-1)*7 + 4
  76.     @datafile.seek(ip_record_pos_pos)
  77.     three_byte = @datafile.read(3).unpack('C3')
  78.     three_bytes_long_int(three_byte)
  79.   end

  80.   #读取直到字符串结尾
  81.   def read_zero_end_string(file_pos)
  82.     p 'read 0 str' if $DEBUG
  83.     @datafile.seek(file_pos)
  84.     str = ""
  85.     count = 0
  86.     while c = @datafile.getc
  87.       break if count>100
  88.       break if c.ord < 0x32
  89.       str << c
  90.       count += 1
  91.     end
  92.     if count > 70
  93.       puts 'ipwry count:' + count.to_s
  94.       str = "2 unknown string."
  95.       @get_country_string_error = true
  96.     end
  97.     @after_read_country_pos = @datafile.pos
  98.     return Iconv.conv("UTF-8//IGNORE","GB18030//IGNORE",str) rescue ''
  99.   end

  100.   #private

  101.   def get_country_string()
  102.     p 'get country str' if $DEBUG
  103.     @get_country_string_error = false
  104.     begin
  105.       @datafile.seek(@ip_record_pos + 4)
  106.       @mode_flag,  = @datafile.read(1).unpack("C1")
  107.       if @mode_flag == 1 #the next three bytes are another pointer
  108.         @ip_record_level_two_pos = three_bytes_long_int(@datafile.read(3).unpack('C3'))
  109.         @datafile.seek(@ip_record_level_two_pos)
  110.         @level_two_mode_flag, = @datafile.read(1).unpack("C1")
  111.         if @level_two_mode_flag == 2
  112.           @ip_record_level_three_pos = three_bytes_long_int(@datafile.read(3).unpack('C3'))
  113.           @level_three_mode_flag, = @datafile.read(1).unpack("C1")
  114.           read_zero_end_string(@ip_record_level_three_pos)
  115.         else
  116.           @level_two_mode_flag = 0
  117.           read_zero_end_string(@ip_record_level_two_pos)
  118.         end
  119.       elsif @mode_flag == 2
  120.         @ip_record_level_two_pos = three_bytes_long_int(@datafile.read(3).unpack('C3'))
  121.         read_zero_end_string(@ip_record_level_two_pos)
  122.       else
  123.         @mode_flag = 0
  124.         read_zero_end_string(@ip_record_pos + 4)
  125.       end
  126.     rescue
  127.       err
  128.       @get_country_string_error = true
  129.       return "unknown country!"
  130.     end
  131.   end

  132.   def get_area_string()
  133.     p 'get area string' if $DEBUG
  134.     @get_area_string_error = false
  135.     if @get_country_string_error
  136.       @get_area_string_error = true
  137.       return "4 unknown area!"
  138.     end
  139.     begin
  140.       if @mode_flag == 0
  141.         read_zero_end_string(@after_read_country_pos)
  142.       elsif @mode_flag == 1
  143.         if @level_two_mode_flag == 2
  144.           #p @level_three_mode_flag
  145.           if @level_three_mode_flag == 1 || @level_three_mode_flag == 2
  146.             @datafile.seek(@ip_record_level_two_pos + 5)
  147.             @ip_record_area_string_pos = three_bytes_long_int(@datafile.read(3).unpack('C3'))
  148.             read_zero_end_string @ip_record_area_string_pos
  149.           else
  150.             read_zero_end_string(@ip_record_level_two_pos + 4)
  151.           end
  152.         else
  153.           read_zero_end_string(@after_read_country_pos)
  154.         end
  155.       else
  156.         read_zero_end_string(@ip_record_pos+8)
  157.       end
  158.     rescue
  159.       err
  160.       @get_area_string_error = true
  161.       return "unknown area!"
  162.     end
  163.   end
  164.   def err
  165.     p $!.message + $@[0]
  166.   end

  167.   def my_inet_aton(ip_str)
  168.     ip_str.split(".").collect{|x|x.to_i}.inject(0){|ip_int,ip_field|
  169.       ip_int = (ip_int << 8) + ip_field
  170.     }
  171.   end
  172. end
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP