Предисловие: в июле 2024 года я закончил обучение в университете, стал инженером-энергетиком и попал на завод. Одной из моих задач было контролирование потребляемой мощности предприятием. При превышении значения N необходимо трубить в группу в Viber и просить, чтобы пока не включали энергоемкое оборудование, а также раз в полчаса писать текущую трехминутную мощность. Так как 99% рабочего дня я на месте не сижу, такой контроль затруднителен. Контроль мощности осуществляется через старенькую АСКУЭ с минимальным функционалом. Поэтому спустя месяц работы было принято решение упросить процесс контроля.
Вводные: 1) Старенькая АСКУЭ, открывающаяся только через IE, единственная функциональность которой — опрос коммерческих счетчиков и небольшие расчеты. 2) Желание упростить себе жизнь.
Первым делом необходимо было определиться с языком программирования. Выбор пал на Python. Причин несколько: есть небольшой опыт, простота языка, большое количество готовых библиотек.
Для получения значения мощности был выбран самый простой вариант — телеграм-бот. Значения из АСКУЭ выдираются простым парсингом. Для бота была выбрана библиотека TeleBot, для парсинга — BeautifulSoup.
Разбор кода
Первоначально необходимо произвести авторизацию бота. Для этого необходимо произвести получение токена. Процесс получения токена можно посмотреть, например, тут. После этого необходимо создать объект для работы с ботом.
bot = telebot.TeleBot("------Telegram Token----------")
После этого можно переходить к непосредственному описанию сценариев для бота. Первоначально необходимо создать стартовую функцию, которая будет вызываться при первом запуске бота и которая позволит добавить некоторые интерактивные элементы.
@bot.message_handler(commands=['start'])
def start(message):
markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
btn1 = types.KeyboardButton("Узнать мощность завода")
btn2 = types.KeyboardButton('Отбито с 08:00 до 11:00')
markup.add(btn1)
markup.add(btn2)
bot.send_message(message.chat.id, text="Привет, {0.first_name}!".format(
message.from_user), reply_markup=markup)
Здесь мы определяем, что функция вызывает при помощи введении команды «/start» (1 строка), добавляем две кнопки btn1 «Узнать мощность завода» для получения последних 3-минутных мощностей и btn2 «Отбито с 08:00 до 11:00» для определения максимальной получасовой нагрузки в утренний пик, а также приветственной сообщение (последняя строка).
После создания интерактивных элементов можно переходить к основным функциям. Сначала необходимо создать функции для парсинга страницы с 3-минутными мощностями . Определить шаблон париснга можно при помощи инструмента разработчика, встроенного в браузер. Подробно останавливаться на описании процессе парсинга я не буду , так как здесь все довольно индивидуально. Сначало немного расскажу о функции получения 3-минутных мощностей.
Сначала определим текущую дату для встраивания ее в ссылку запроса:
date1 = str(datetime.datetime.now().day)+'.' + \
str(datetime.datetime.now().month) + \
'.'+str(datetime.datetime.now().year)
Определение временных параметров для встраивания в запрос:
hr1 = str(datetime.datetime.now().hour+1) if datetime.datetime.now().hour + \
1 >= 10 else "0"+str(datetime.datetime.now().hour+1)
Далее параметры, полученные выше, вставляем в запрос, устаналиваем заголовки для запроса, делаем запрос на сервер АСКУЭ и получаем веб-страницу для парсинга:
url = "http://IP_ASKUE/arm/3min_p.php?tab=0&dc="+date1+"+"+hr1 + \
"%3A30&disp=120&iname=%E2%E2%EE%E4%E0-%F1%F3%E1.-%F1%F2%EE%EB%EE%E2%E0%FF+&id=48&pid=34&lid=3&node=1&nobj=1001&adr=1004&frameName=3min_p"
headers = {"User-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36"}
response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.text, 'html.parser')
После этого можно переходить к непосредственному парсингу по элементам веб-страницы. Полный текст функции:
def askue_req():
date1 = str(datetime.datetime.now().day)+'.' + \
str(datetime.datetime.now().month) + \
'.'+str(datetime.datetime.now().year)
hr1 = str(datetime.datetime.now().hour+1) if datetime.datetime.now().hour + \
1 >= 10 else "0"+str(datetime.datetime.now().hour+1)
url = "http://IP_ASKUE/arm/3min_p.php?tab=0&dc="+date1+"+"+hr1 + \
"%3A30&disp=120&iname=%E2%E2%EE%E4%E0-%F1%F3%E1.-%F1%F2%EE%EB%EE%E2%E0%FF+&id=48&pid=34&lid=3&node=1&nobj=1001&adr=1004&frameName=3min_p"
headers = {
"User-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36"
}
response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.text, 'html.parser')
table = soup.find_all('table')[3]
time = [table.find_all('tr')[8].find_all('td')[1].text, table.find_all('tr')[7].find_all('td')[
1].text, table.find_all('tr')[6].find_all('td')[1].text, table.find_all('tr')[5].find_all('td')[1].text]
P = [table.find_all('tr')[8].find_all('td')[2].text, table.find_all('tr')[7].find_all('td')[
2].text, table.find_all('tr')[6].find_all('td')[2].text, table.find_all('tr')[5].find_all('td')[2].text]
return P, time
Аналогично определяется функция для получения получасовых утренних пиков:
def pik():
date1 = str(datetime.datetime.now().day)+'.' + \
str(datetime.datetime.now().month) + \
'.'+str(datetime.datetime.now().year)
url = "http://IP_ASKUE/arm/form1.php?tab=1&disp=1&maxp=0&dc="+date1 + \
"&iname=%E2%E2%EE%E4%E0-%F1%F3%E1.-%F1%F2%EE%EB%EE%E2%E0%FF+&id=48&pid=34&lid=3&node=1&nobj=1001&adr=1004&frameName=form1"
headers = {
"User-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36"
}
response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.text, 'html.parser')
P_p = soup.find_all('tr', attrs={'bgcolor': 'salmon'})[
1].find_all('td')[1].text
time_p = soup.find_all('tr', attrs={'bgcolor': 'salmon'})[
0].find_all('td')[1].text
return P_p, time_p
На этом первая часть подходит к концу. В следующей и заверщающей части я покажу непосредственное определение функций для общения с телеграм-ботом.