Архив за месяц: Июль 2017

3 способа загрузки файла на сервер с помощью curl

Продемонстрируем curl запрос на примере, с учетом следующих ограничений.
1. Файл надо загрузить методом POST
2. Необходима авторизация
3. На сервере установлен сертификат ssl

Способ 1, командная строка: Загрузка файла непосредственно через командную строку выглядит так:

curl -i -u user:password -X POST --form datafile=@/path/to/some/file.txt https://localhost:443/page --insecure

Разберем подробнее:
-X — указываем метод POST
-u — логин и пароль пользователя
—insecure — при работе по https часто приходится тестировать в тестовом окружении где не стоит проверенный сертификат. Этой опцией отказываемся от проверки.
Чтобы ещё более подробно узнать о тонкостях команды, используйте curl —help

Способ 2, PHP: Продемонстрируем как загрузить файл

// очень полезно предварительно сделать проверку на наличие библиотеки curl для php
if  (!in_array  ('curl', get_loaded_extensions())) {
    exit("CURL is NOT installed on this server");
}

        $ch = curl_init();
        //указываем url адрес на сервере
        curl_setopt($ch, CURLOPT_URL, 'https://localhost:443/page');
        // чтобы возвращало
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        // указываем метод POST
        curl_setopt($ch, CURLOPT_POST, 1); 
        // этот параметр для указания логина и пароля
        curl_setopt($ch, CURLOPT_USERPWD, "login:password");
        curl_setopt($ch, CURLOPT_POSTFIELDS, [
                'some_more_data' => 'здесь можно передать дополнительные параметры, например если эмулируется отправка формы',
                'datafile' => curl_file_create('/path/to/file.txt' , mime_content_type($path_to_file), basename('/path/to/file'))
            ]
        );
        // проверка peer для ssl отключена, смотрите также CURLOPT_SSL_VERIFYHOST для полного игнорирования ssl сертификата
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); 
        // все опции выставлены - выполняем запрос
        $result = curl_exec($ch);
        // распечатываем ответ сервера
        var_dump($result); 
        // закрываем соединение
        curl_close($ch);

Практически всё прокомментировано в коде, однако отмечу функцию curl_file_create , один сервер постоянно ругался что файл как-то не так указан или отсутсвует. Это вылечилось добавлением мим типа, т.е. функция curl_file_create создает дополнительные заголовки для корректной отправки файла.

Способ 3, Python : Наконец дошли до python, здесь воспользуемя отличной библиотекой requests

import requests

    auth = ('user', 'password')
    data = [
        ('some_more_field', 'some_field_data')
    ]

    # curl request
    files = {'datafile': open('/path/to/file.txt', 'rb')}
    r = requests.post('https://localhost:443/page', files=files, data=data, auth=auth)
    print(r.text)

В указанном примере открываем файл в режиме бинарного чтения, и дальше сразу делаем запроc. В запросе указаны параметры авторизации, метод, страница и файл. Если файлов несколько — просто расширьте словарь files.
Всё просто, удачи с curl!

Генерация множественных числительных в согласовании с существительным на python

Суть задачи: написать функцию, на входе у которой число и существительное, на выходе сгенерированное числительное и существительное в правильном склонении.
Такая задача очень часто возникает например в финансовой сфере, так как на документах принято писать сумму помимо цифрой — ещё и прописью.

Алгоритм склонения множественно числа очень прост. Всего существует только три варианта для любого числа. Возьмём слово доллар, тогда
Вариант 1: именительный падеж, например один доллар, тридцать один доллар, много-много-один доллар. т.е. когда число оканчивается на 1
Вариант 2: Родительный падеж, например два доллара, тридцать три доллара, много-много-четыре доллара. т.е. когда число оканчивается на 2, 3 и 4
Вариант 3: Множественная форма, Родительный падеж. например пять долларово, много-много-восемь долларов. т.е. когда число оканчивается на 5, 6, 7, 8, 9, 0
Случай с нулём лучше рассмотреть отдельно в силу различных требований от того что вы действительно хотите получить.

Внимание! Для чисел оканчивающихся на 11, 12, 13, 14 есть особенность. Поэтому
основной алгоритм выбора формы существительного после числительного будет таким:
Шаг 1: Если число оканчивается на 1, но не оканчивается на 11, то вариант 1 (Именительный падеж)
Шаг 2: Если число оканчивается на 2, 3, 4, и не оканчивается на 12, 13, 14, то вариант 2 (Родительный падеж)
Шаг 3: Всё остальное — вариант 3 (Множественный родительный падеж)

Теперь вернемся к нашей изначальной задаче, ведь на входе у нас есть только одно существительное. Значит надо уметь его поставить в одну из этих форм. Воспользуемся библиотекой на python — pymorphy2 :

import pymorphy2

morph = pymorphy2.MorphAnalyzer()
word = morph.parse('доллар')[0]
v1, v2, v3 = word.inflect({'sing', 'nomn'}), word.inflect({'gent'}), word.inflect({'plur', 'gent'})

print(v1.word, v2.word, v3.word)  # доллар доллара долларов

Если кто знаком с библиотекой pymorphy2, то возможно знают, что можно напрямую воспользоваться методом make_agree_with_number . Это действительно так, и не надо воротить лишний код, но есть одно Но — библиотека не умеет генерировать сами числительные, а лишь согласовывать, ставя в нужную форму
существительное. Чтобы именно генерировать — воспользуемся библиотекой, найденной мной на github — https://github.com/seriyps/ru_number_to_text/blob/master/num2t4ru/__init__.py (ru_number_to_text-master). Отмечу, что библиотека делает даже чуть больше чем генерация целых числительных, также возможна генерация дробных числительных. И так, создадим финальную функцию, с импортом указанной библиотеки

from num2t4ru import num2text
import pymorphy2

def get_number_and_noun(numeral, noun):
    morph = pymorphy2.MorphAnalyzer()
    word = morph.parse(noun)[0]
    v1, v2, v3 = word.inflect({'sing', 'nomn'}), word.inflect({'gent'}), word.inflect({'plur', 'gent'})
    return num2text(num=numeral, main_units=((v1.word, v2.word, v3.word), 'm'))

result = get_number_and_noun(123452, 'доллар')  
print(result)  # сто двадцать три тысячи четыреста пятьдесят два доллара

В качестве практического применения сгенерированных числительных — представьте что вам надо создать много документов word, в каждый из которых требуется подставить полученные числа. Причем сгенерированные числа с согласуемым существительным можно в дальнейшем просклонять с помощью pymorphy2. (в текущем примере числительные в именительном падеже)

Кроссплатформенный способ формирования документов Word с помощью python

В данной публикации будет рассказано как сделать кроссплатформенный шаблон Microsoft Word и в дальнейшем использовать его для генерации документов на python 3.

История такова — что каждый месяц мне надо было отправлять фактически один и тот же документ, но в котором изменены несколько полей. Подправить документ — дело в общем-то не хитрое и алгоритм прост. Сначала ищем за предыдущий месяц, открываем и ждем пока word загрузится, изменяем нужные цифры и слова вручную, изменяем, закрываем и отправляем. Но вот это меня и напрягло — ведь всё можно автоматизировать и не тратить каждый раз по 5 минут, включая отправку. Кстати про отправление писем я уже писал в статье об python и outlook .

Достаточно быстро нашлась библиотека python3 docx-mailmerge . При установке не спутайте с mailmerge, они импортируются одинаково, но нет объекта MailMerge

Создаем шаблон в документе docx, обратите внимание, что документ должен быть именно docx. (Да, шаблони придется сделать на windows, но саму генерацию можно делать уже на linux.)

В то место, где надо вставить изменяемый текст кликаем курсором, после этого идем во Insert далее Quick Parts далее Field. Выскочит окно, в нем слева выбираем MergeField и в название пишем наименование изменяемого поля, например substitution_1 . Подробнее показано на рискунке
формирование word c изменяемым полем

Когда шаблон сформируете, сохраните его, например word_tpl.docx
Приступаем к кодированию, собственно минимальный код представлен ниже

from mailmerge import MailMerge

# указываем путь до шаблона
template = r"/path/to/template/word_tpl.docx"

# создаем объект и смотрим на имеющиемся поля
document = MailMerge(template)
print(document.get_merge_fields())

document.merge(
    substitution_1='Проверка генерирации документов с русским текстом',
    substitution_2='Работает'
)

document.write('generated_word_with_python.docx')

с помощью функции get_merge_fields можно посмотреть список имеющихся подстановок. Если вы его не видите, то что-то сделано не так, пересоздайте docx документ.
Таким образом такой простой код на python поможет генерировать однотипные документы word и избавит вас от рутины.