Проверка доступности сайта с помощью Golang
Проверка доступности сайта, используя Golang.
Al-Sher
Всем привет. Уже давно я пытаюсь изучить Golang, ну вот и решил написать небольшую программу для автоматической проверки сайтов из списка.
Внимание!Использование ПО разрешается лишь с вашем собственным сайтом!
Весь код программы на GitHub
Подготовка.
Для начала необходимо установить Golang. Думаю это не вызовет проблем, достаточно скачать инсталятор с официального сайта и запустить его. Но, если вдруг, это вызвало сложности, то можно почитать инструкцию. В программе используются лишь стандартные пакеты, поэтому всё должно работать и без установки доп. пакетов.
Код.
Вся программа поделена 4 функции:
- main - основная функция, выполняющаяся при запуске программы;
- getSitesFromFile - функция для поиска ссылок в файле. Все ссылки храним в оперативной памяти;
- getParamsFromArgs - функция для получения дополнительных параметров;
- testSite - функция для проверки доступности сайта.
Итак, начнем с сначала. А в начале нам необходимо объявить название пакета. Так как мы пишем приложение, то название пакета должно быть main:
package main
Далее импортируем необходимые пакеты и объявляем наши переменные:
import (
"net/http"
"net/url"
"fmt"
"io/ioutil"
"os"
"strings"
"time"
"strconv"
)
var timer int = 1
var proxy string = ""
Не буду вдаваться в подробности данных пакетов. А вот переменные... Переменная timer предназначена для установки таймера. То есть время, спустя которое программа заходит на сайт. По-умолчанию стоит 1. Переменная proxy предназначена для работы приложения через прокси. Позволит проверять внутренние ресурсы.
Ну и затроним еще функцию main, то есть нашу главную функцию:
func main() {
sites := getSitesFromFile("sites.txt")
getParamsFromArgs()
if timer > 1 {
fmt.Println("use timer: ", timer)
}
if proxy != "" {
fmt.Println("use proxy: ", proxy)
}
ch := make(chan byte, 1)
for _, site := range sites {
go func (site string) {
for {
testSite(site)
time.Sleep(time.Duration(timer) * time.Second)
}
ch
Итак, мы объявили функцию. В переменную sites мы сохраняем все необходимые нам дя проверки сайты, которые лежат в файле sites.txt:
sites := getSitesFromFile("sites.txt")
Далее мы вызываем вспомогательную функцию getParamsFromArgs:
getParamsFromArgs()
Если время таймера больше 1, то мы используем не стандартное время, а значит передали программе время таймера. Время, кстати, в секундах, но об этом позже. Так же проверяем использование прокси:
if timer > 1 {
fmt.Println("use timer: ", timer)
}
if proxy != "" {
fmt.Println("use proxy: ", proxy)
}
Так же создаем канал ch для того, чтобы процесс main не завершался. Это позволит выводить сообщения в консоль:
ch := make(chan byte, 1)
Итак, проходимся по массиву наших сайтов. В переменной site хранится один адрес:
for _, site := range sites {
Реализуем многопоточность благодаря вызову анонимной функции через go. В эту функцию передаем значение переменной site:
go func (site string) {
В данной функции мы осуществляем бесконечный цикл. По завершению мы передаем очереди, что всё готово. Так же именно тут вызывается функция testSite, которой мы передаем адрес сайта. А еще можно заметить и наш таймер:
for {
testSite(site)
time.Sleep(time.Duration(timer) * time.Second)
}
После каждого выполнения testSite мы отправляем поток в "сон" на определенное время. Именно тут и указано, что мы используем секунды, благодаря умножению на time.Second:
time.Duration(timer) * time.Second
Далее мы используем наш канал ch, передавая в него единицу:
ch <- 1
Вызываем нашу анонимную функцию с параметром site:
}(site)
Выбрасываем в пустоту значение канала ch:
<- ch
Функция getSitesFromFile.
Далее мы рассматриваем getSitesFromFile, то есть получение сайтов из файла:
func getSitesFromFile(namefile string) []string {
data, err := ioutil.ReadFile(namefile)
if err != nil {
fmt.Println("error: ", err)
os.Exit(2)
}
result := string(data)
test := strings.Split(result, "\r\n")
return test
}
В ней мы передаем название нашего файла и указываем, что вернется массив строк:
func getSitesFromFile(namefile string) []string {
Далее мы загружаем содержимое файла в переменную data, а так же ошибку в err:
data, err := ioutil.ReadFile(namefile)
Проверяем на ошибки:
if err != nil {
fmt.Println("error: ", err)
os.Exit(2)
}
Если есть ошибки, то выводим ошибку и завершаем программу. Далее переводим содержимое файла из байт в строку:
result := string(data)
Разделяем строку по символам \r\n, то есть по пропуску строки:
test := strings.Split(result, "\r\n")
И возвращаем результат:
return test
Функция getParamsFromArgs.
Как я говорил, мы принимаем дополнительные параметры из командой строки. Вот эта функция:
func getParamsFromArgs() {
if len(os.Args) > 1 {
for i, _ := range os.Args {
if os.Args[i] == "proxy" {
i++
proxy = os.Args[i]
}
if os.Args[i] == "timer" {
i++
timer, _ = strconv.Atoi(os.Args[i])
}
}
}
}
В ней мы проверяем содержимое аргументов os.Args:
if len(os.Args) > 1 {
Первый элемент всегда название исполняемого файла, поэтому используем проверку на больше 1. Далее проходимся циклом по данным аргументам:
for i, _ := range os.Args {
Если находим необходимые нам параметры, то следующий параметр записываем в нужные места. Легко можно расширить возможности...
Функция testSite.
И вот мы дошли до самой интересной функции - testSite:
func testSite(u string) bool {
if u == "" {
return false
}
client := http.Client{}
if proxy != "" {
proxyUrl, _ := url.Parse(proxy)
client = http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(proxyUrl)}}
}
req, _ := http.NewRequest("GET", u, nil)
req.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT x.y; Win64; x64; rv:10.0) Gecko/20100101 Firefox/10.0")
resp, err := client.Do(req)
if err != nil {
fmt.Println("error: ", err)
return false
}
_, err := ioutil.ReadAll(resp.Body)
if err == nil {
if resp.StatusCode == 200 {
fmt.Println(u + ": " + "ok")
} else {
fmt.Println("Site ", u, " returned error code: ", resp.StatusCode)
}
}
defer resp.Body.Close()
return true
}
Мы передаем данной функции необходимый url адес. Сама функция возвращает bool'евое значение:
func testSite(u string) bool {
Проверяем не пустой ли url адрес:
if u == "" {
return false
}
Создаем http клиента:
client := http.Client{}
Проверяем прокси. Если он имеется, то настраиваем наш клиент:
if proxy != "" {
proxyUrl, _ := url.Parse(proxy)
client = http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(proxyUrl)}}
}
Создаем переменную Request. Она будет содержать все необходимые параметры, передаваемые клиенту, в том числе и метод, и url адрес:
req, _ := http.NewRequest("GET", u, nil)
Задаем заголовок браузера:
req.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT x.y; Win64; x64; rv:10.0) Gecko/20100101 Firefox/10.0")
И исполняем запрос клиентом:
resp, err := client.Do(req)
Функция вернет нам ответ сервера(resp) и ошибку(err). Проверяем на наличие ошибки:
if err != nil {
fmt.Println("error: ", err)
return false
}
Проверяем ошибки чтения из Body:
_, err := ioutil.ReadAll(resp.Body)
if err == nil {
Если ошибок нет, то проверяем статус ответа:
if resp.StatusCode == 200 {
fmt.Println(u + ": " + "ok")
} else {
fmt.Println("Site ", u, " returned error code: ", resp.StatusCode)
}
Закрываем Body после того, как он нам не нужен:
defer resp.Body.Close()
И возвращаем true:
return true
Заключение.
Вот вам простенькая программа для проверки ваших сайтов на доступность, которую можно собрать как под linux, так и под windows :) Спасибо за внимание, надеюсь она послужит для достойных целей!