Как я могу проверить, существует ли URL с Ruby?
Например, для URL
https://google.com
результат должен быть правдивым, но для URL
https://no.such.domain
или
https://stackoverflow.com/no/such/path
результат должен быть ложным
Как я могу проверить, существует ли URL с Ruby?
Например, для URL
https://google.com
результат должен быть правдивым, но для URL
https://no.such.domain
или
https://stackoverflow.com/no/such/path
результат должен быть ложным
Используйте библиотеку Net:: HTTP.
require "net/http"
url = URI.parse("http://www.google.com/")
req = Net::HTTP.new(url.host, url.port)
res = req.request_head(url.path)
В этот момент res находится объект Net:: HTTPResponse, содержащий результат запроса. Затем вы можете проверить код ответа:
do_something_with_it(url) if res.code == "200"
Примечание. Чтобы проверить URL-адрес на основе https, атрибут use_ssl должен быть true как:
require "net/http"
url = URI.parse("https://www.google.com/")
req = Net::HTTP.new(url.host, url.port)
req.use_ssl = true
res = req.request_head(url.path)
Извините за поздний ответ на это, но я думаю, что это заслуживает лучшего ответа.
Есть три способа взглянуть на этот вопрос:
Пока 200 означает, что сервер отвечает на этот URL (таким образом, существует URL-адрес), ответ на другой код состояния не означает, что URL-адрес не существует. Например, ответ 302 - redirected означает, что URL-адрес существует и перенаправляется на другой. Во время просмотра 302 много раз ведет себя так же, как 200 для конечного пользователя. Другой код состояния, который может быть возвращен, если существует URL-адрес, равен 500 - internal server error. В конце концов, если URL-адрес не существует, как сервер приложений обрабатывает ваш запрос, вместо него просто возвращается 404 - not found?
Таким образом, на самом деле существует только два случая, когда URL-адрес не существует: когда сервер не существует или когда сервер существует, но не может найти данный URL-адрес, его не существует. Таким образом, единственный способ проверить, существует ли URL-адрес, проверяется, отвечает ли сервер, а код возврата - не 404. Следующий код делает именно это.
require "net/http"
def url_exist?(url_string)
url = URI.parse(url_string)
req = Net::HTTP.new(url.host, url.port)
req.use_ssl = (url.scheme == 'https')
path = url.path if url.path.present?
res = req.request_head(path || '/')
res.code != "404" # false if returns 404 - not found
rescue Errno::ENOENT
false # false if can't find the server
end
Однако в большинстве случаев нам неинтересно видеть, существует ли URL-адрес, но если мы можем получить к нему доступ. К счастью, глядя на коды состояния HTTP, это семейство 4xx, которое указывает на ошибку клиента (таким образом, ошибка на вашей стороне, что означает, что вы не запрашиваете страницу правильно, не имеете разрешения или вообще что-либо). Это полезно для ошибок, чтобы проверить, можете ли вы получить доступ к этой странице. Из wiki:
Класс кода класса 4xx предназначен для случаев, когда клиент, похоже, ошибся. За исключением случаев, когда он отвечает на запрос HEAD, сервер должен включать в себя объект, содержащий объяснение ситуации ошибки, и является ли это временным или постоянным условием. Эти коды состояния применимы к любому методу запроса. Пользовательские агенты должны отображать для пользователя какой-либо объект.
Итак, следующий код убедитесь, что URL существует, и вы можете получить к нему доступ:
require "net/http"
def url_exist?(url_string)
url = URI.parse(url_string)
req = Net::HTTP.new(url.host, url.port)
req.use_ssl = (url.scheme == 'https')
path = url.path if url.path.present?
res = req.request_head(path || '/')
if res.kind_of?(Net::HTTPRedirection)
url_exist?(res['location']) # Go after any redirect and make sure you can access the redirected URL
else
res.code[0] != "4" #false if http code starts with 4 - error on your side.
end
rescue Errno::ENOENT
false #false if can't find the server
end
Подобно тому, как семейство 4xx проверяет, можете ли вы получить доступ к URL-адресу, семейство 5xx проверяет, не возникла ли на сервере проблема с ответом на ваш запрос. Ошибка в этом семействе в большинстве случаев связана с проблемами на самом сервере, и, надеюсь, они работают над его решением. Если Вам нужно иметь доступ к странице и получить правильный ответ сейчас, вы должны убедиться, что ответ не из семейства 4xx или 5xx, и если вы были перенаправлены, перенаправленный правильные ответы на страницы. Подобно (2), вы можете просто использовать следующий код:
require "net/http"
def url_exist?(url_string)
url = URI.parse(url_string)
req = Net::HTTP.new(url.host, url.port)
req.use_ssl = (url.scheme == 'https')
path = url.path if url.path.present?
res = req.request_head(path || '/')
if res.kind_of?(Net::HTTPRedirection)
url_exist?(res['location']) # Go after any redirect and make sure you can access the redirected URL
else
! %W(4 5).include?(res.code[0]) # Not from 4xx or 5xx families
end
rescue Errno::ENOENT
false #false if can't find the server
end
Net::HTTP работает, но если вы можете работать за пределами stdlib, Faraday лучше.
Faraday.head(the_url).status == 200
(200 - это код успеха, предполагающий, что вы имели в виду "существует".)
Вы должны прочитать эту статью:
Ответ Симоны был очень полезен для меня.
Вот версия, которая возвращает true/false в зависимости от действительности URL-адреса и обрабатывает перенаправления:
require 'net/http'
require 'set'
def working_url?(url, max_redirects=6)
response = nil
seen = Set.new
loop do
url = URI.parse(url)
break if seen.include? url.to_s
break if seen.size > max_redirects
seen.add(url.to_s)
response = Net::HTTP.new(url.host, url.port).request_head(url.path)
if response.kind_of?(Net::HTTPRedirection)
url = response['location']
else
break
end
end
response.kind_of?(Net::HTTPSuccess) && url.to_s
end