Получение имени страны пользователя из исходного IP-адреса с помощью Ruby on Rails

Я хочу извлечь имя страны пользователя из IP-адресов посетителей.

Я мог бы получить IP-адрес с помощью remote_ip. Но что может быть самым простым способом получить название страны?

Он не должен быть супер точным. Любая рубиновая библиотека (жемчужина или плагин) для этого?

Я хочу простое и легкое решение для этого.


person TK.    schedule 01.01.2010    source источник


Ответы (11)


Вы можете использовать geoip драгоценный камень.

окружающая среда.rb

config.gem 'geoip'

Скачать GeoIP.dat.gz с http://www.maxmind.com/app/geolitecountry. разархивируйте файл. Ниже предполагается, что под #{RAILS_ROOT}/db dir.

@geoip ||= GeoIP.new("#{RAILS_ROOT}/db/GeoIP.dat")    
remote_ip = request.remote_ip 
if remote_ip != "127.0.0.1" #todo: check for other local addresses or set default value
  location_location = @geoip.country(remote_ip)
  if location_location != nil     
    @model.country = location_location[2]
  end
end
person Chandra Patni    schedule 01.01.2010
comment
Похоже, они изменили формат этого файла, потому что если вам нужно полное имя, то location_location[5] — это то, что вам нужно. - person miccet; 17.03.2011
comment
На самом деле, из geoip 1.1.1 вы можете использовать @geoip.country(ip).country_name - person ndrix; 26.04.2012
comment
geoip устарел; см. мой ответ. - person Artelius; 10.01.2019

Вы также можете использовать "Geocoder"

Это просто облегчит вам жизнь. Поместите следующую строку в свой Gemfile и выполните команду установки пакета.

gem 'geocoder'

Используя этот Gem, вы можете легко получить страну, IP-адрес или даже город исходного IP-адреса. См. пример ниже

request.ip  # =>    "182.185.141.75"
request.location.city   # =>    ""
request.location.country    # =>    "Pakistan"
person Nadeem Yasin    schedule 20.11.2012
comment
Есть ли предел у этого драгоценного камня? Какой тип провайдера вы используете с этим драгоценным камнем? Я так понял, что есть ограничение в 2500 запросов в день. Пожалуйста, поправьте меня, если я ошибаюсь. Спасибо!. Документация немного запутанная. - person hyperrjas; 24.02.2013
comment
@hyperrjas да, если вы используете API Google, вы можете проверить квоту для каждого провайдера по этой ссылке github.com/alexreisner/geocoder#listing-and-comparison - person mohamagdy; 10.03.2013

Я использую этот однострочный:

locale = Timeout::timeout(5) { Net::HTTP.get_response(URI.parse('http://api.hostip.info/country.php?ip=' + request.remote_ip )).body } rescue "US"
person stef    schedule 03.02.2012
comment
Идеальный ответ. Большое спасибо! Я также добавил что-то вроде locale = 'US' if locale == 'XX'. В некоторых случаях api.hostip.info возвращал XX, так что я тоже это улавливаю. - person Tobias; 04.02.2014
comment
Оглядываясь назад, можно сказать, что существует опасность истечения времени ожидания этой службы, поэтому вам, вероятно, следует поместить это в асинхронный вызов и отправить его обратно в браузер через веб-сокет или путем опроса. И кешировать результат в чем-то вроде memcache или redis. - person stef; 05.02.2014

Самый простой — использовать для этого существующий веб-сервис.

Существуют плагины, которые позволяют делать гораздо больше, включая автоматическое определение геолокации ваших моделей (geokit-rails), но если все, что вам нужно, это, например, код страны, просто отправьте HTTP Get to http://api.hostip.info/country.php (есть и другие сервисы, но этот one не требует ключа API) вернет его, например :

Net::HTTP.get_response(URI.parse('http://api.hostip.info/country.php'))
=> US


Или опрос http://api.hostip.info/ вернет полный XML-ответ с указанием города, широты и долготы. , и т.д.

Имейте в виду, что полученные вами результаты не являются точными на 100%. Например, прямо сейчас я нахожусь во Франции, но сообщается, что в Германии. Это будет иметь место практически для любого IP-сервиса.

person JRL    schedule 01.01.2010
comment
Вы можете передать IP-адрес посещающего пользователя этому API в качестве параметра api.hostip.info /?ip=217.132.3.54, что означает, что вы можете использовать Net::HTTP.get_response(URI.parse('api.hostip.info/country.php?ip=' + request.remote_ip )) (Не уверен, почему этот символ появляется, и я не могу от него избавиться) - person stef; 03.02.2012
comment
Да вроде самый простой вариант. Другой API, который вы можете использовать, — это ipinfo.io, который вернет полные данные JSON, если вы запросите именно это, или вы можете получить просто строка страны с ipinfo.io/country - person Ben Dowling; 30.06.2014
comment
@BenDowling +1 за ipinfo.io — я только что протестировал дюжину реальных примеров, и в большинстве случаев hostip.info потерпел неудачу. ipinfo.io не промахнулся. Очень разумные цены / ограничения скорости тоже. - person Yarin; 24.06.2015

Для этого вы можете использовать мой собственный сервис https://ipinfo.io. Он дает вам код страны и кучу других деталей:

$ curl ipinfo.io
{
  "ip": "24.6.61.239",
  "hostname": "c-24-6-61-239.hsd1.ca.comcast.net",
  "city": "Mountain View",
  "region": "California",
  "country": "US",
  "loc": "37.3845,-122.0881",
  "org": "AS7922 Comcast Cable Communications, LLC",
  "postal": "94040"
}

Если вам просто нужна страна, вы можете получить ее, запросив /country

$ curl ipinfo.io/country
US

Затем вы можете сопоставить код страны с названием, используя данные с http://country.io или используя пример на http://ipinfo.io/developers/full-country-names

person Ben Dowling    schedule 06.01.2017
comment
%x(curl 'ipinfo.io/country') правильный код для использования. Он возвращает страну сервера или страну клиента? Существуют ли квоты или другие ограничения, которые необходимо соблюдать? - person Asarluhi; 04.08.2017
comment
Если вы вызываете его с сервера, он вернет IP-адрес сервера - вам нужно передать IP-адрес клиента. См. ipinfo.io/developers. - person Ben Dowling; 04.08.2017

Драгоценный камень geoip больше не работает с новыми базами данных MaxMind. Для этого есть новый гем, MaxMind-DB-Reader-ruby. .

Просто загрузите двоичные файлы City или Country, сжатые gzip-базы данных с MaxMind, разархивируйте и используйте код следующего вида:

require 'maxmind/db'

reader = MaxMind::DB.new('GeoIP2-City.mmdb', mode: MaxMind::DB::MODE_MEMORY)

# you probably want to replace 1.1.1.1 with  request.remote_ip
# or request.env['HTTP_X_FORWARDED_FOR']
ip_addr = '1.1.1.1'
record = reader.get(ip_addr)
if record.nil?
  puts '#{ip_addr} was not found in the database'
else
  puts record['country']['iso_code']
  puts record['country']['names']['en']
end

reader.close

Адаптируйте в зависимости от ваших потребностей. Я создал метод в инициализаторе, который я могу вызывать по мере необходимости.

person Artelius    schedule 10.01.2019
comment
Это официальный гем / репозиторий Maxmind для их материалов, поэтому база данных также должна оставаться актуальной, спасибо Artelius :) - person Kem Mason; 09.10.2019

Я только что опубликовал драгоценный камень для IPLocate.io API, который я создал.

Очень просто, не нужно скачивать базы данных и 1500 бесплатных запросов в день:

require 'iplocate'

# Look up an IP address
results = IPLocate.lookup("8.8.8.8")

# Or with an API key
results = IPLocate.lookup("8.8.8.8", "abcdef")

results["country"]
# "United States"

results["country_code"]
# "US"

results["org"]
# "Google LLC"

results.inspect
# {
#   "ip"=>"8.8.8.8",
#   "country"=>"United States",
#   "country_code"=>"US",
#   "city"=>nil,
#   "continent"=>"North America",
#   "latitude"=>37.751,
#   "longitude"=>-97.822,
#   "time_zone"=>nil,
#   "postal_code"=>nil,
#   "org"=>"Google LLC",
#   "asn"=>"AS15169"
# }  

Нет драгоценного камня

Его также можно использовать без драгоценного камня, просто используя Ruby Net::HTTP и URI:

response = Net::HTTP.get( URI.parse( "https://www.iplocate.io/api/lookup/8.8.8.8" ) )

Запрос вернет JSON, чтобы вы могли проанализировать его и получить к нему доступ следующим образом:

country = JSON.parse( response )["country"]
# => "US"
person ttarik    schedule 11.12.2017
comment
Отличный маленький сервис! Подключил его на Ruby, даже не скачивая гем. Просто сделайте запрос Net::HTTP с помощью JSON.parse( Net::HTTP.get( URI.parse( "https://www.iplocate.io/api/lookup/139.18.2.74" ) ) ) - person Joshua Pinter; 18.03.2018
comment
@ttarik, когда я запускаю ваш код, я получаю сообщение об ошибке: `require': невозможно загрузить такой файл -- IP-адрес (LoadError).... Я скачал гем iplocate. У вас есть возможное решение этой проблемы? - person tee; 24.06.2018
comment
@tee Похоже, он не может найти драгоценный камень. Вы добавили iplocate в свой Gemfile и запустили bundle install? Или вы можете использовать пример кода «No Gem», услужливо опубликованный Джошуа :) - person ttarik; 25.06.2018
comment
@ttarik Я добавил драгоценный камень и все еще получаю сообщение об ошибке ... все хорошо, хотя я могу использовать код «Нет драгоценного камня», спасибо! - person tee; 25.06.2018

Вы можете попробовать гем локатора Яндекса, сервис возвращает долготу, широту и точность.

conn = YandexLocator::Client.new
result = conn.lookup(ip: "109.252.52.39")
# => {"position"=>{"altitude"=>0.0, "altitude_precision"=>30.0, "latitude"=>55.75395965576172, "longitude"=>37.62039184570312, "precision"=>100000.0, "type"=>"ip"}}
person Sergey Chechaev    schedule 04.10.2016

Попробуйте IP2Location Ruby

https://github.com/ip2location/ip2location-ruby

Предварительное условие

Загрузите бесплатную базу данных LITE с http://lite.ip2location.com/ и используйте ниже.

Установить

gem install ip2location_ruby

использование

require 'ip2location_ruby'

i2l = Ip2location.new.open("./data/IP-COUNTRY-SAMPLE.BIN")
record = i2l.get_all('8.8.8.8')

print 'Country Code: ' + record.country_short + "\n"
print 'Country Name: ' + record.country_long + "\n"
print 'Region Name: ' + record.region + "\n"
print 'City Name: ' + record.city + "\n"
print 'Latitude: '
print record.latitude
print "\n"
print 'Longitude: '
print record.longitude
print "\n"
print 'ISP: ' + record.isp + "\n"
print 'Domain: ' + record.domain + "\n"
print 'Net Speed: ' + record.netspeed + "\n"
print 'Area Code: ' + record.areacode + "\n"
print 'IDD Code: ' + record.iddcode + "\n"
print 'Time Zone: ' + record.timezone + "\n"
print 'ZIP Code: ' + record.zipcode + "\n"
print 'Weather Station Code: ' + record.weatherstationname + "\n"
print 'Weather Station Name: ' + record.weatherstationcode + "\n"
print 'MCC: ' + record.mcc + "\n"
print 'MNC: ' + record.mnc + "\n"
print 'Mobile Name: ' + record.mobilebrand + "\n"
print 'Elevation: '
print record.elevation
print "\n"
print 'Usage Type: ' + record.usagetype + "\n"
person Vlam    schedule 11.12.2017

Вот пример Ruby, вызывающий API ipdata.co.

Это быстро и надежно благодаря наличию 10 глобальных конечных точек, каждая из которых способна обрабатывать более 10 000 запросов в секунду!

В этом ответе используется «тестовый» ключ API, который очень ограничен и предназначен только для тестирования нескольких вызовов. Зарегистрируйтесь для получения собственного бесплатного ключа API и получать до 1500 запросов ежедневно на разработку.

Замените 78.8.53.5 любым IP-адресом, который вы хотите найти.

require 'rubygems' if RUBY_VERSION < '1.9'
require 'rest_client'

headers = {
  :accept => 'application/json'
}

response = RestClient.get 'https://api.ipdata.co/78.8.53.5?api-key=test', headers
puts response

Это даст вам

{
    "ip": "78.8.53.5",
    "is_eu": true,
    "city": "G\u0142og\u00f3w",
    "region": "Lower Silesia",
    "region_code": "DS",
    "country_name": "Poland",
    "country_code": "PL",
    "continent_name": "Europe",
    "continent_code": "EU",
    "latitude": 51.6557,
    "longitude": 16.089,
    "asn": "AS12741",
    "organisation": "Netia SA",
    "postal": "67-200",
    "calling_code": "48",
    "flag": "https://ipdata.co/flags/pl.png",
    "emoji_flag": "\ud83c\uddf5\ud83c\uddf1",
    "emoji_unicode": "U+1F1F5 U+1F1F1",
    "carrier": {
        "name": "Netia",
        "mcc": "260",
        "mnc": "07"
    },
    "languages": [
        {
            "name": "Polish",
            "native": "Polski"
        }
    ],
    "currency": {
        "name": "Polish Zloty",
        "code": "PLN",
        "symbol": "z\u0142",
        "native": "z\u0142",
        "plural": "Polish zlotys"
    },
    "time_zone": {
        "name": "Europe/Warsaw",
        "abbr": "CEST",
        "offset": "+0200",
        "is_dst": true,
        "current_time": "2018-08-29T15:34:23.518065+02:00"
    },
    "threat": {
        "is_tor": false,
        "is_proxy": false,
        "is_anonymous": false,
        "is_known_attacker": false,
        "is_known_abuser": false,
        "is_threat": false,
        "is_bogon": false
    },
}
person Jonathan    schedule 06.11.2017
comment
когда я запускаю приведенный выше код, я получаю сообщение об ошибке: `require': невозможно загрузить такой файл -- rest_client (LoadError).... Откуда я могу получить доступ к файлу rest_client - person tee; 24.06.2018

Гем geoip можно заменить новым гемом maxminddb. Он поддерживает новый формат базы данных MaxMind.

db = MaxMindDB.new('./GeoLite2-City.mmdb')
ret = db.lookup('74.125.225.224')

ret.found? # => true
ret.country.name # => 'United States'
ret.country.name('zh-CN') # => '美国'
ret.country.iso_code # => 'US'
ret.city.name(:fr) # => 'Mountain View'
ret.subdivisions.most_specific.name # => 'California'
ret.location.latitude # => -122.0574
person Pioz    schedule 22.03.2019