Как я могу проверить, существует ли 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