- Информация о материале
- Автор: JediG
- Категория: Web, Python, Ubuntu, Joomla, Virtuemart
- Просмотров: 24
import logging
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
def fetch_page(url):
try:
response = requests.get(url, timeout=10) # Устанавливаем таймаут 10 секунд
response.raise_for_status() # Проверяем, что запрос успешен
return response.text
except requests.exceptions.RequestException as e:
logger.error(f"Ошибка при запросе страницы: {e}")
return None
def get_headers(html):
soup = BeautifulSoup(html, "html.parser")
headers = soup.find_all("h1") # Ищем все заголовки h1
for header in headers:
print(header.text.strip()) # Выводим текст заголовка
return bool(headers) # Возвращаем True, если заголовки найдены
def main():
url = "https://jedig.ru"
html = fetch_page(url)
if html:
if get_headers(html):
logger.info("Заголовки успешно извлечены и выведены")
else:
logger.error("Не удалось извлечь заголовки")
else:
logger.error("Не удалось загрузить страницу")
if __name__ == "__main__":
main()
- Информация о материале
- Автор: JediG
- Категория: Web, Python, Ubuntu, Joomla, Virtuemart
- Просмотров: 22
Модуль SeleniumWebNavigator
Модуль SeleniumWebNavigator предоставляет удобный интерфейс для работы с интернет-реквестами и парсингом страниц сайтов с использованием Selenium WebDriver. Этот модуль позволяет ботам подключаться к интернету и извлекать необходимую информацию без необходимости дублирования кода в каждом из них.
Основные функции
- Инициализация WebDriver для управления браузером Firefox.
- Поддержка режима без головы (headless) для невидимого выполнения скрипта.
- Навигация по указанным URL-адресам.
- Ожидание загрузки определенных элементов на странице.
- Закрытие браузера по завершении работы.
Пример использования
from SeleniumWebNavigator import SeleniumWebNavigator navigator = SeleniumWebNavigator() url = "https://example.com" if navigator.navigate_to_url(url): element = navigator.wait_for_element(By.TAG_NAME, "h1") if element: print(element.text) navigator.quit()
Структура проекта
Модуль SeleniumWebNavigator можно разместить в отдельном файле SeleniumWebNavigator.py
, который используется в других проектах или ботах:
/ваш_проект │ ├── main.py # Ваш главный скрипт или бот ├── SeleniumWebNavigator.py # Модуль для работы с интернетом через Selenium └── /другие_файлы_и_папки_проекта
Код SeleniumWebNavigator.py:
import logging
import os
import time
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.firefox.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import WebDriverException, TimeoutException
logger = logging.getLogger(__name__)
class SeleniumWebNavigator:
def __init__(self, geckodriver_path="/usr/bin/geckodriver", headless=True, timeout=180):
self.geckodriver_path = geckodriver_path
self.headless = headless
self.timeout = timeout
self.driver = self._init_driver()
def _init_driver(self):
if not os.path.exists(self.geckodriver_path):
logger.error(f"Geckodriver не найден по пути: {self.geckodriver_path}")
return None
options = Options()
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
if self.headless:
options.add_argument("--headless")
service = Service(executable_path=self.geckodriver_path)
try:
driver = webdriver.Firefox(service=service, options=options)
driver.set_page_load_timeout(self.timeout)
logger.info("WebDriver успешно запущен")
return driver
except Exception as e:
logger.error(f"Ошибка запуска WebDriver: {e}")
return None
def navigate_to_url(self, url):
if not self.driver:
logger.error("WebDriver не инициализирован")
return False
try:
self.driver.get(url)
logger.info(f"Навигация к {url} успешна")
return True
except (WebDriverException, TimeoutException) as e:
logger.error(f"Ошибка навигации на {url}: {e}")
return False
def wait_for_element(self, by, value, wait_time=10):
if not self.driver:
logger.error("WebDriver не инициализирован")
return None
try:
element = WebDriverWait(self.driver, wait_time).until(
EC.presence_of_element_located((by, value))
)
logger.info(f"Элемент {value} найден")
return element
except TimeoutException:
logger.error(f"Элемент {value} не найден в течение {wait_time} секунд")
return None
def quit(self):
if self.driver:
self.driver.quit()
logger.info("WebDriver закрыт")
# Пример использования
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
navigator = SeleniumWebNavigator()
url = "https://example.com"
if navigator.navigate_to_url(url):
element = navigator.wait_for_element(By.TAG_NAME, "h1")
if element:
print(element.text)
navigator.quit()
- Информация о материале
- Автор: JediG
- Категория: Web, Python, Ubuntu, Joomla, Virtuemart
- Просмотров: 27
Многообразие программ и способов выхода
В мире Linux и Unix-подобных систем действительно существует множество программ, и каждая из них может иметь свои уникальные способы взаимодействия и выхода. Это может быть как преимуществом (гибкость и мощь), так и сложностью (нужно помнить много разных команд и сочетаний клавиш). 😊
Немного юмора и фактов:
less
: Выход —q
.vim
: Выход —Esc
, затем:q!
(если не хотите сохранять изменения).nano
: Выход —Ctrl + X
.man
: Выход —q
(по сути, это тожеless
).psql
: Выход —\q
.top
илиhtop
: Выход —q
.tmux
: Выход —Ctrl + B
, затемd
(detach), илиexit
для завершения сессии.screen
: Выход —Ctrl + A
, затемd
(detach), илиexit
для завершения сессии.mysql
: Выход —exit
или\q
.python
(интерактивная оболочка): Выход —exit()
илиCtrl + D
.
Почему так много разных способов?
- Исторические причины: Многие программы разрабатывались разными людьми в разное время, и у каждого были свои предпочтения.
- Разные задачи: Например, текстовые редакторы (
vim
,nano
) и интерактивные оболочки (psql
,mysql
) решают разные задачи, поэтому их интерфейсы отличаются. - Гибкость: Linux даёт пользователям свободу выбора. Если вам не нравится одна программа, вы можете использовать другую.
Как не запутаться?
- Используйте
--help
илиman
: Почти все программы поддерживают справку. Например:psql --help man less
- Запоминайте часто используемые команды: Со временем вы привыкнете к тем программам, которые используете чаще всего.
- Создайте шпаргалку: Запишите команды выхода для программ, которые используете чаще всего.
- Используйте
Ctrl + C
: Это универсальный способ прервать выполнение большинства программ.
Итог
Многообразие программ и способов выхода — это часть философии Linux. Со временем вы привыкнете к этому, и это станет вашей второй натурой. А пока — держите под рукой шпаргалку и не бойтесь экспериментировать! 🚀
- Информация о материале
- Автор: JediG
- Категория: Web, Python, Ubuntu, Joomla, Virtuemart
- Просмотров: 23
Шаг 1: Подготовка базы данных
Убедитесь, что у вас есть таблица sukko_virtuemart_apartment_availabilities
с данными о занятости квартир. Структура таблицы должна быть такой:
CREATE TABLE sukko_virtuemart_apartment_availabilities (
id INT PRIMARY KEY AUTO_INCREMENT,
apartment_id INT NOT NULL,
dtstart DATETIME NOT NULL,
dtend DATETIME NOT NULL,
event_id VARCHAR(255),
status VARCHAR(50) DEFAULT 'confirmed',
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Шаг 2: Создание плагина для VirtueMart
- Создайте папку для плагина:
- Перейдите в папку
plugins/vmcustom/
вашего сайта на Joomla. - Создайте новую папку, например,
availabilityfilter
.
- Перейдите в папку
- Создайте файл плагина:
- Внутри папки
availabilityfilter
создайте файлavailabilityfilter.php
. - Вставьте следующий код:
<?php defined('_JEXEC') or die; use Joomla\CMS\Factory; use Joomla\CMS\Plugin\CMSPlugin; class plgVmCustomAvailabilityFilter extends CMSPlugin { public function __construct(&$subject, $config) { parent::__construct($subject, $config); } public function onVmSearchFilter(&$filters, &$params) { // Получаем даты из запроса $app = Factory::getApplication(); $input = $app->input; $dtstart = $input->getString('dtstart', ''); $dtend = $input->getString('dtend', ''); if (empty($dtstart) || empty($dtend)) { return; } // Подключаемся к базе данных $db = Factory::getDbo(); $query = $db->getQuery(true); // Находим занятые квартиры $query->select('DISTINCT apartment_id') ->from($db->quoteName('sukko_virtuemart_apartment_availabilities')) ->where($db->quoteName('dtstart') . ' <= ' . $db->quote($dtend)) ->where($db->quoteName('dtend') . ' >= ' . $db->quote($dtstart)); $db->setQuery($query); $occupiedApartments = $db->loadColumn(); // Исключаем занятые квартиры из списка if (!empty($occupiedApartments)) { $filters[] = $db->quoteName('virtuemart_product_id') . ' NOT IN (' . implode(',', $occupiedApartments) . ')'; } } }
- Внутри папки
- Создайте XML-файл для плагина:
- В той же папке создайте файл
availabilityfilter.xml
. - Вставьте следующий код:
<?xml version="1.0" encoding="utf-8"?> <extension type="plugin" version="5.0" method="upgrade" group="vmcustom"> <name>Availability Filter</name> <author>Your Name</author> <creationDate>2023-10-01</creationDate> <version>1.0</version> <description>Фильтр для подбора квартир по датам заезда и выезда.</description> <files> <filename plugin="availabilityfilter">availabilityfilter.php</filename> </files> </extension>
- В той же папке создайте файл
Шаг 3: Установка плагина
- Заархивируйте папку
availabilityfilter
в ZIP-файл. - Перейдите в админку Joomla: Расширения → Управление → Установка.
- Загрузите ZIP-файл и установите плагин.
- После установки перейдите в Расширения → Плагины, найдите плагин
Availability Filter
и включите его.
Шаг 4: Добавление формы для фильтра
- Откройте шаблон VirtueMart, который используется на вашем сайте (например,
components/com_virtuemart/templates/default/templates.php
). - Добавьте форму для ввода даты заезда и выезда:
<form action="<?php echo JRoute::_('index.php?option=com_virtuemart&view=category'); ?>" method="get"> <input type="hidden" name="option" value="com_virtuemart"> <input type="hidden" name="view" value="category"> <label for="dtstart">Дата заезда:</label> <input type="date" name="dtstart" id="dtstart" required> <label for="dtend">Дата выезда:</label> <input type="date" name="dtend" id="dtend" required> <button type="submit">Найти</button> </form>
Шаг 5: Тестирование
- Перейдите на страницу категории VirtueMart.
- Введите дату заезда и дату выезда в форму.
- Нажмите "Найти".
- Убедитесь, что отображаются только те квартиры, которые свободны в указанный период.
Шаг 6: Дополнительные улучшения
- Кэширование: Добавьте кэширование результатов фильтрации для повышения производительности.
- Валидация дат: Убедитесь, что дата выезда больше даты заезда.
- Обработка ошибок: Добавьте сообщения об ошибках, если данные введены некорректно.
Пример SQL-запроса для фильтрации
Если пользователь ввел дату заезда 2023-10-01
и дату выезда 2023-10-10
, запрос будет выглядеть так:
SELECT DISTINCT apartment_id
FROM sukko_virtuemart_apartment_availabilities
WHERE (
(dtstart <= '2023-10-10' AND dtend >= '2023-10-01')
OR
(dtstart BETWEEN '2023-10-01' AND '2023-10-10')
OR
(dtend BETWEEN '2023-10-01' AND '2023-10-10')
)
Этот запрос вернет все apartment_id
, которые заняты в указанный период. Затем мы исключим их из списка товаров.
- Информация о материале
- Автор: JediG
- Категория: Web, Python, Ubuntu, Joomla, Virtuemart
- Просмотров: 22
Что будет, если бот, запущенный с помощью systemd, завершится с ошибкой?
Если бот, запущенный с помощью systemd
, завершится с ошибкой, то дальнейшее поведение зависит от конфигурации юнита systemd
, который управляет этим ботом. В частности, важны параметры Restart=
и RestartSec=
в файле юнита.
Основные параметры, которые влияют на поведение:
1. Restart=
:
no
(по умолчанию) — система не будет перезапускать процесс после его завершения.on-success
— перезапуск только при успешном завершении (с кодом 0).on-failure
— перезапуск при завершении с ненулевым кодом возврата или при аварийном завершении (например, segfault).on-abnormal
— перезапуск при аварийном завершении (например, сигнал SIGSEGV).always
— перезапуск всегда, независимо от причины завершения.on-abort
— перезапуск только при аварийном завершении.
2. RestartSec=
:
- Указывает задержку перед перезапуском (например,
RestartSec=5s
для задержки в 5 секунд).
3. StartLimitInterval=
и StartLimitBurst=
:
- Эти параметры ограничивают количество перезапусков в определённый промежуток времени. Например, если указать
StartLimitInterval=60s
иStartLimitBurst=5
, тоsystemd
позволит не более 5 перезапусков за 60 секунд. Если лимит превышен,systemd
прекратит попытки перезапуска.
Пример конфигурации юнита:
[Unit]
Description=My Bot Service
After=network.target
[Service]
ExecStart=/usr/bin/python3 /path/to/bot.py
Restart=on-failure
RestartSec=5s
User=botuser
Group=botgroup
[Install]
WantedBy=multi-user.target
Что произойдёт:
- Если бот завершится с ошибкой, и в юните указано
Restart=on-failure
, тоsystemd
попытается перезапустить его через указанное вRestartSec
время. - Если перезапуски происходят слишком часто, и срабатывает ограничение
StartLimitInterval
/StartLimitBurst
,systemd
остановит попытки перезапуска и переведёт сервис в состояниеfailed
.
Как проверить статус сервиса:
systemctl status my-bot-service
Эта команда покажет текущее состояние сервиса, количество перезапусков и причину последнего завершения.
Как посмотреть логи:
Логи сервиса можно просмотреть с помощью journalctl
:
journalctl -u my-bot-service
Что делать, если сервис не перезапускается:
- Проверьте конфигурацию юнита (
/etc/systemd/system/my-bot-service.service
). - Убедитесь, что параметр
Restart=
настроен правильно. - Проверьте логи (
journalctl -u my-bot-service
) для диагностики ошибки. - Если проблема в коде бота, исправьте её и перезапустите сервис:
sudo systemctl restart my-bot-service
Таким образом, поведение системы зависит от настроек systemd
, и при правильной конфигурации бот может быть автоматически перезапущен после сбоя.