Вставка курса валюты в документ[РЕШЕНО]

Автор Alexcostariha, 17 апреля 2022, 19:40

0 Пользователи и 1 гость просматривают эту тему.

Alexcostariha

Добрый день!
Для работы с именованными диапазонами имеется ячей ка для имени "курс Евро" или "курс $". Потом эта ячейка используется для создания формулы в именованном диапазоне, например:
цена_рублей=курс_евро*ИМЯ(имя ячейки с ценой в евро).
Требуется вставить в ячейку для курса валюты значение по курсу ЦБР на текущий день.
Что мне известно: есть  APi от ЦБР ,  есть функция ВЕБСЛУЖБА для вставки URL адресов, есть SMF расширение , есть расширение на GITHUB. Из всего самое простое - ВЕБСЛУЖБА-но там надо как-то извлекать курсы нужных валют.
P.S. См. решение в ответе #11.

economist

#1
Самое простое - это UDF на языке python, причем без к-либо внешних библиотек. Но есть проблема - сайт cbr.ru c марта постоянно "падает" из-за DDoS-атак, поэтому лучше взять другой источник. Он возвращает как неудобный XML, так и более опрятный JSON, с курсами на сегодня и вчера (на самом деле на любую дату, и с кучей другой инфы). "Играть" с JSON питон тоже умеет из коробки,  так что будет что-то вроде:


import requests

def rate(valuta):
   return requests.get('https://www.cbr-xml-daily.ru/daily_json.js').json()['Valute'][valuta]['Value']

if __name__=='__main__': print(rate('USD'))


Нижняя конструкция if... - нужна только для отладки вне Либры, так что вся функция улеглась в одну строку. Лаконичность языка Python просто завораживает.

Куда это воткнуть? Самое простое - файл с py-скриптом положить:
- в папку \libreoffice\share\Scripts\python
- в сетевую библиотеку
- сохранить ее как oxt-расширение
- или внедрить в тело файла

А вызов функции листа в Calc можно вставить в тело UDF на Basic, на Форуме есть примеры с invoke() - вызовами. Возможно есть способ проще.
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

Alexcostariha

#2
Это сложно для меня. А нельзя что-то вроде такой формулы с Пикабу :
Цитировать==ФИЛЬТР.XML(ПОДСТАВИТЬ(ПОДСТАВИТЬ(ВЕБСЛУЖБА("https://www.cbr-xml-daily.ru/daily_eng_utf8.xml?date_req1="&ТЕКСТ(СЕГОДНЯ();"ДД.ММ.ГГГГ")&"&date_req2="&ТЕКСТ(СЕГОДНЯ();"ДД.ММ.ГГГГ")&"&VAL_NM_RQ=R01235");".";",");"=""1,0";"=""1.0");"//ValCurs//Record//Value")
На сайте ЦБР есть пояснение по новым API в связи атаками, они дают ссылки на разные файлы, например на
файл xml  в utf-8 - поскольку имею Линукс, это видимо для меня:
Цитироватьhttps://www.cbr-xml-daily.ru/daily_utf8.xml
Содержимое этого файла, поставляется в ячейку по формуле:
=ВЕБСЛУЖБА("https://www.cbr-xml-daily.ru/daily_utf8.xml")
Видимо какой-то функцией, как я понимаю это ФИЛЬТР.XML можно выделить значение для нужной валюты, например евро, так, чтобы для евро значение подставилось в ячейку.
Тогда при открытии докмента можно иметь  значение для евро на дату открытия документа и соответственно-по нему пересчитаются все соответствующие значения в рублях.
Пример:
=ФИЛЬТР.XML(ВЕБСЛУЖБА("https://www.cbr-xml-daily.ru/daily_utf8.xml");"//Value")
даёт значение курса австралийского доллара-он первый в списке. А мне нужно для евро . Нужно знать синтаксис XPath!

economist

Да уж куда проще-то? По шагам:

1) кладем rate.py из вложения (Форум не любит py-файлы) в /share/Scripts/python

2) в ods-файле в модуль Standard добавляете функцию:


Function RATE_VAL(valuta As string) As double
script = "rate.py"
script = createUnoService("com.sun.star.script.provider.MasterScriptProviderFactory").createScriptProvider("")._
getScript("vnd.sun.star.script:" & script & "$rate?language=Python&location=share")
RATE_VAL = script.invoke(array(valuta), array(), array())
End Function


3) в листе вызываете функцию =RATE_VAL("EUR") для сегодняшнего курса EUR или др. нужной валюты
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

Alexcostariha

1) файл JSON действительно более аккуратный-во всяком случае в браузере.
2) вы пишете скрипт для доллара:
Цитироватьif __name__=='__main__': print(rate('USD'))
В то же время пример для скрипта приводите для евро:
Цитироватьв листе вызываете функцию =RATE_VAL("EUR")
Это совместимо?
3) Для вас просто
Цитировать) в ods-файле в модуль Standard добавляете функцию:
Я пока лишь понял, что нужно создать макрос.
4)
Цитироватькладем rate.py из вложения  в /share/Scripts/python
В Линуксе как я понимаю, это путь к домашней папке с Libreoffice, в которой нет папки share и выглядит он иначе:
~/.config/libreoffice/4/user/

economist

#5
Цитата: Alexcostariha от 18 апреля 2022, 18:11if __name__=='__main__': print(rate('USD'))

Скрипт из #1 вернет курс любой валюты, которая рейтится в ЦБ РФ.

Строка if __name__=='__main__': print(rate('USD')) - нужна только для отладки скрипта вне OpenOffice|LibreOffice, например в любой IDE (в OpenOffice|LibreOffice IDE есть, но не для python). Без этой строки скрипт в IDE просто загрузит в память функцию, но ничего не выведет. Эту строку можно вообще удалить.

В Линуксе д.б. аналог share/Scripts/python, мне не на чем проверить. Поместите rate.py в ~/.config/libreoffice/4/user/ и проверьте, работает ли функция.

Про библиотеку Standard внутри ODS-файла. Нажмите в LO Alt+F11, выделите слева документ, Создать - Модуль, создастся пустой макрос Sub Main(). Вот вместо него и вставьте функцию Function RATE_VAL()...End function. Должно заработать.
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

eeigor

Цитата: economist от 18 апреля 2022, 20:08Строка if __name__=='__main__': print(rate('USD')) - нужна только для отладки скрипта вне...
Вообще-то, дословно это означает, что если функция rate() вызывается из модуля, в котором она определена, то тогда надо выполнить этот самый код. А если вызов осуществляется извне после импорта этого модуля, то ничего выполнять не надо. Так и есть: для удобства отладки на месте.
Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community

Alexcostariha

#7
1) Путь для файла со скриптом согласно документации для домашней директории:
Цитировать~/.config/libreoffice/4/user/Scripts/python
Вопрос-нужно ли делать файл исполняемым?
2) Ошибка-см. вложенный файл.
3) Нашёл  т.н. путь "для всех пользователей" - на всю систему:
Цитировать/usr/lib/libreoffice/share/Scripts/python
Ошибка та же.

economist

#8
Ошибка говорит о том что скрипт Либра не нашла. Перепишите строку script = ... без символа переноса строки _

Перейдите в консоли в /usr/lib/libreoffice/share/Scripts/python и выполните rate.py - должен выйти курс USD вида 80.0437

Какой у вас дистр Linux? Команда python3 запускает или "системный" python, или тот что идет с LO. Зависит это от переменных окружения, текущей папки и/или наличия ключа -m? т.е. python3 -m или просто python3

Определить путь запущенного с rate.py питона можно, если выполнить 3 команды в консоли:

python3
import sys
sys.executable

Вечером сам попробую под Ubuntu.
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

Alexcostariha

Linux Mint 20.3 Una Cinnamon; основана на UBUNTU 20.04 focal.
python3 => /usr/bin/python3
$ sudo ./rate.py
./rate.py: 1: import: not found
: not found2:
./rate.py: 3: Syntax error: "(" unexpected

economist

В обеих локациях Ubuntu 21.10 ARM

~/.config/libreoffice/4/user/Scripts/python

/usr/lib/libreoffice/share/Scripts/python

- команда python3 rate.py отработала в консоли правильно, т.е. нужно ТС понять почему у него #9.

Но при вызове UDF в Calc - у меня такая же ошибка, как и у ТС в #7. Разбираться дальше не буду, у меня ДР :-)
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

Alexcostariha

#11
 Поигрался с сайтом XPath Tester пытаясь разобраться с синтаксисом  для XPATH, поскольку XPath нужен для извлечения содержимого xml документа в формуле вида:
=ФИЛЬТР.XML(ВЕБСЛУЖБА("http://www.cbr.ru/scripts/XML_daily.asp");"//Value")
Здесь Xpath вставляется в то, что идёт после точки с запятой.
На сайте XPath Tester можно загнать с сайта ЦБР файл XML_daily.asp в формате xml  
и прописывать команды для XPATH с проверкой того, что получится.
Содержимое файла содержит курсы валют на сегодняшнюю дату, что мне достаточно, и представляет из себя при загрузке на этот сайт одну длинную строку;
точно такой же вид у этой строки в ячейке Libreoffice по формуле ВЕБСЛУЖБА:
Цитировать<ValCurs Date="20.04.2022" name="Foreign Currency Market"><Valute ID="R01010"><NumCode>036</NumCode><CharCode>AUD</CharCode><Nominal>1</Nominal><Name>������������� ������</Name><Value>58,2679</Value></Valute><Valute ID="R01020A"><NumCode>944</NumCode><CharCode>AZN</CharCode><Nominal>1</Nominal><Name>��������������� �����</Name><Value>46,4875</Value></Valute><Valute ID="R01035"><NumCode>826</NumCode><CharCode>GBP</CharCode><Nominal>1</Nominal><Name>���� ���������� ������������ �����������</Name><Value>103,1166</Value></Valute><Valute ID="R01060"><NumCode>051</NumCode><CharCode>.....
Совершенно случайно я обнаружил, что если выделить на этом сайте в файле нужное место, то в заголовке для формул XPath САМА появляется формула XPath для этого места, а в месте для значений-результат выполнения формулы. Причём если мы выделим значение для курса скажем, доллара 80,9436 не целиком, а до или после запятой двойным щелчком мыши-то этого достаточно для получения нужной формулы XPath для курса доллара.
Таким образом для получения в документе Libreoffice курса:
1) доллара в нужной вам ячейке, становимся в эту ячейку и в ней пишем:
=ФИЛЬТР.XML(ВЕБСЛУЖБА("http://www.cbr.ru/scripts/XML_daily.asp");"/ValCurs/Valute[11]/Value[1]/text()")
2) евро в нужной вам ячейке, становимся в эту ячейку и в ней пишем:
=ФИЛЬТР.XML(ВЕБСЛУЖБА("http://www.cbr.ru/scripts/XML_daily.asp");"/ValCurs/Valute[12]/Value[1]/text()")
3) юаня в нужной вам ячейке, становимся в эту ячейку и в ней пишем:
=ФИЛЬТР.XML(ВЕБСЛУЖБА("http://www.cbr.ru/scripts/XML_daily.asp");"/ValCurs/Valute[17]/Value[1]/text()")
Если после того, как вы внесли эту запись в ячейку, у вас появляется сообщение об ошибке вам нужно просто связаться с сервером, для этого выполняем
В меню: Файл→Перезагрузить
или просто закрыть и открыть заново ваш документ и нажать в верхней панели окна программы кнопку "Разрешить обновление".
Можно ли пользоваться автоматическим обновлением -не знаю и как это включается - не ведаю.
Примечание. Почему-то файл daily_utf8.xml со страницы с описанием API для ЦБР застрял на дате 16.04.2022 г. , но рабочим оказался файл  XML_daily.asp.  P.S. На 21.04.22 - они одинаковы- может какой-то сбой, может что ещё, нужно понаблюдать. При замене ссылки для функции ВЕБСЛУЖБА на одну из этих страниц формула для XPath не меняется и выдаёт одинаковый ответ.


economist

#12
В любом случае python-решение под Linux существует, мы с ТС его просто не "дожали". Скорее всего надо доустановить к-л. пакет и ошибка уйдет. Linux-туса малочисленна и немногословна (в числителе), а в знаменателе - зоопарк Lin-дистров, умноженный на версии ОС, типа 16...21, а само по себе консольное красноглазание преодоление трудностей - не располагает к делению опытом, даже просто скопировать консольный вывод не всегда возможно.

Радует что все трудности точно преодолимы, но "Крута горка - да забывчива"... Я и сам грешен, ничего не записываю, хотя Linux использую постоянно, для студийной звукозаписи.

Какие еще могут быть python-варианты, помимо UDF-функции в Calc, оборачивающий python-функцию:

1) целевой подход: раз скрипт rate.py работает в Linux и выводит нужное, можно вывод std.out прочитать и вернуть в ячейку. Непонятно правда зачем формулой считывать одно и то же значение тысячи раз в сутки, топя льды Антарктики. Пример: https://stackoverflow.com/questions/46566741/run-python-code-inside-libreoffice

2) предметный подход: учитывая что курс валюты нужно вычислять раз в сутки - можно запускать скрипт только раз в день, при первом старте таблицы. Скрипт запишет курс(ы) валют в TXT-файл на сетевой шаре, откуда его будет легко макросом считать в константу, поле документа итд. Это уменьшит число web-запросов до одного. Если нужен пример - напишу. В Питон запись в файл - пара строк кода, в BASIC - десяток на чтение.
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...