API wrapper для быстрого получения данных от Битрикс24 через REST API. Параллельные запросы к серверу, упаковка запросов в батчи, контроль скорости запросов, есть синхронный и асинхронный клиенты.
Project description
fast_bitrix24
API wrapper для Питона для быстрого получения данных от Битрикс24 через REST API.
Основная функциональность
Высокая скорость обмена данными
- На больших списках скорость обмена данными с сервером достигает тысяч элементов в секунду.
- Использование асинхронных запросов через
asyncio
иaiohttp
позволяет экономить время, делая несколько запросов к серверу параллельно. - Автоматическая упаковка запросов в батчи сокращает количество требуемых запросов к серверу и ускоряет обмен данными.
Избежание отказов сервера
- Скорость отправки запросов к серверу Битрикс контролируется для избежания ошибки HTTP
503 Service unavailable
. - Если сервер для сложных запросов начинает возвращать
500 Internal Server Error
, можно в одну строку понизить скорость запроосов.
Удобство кода
- Высокоуровневые списочные методы для сокращения количества необходимого кода. Большинство операций занимают только одну строку кода. Обработка параллельных запросов, упаковка запросов в батчи и многое другое убрано "под капот".
- Позволяет задавать параметры запроса именно в таком виде, как они приведены в документации к Bitrix24 REST API. Параметры проверяются на корректность для облегчения отладки.
- Выполнение запросов автоматически сопровождается прогресс-баром из пакета
tqdm
, иллюстрирующим не только количество обработанных элементов, но и прошедшее и оставшееся время выполнения запроса.
Синхронный и асинхронный клиенты
- Наличие асинхронного клиента позволяет использовать библиотеку для написания веб-приложений (например, телеграм-ботов).
Начало
Установите модуль через pip
:
pip install fast_bitrix24
Далее в python:
from fast_bitrix24 import *
# замените на ваш вебхук для доступа к Bitrix24
webhook = "https://your_domain.bitrix24.ru/rest/1/your_code/"
b = Bitrix(webhook)
Методы полученного объекта b
в дальнейшем используются для взаимодействия с сервером Битрикс24.
Использование
get_all()
Чтобы получить полностью список сущностей, используйте метод get_all()
:
# список пользователей
users = b.get_all('user.get')
Метод get_all()
возвращает список, где каждый элемент списка является словарем, описывающим одну сущность из запрошенного списка.
Вы также можете использовать параметр params
, чтобы кастомизировать запрос:
# список сделок в работе, включая пользовательские поля
deals = b.get_all('crm.deal.list', params={
'select': ['*', 'UF_*'],
'filter': {'CLOSED': 'N'}
})
get_by_ID()
Если у вас есть список ID сущностей, то вы можете получить их свойства при помощи метода get_by_ID()
и использовании методов вида *.get
:
'''
получим список всех контактов, привязанных к сделкам, в виде
[
(ID сделки1, [контакт1, контакт2, ...]),
(ID сделки2, [контакт1, контакт2, ...]),
...
]
'''
contacts = b.get_by_ID('crm.deal.contact.items.get',
[d['ID'] for d in deals])
Метод get_by_ID()
возвращает список кортежей вида (ID, result)
, где result
- ответ сервера относительно этого ID
.
call()
Чтобы создавать, изменять или удалять список сущностей, используйте метод call()
:
# вставим в начало названия всех сделок их ID
tasks = [
{
'ID': d['ID'],
'fields': {
'TITLE': f'{d["ID"]} - {d["TITLE"]}'
}
}
for d in deals
]
b.call('crm.deal.update', tasks)
Метод call()
возвращает список ответов сервера по каждому элементу переданного списка.
call_batch()
Если вы хотите вызвать пакетный метод, используйте call_batch()
:
results = b.call_batch ({
'halt': 0,
'cmd': {
'deals': 'crm.deal.list', # берем список сделок
# и берем список дел по первой из них
'activities': 'crm.activity.list?filter[ENTITY_TYPE]=3&filter[ENTITY_ID]=$result[deals][0][ID]'
}
})
Асинхронные вызовы
Если требуется использование бибилиотеки в асинхронном коде, то вместо клиента Bitrix()
создавайте клиент класса BitrixAsync()
:
from fast_bitrix24 import BitrixAsync
b = BitrixAsync(webhook)
Все методы у него - синхронные аналоги методов из Bitrix()
, описанных выше:
leads = await b.get_all('crm.lead.list')
NB! Не рекомендуется использование асинхронного клиента вместе со slow()
. Контекстный менеджер slow()
использует глобальные переменные для хранения состояния, и несколько параллельных вызовов slow()
приведут к непредсказуемым последствиям. Эта проблема будет закрыта в будущих версиях, когда slow()
станет частью клиента, а не самостоятельной сущностью.
Как это работает
- Перед обращением к серверу во всех методах класса
Bitrix
происходит проверка корректности самых популярных параметров, передаваемых к серверу, и поднимаются исключенияTypeError
иValueError
при наличии ошибок. - Cоздаются запросы на получение всех элементов из запрошенного списка.
- Созданные запросы упаковываются в батчи по 50 запросов в каждом.
- Полученные батчи параллельно отправляются на сервер с соблюдением установленных скоростных ограничений (см. ниже "Как Битрикс24 ограничивает скорость заросов").
- Ответы (содержимое поля
result
) собираются в единый плоский список и возвращаются пользователю.- Поднимаются исключения класса
aiohttp.ClientError
, если сервер Битрикс вернул HTTP-ошибку, иRuntimeError
, если код ответа был200
, но ошибка сдержалась в теле ответа сервера. - Происходит сортировка ответов (кроме метода
get_all()
) - порядок элементов в списке результатов совпадает с порядком соответствующих запросов в списке запросов.
- Поднимаются исключения класса
В случае с методом get_all()
пункт 2 выше выглядит немного сложнее:
get_all()
делает первый запрос к серверу Битрикс24 с указанным методом и параметрами.- Сервер возвращает первую страницу (50 элементов) и параметр
total
- общее количество элементов, найденных по запросу. - Исходя из полученного общего количества элементов, создаются запросы на каждую из страниц (всего
total // 50 - 1
запросов), необходимых для получения всех запрошенных элементов.
В связи с тем, что выполнение get_all()
по длинным спискам может занимать долгое время, в течение которого пользователи могут добавлять новые элементы в список, может возникнуть ситуация, когда общее полученное количество элементов может не соответствовать изначальному значению total
. В таких случаях будет выдано стандартное питоновское предупреждение (warning
).
Как Битрикс24 ограничивает скорость запросов
- Существует пул из 50 запросов, которые можно направить без ожидания.
- Пул пополняется со скоростью 2 запроса в секунду.
- При исчерпании пула и несоблюдении режима ожидания сервер выдаёт ответ
403 Too Many Requests
.
Подробный справочник по классу Bitrix
Объект класса Bitrix
создаётся, чтобы через него выполнять все запросы к серверу Битрикс24.
Внутри объекта ведётся учёт скорости отправки запросов к серверу, поэтому важно, чтобы все запросы приложения в отношении одного аккаунта с одного IP-адреса отправлялись из одного экземпляра Bitrix
.
Метод __init__(self, webhook: str, verbose: bool = True):
Создаёт экземпляр объекта Bitrix
.
Параметры
-
webhook: str
- URL вебхука, полученного от сервера Битрикс. -
verbose: bool = True
- показывать прогрессбар при выполнении запроса.
Метод get_all(self, method: str, params: dict = None) -> list
Получить полный список сущностей по запросу method
.
get_all()
самостоятельно обрабатывает постраничные ответы сервера, чтобы вернуть полный список (подробнее см. "Как это работает" выше).
Параметры
-
method: str
- метод REST API для запроса к серверу. -
params: dict
- параметры для передачи методу. Используется именно тот формат, который указан в документации к REST API Битрикс24.get_all()
не поддерживает параметрыstart
,limit
иorder
.
Возвращает полный список сущностей, имеющихся на сервере, согласно заданным методу и параметрам.
Метод get_by_ID(self, method: str, ID_list: Sequence, ID_field_name: str = 'ID', params: dict = None) -> list
Получить список сущностей по запросу method
и списку ID.
Используется для случаев, когда нужны не все сущности, имеющиеся в базе, а конкретный список поименованных ID, либо в REST API отсутствует способ получения сущностей одним вызовом.
Например, чтобы получить все контакты, привязанные к сделкам в работе, нужно выполнить следующий код:
deals = b.get_all('crm.deal.list', params={
'filter': {'CLOSED': 'N'}
})
contacts = b.get_by_ID('crm.deal.contact.item.get',
[d['ID'] for d in deals])
Параметры
-
method: str
- метод REST API для запроса к серверу. -
ID_list: Sequence
- список ID, в отношении которых будут выполняться запросы. -
ID_field_name: str
- название поля, в которое будут подставляться значения из спискаID_list
. По умолчанию'ID'
. -
params: dict
- параметры для передачи методу. Используется именно тот формат, который указан в документации к REST API Битрикс24. Если среди параметров, указанных вparams
, указан параметрID
, то поднимается исключениеValueError
.
Возвращает список кортежей вида:
[
(ID_1, результат_выполнения_запроса_по_ID_1),
(ID_2, результат_выполнения_запроса_по_ID_2),
...
]
Первым элементом каждого кортежа будет ID из списка ID_list
. Вторым элементом каждого кортежа будет результат выполнения запроса относительно этого ID. Это может быть, например, список связанных сущностей или пустой список, если не найдено ни одной привязанной сущности.
get_by_ID()
гарантированно возвращает список такой же длины, как и поданный на вход ID_list
.
Метод call(self, method: str, items)
Вызвать метод REST API. Самый универсальный метод,
применяемый, когда get_all
и get_by_ID
не подходят.
Параметры
-
method: str
- метод REST API -
items
- параметры вызываемого метода. Может быть списком, и тогда метод будет вызван для каждого элемента списка, а может быть одним словарем параметров для единичного вызова.
call()
вызывает method
, последовательно подставляя в параметры запроса все элементы items
, и возвращает список ответов сервера для каждого из отправленных запросов. Либо, если items
- не список, а словарь с параметрами, то происходит единичный вызов и возвращается его результат.
Метод call_batch(self, params: dict) -> dict
Вызвать метод batch
(см. официальную документацию по методу batch
).
Поддерживается примение результатов выполнения одной команды в следующей при помощи ключевого слова $result
:
results = b.call_batch ({
'halt': 0,
'cmd': {
'deals': 'crm.deal.list', # берем список сделок
# и берем список дел по первой из них
'activities': 'crm.activity.list?filter[ENTITY_TYPE]=3&filter[ENTITY_ID]=$result[deals][0][ID]'
}
})
Возвращает словарь вида:
{
'имя_команды_1': результаты_выполнения_команды_1,
'имя_команды_1': результаты_выполнения_команды_1,
...
}
Контекстный менеджер slow
Иногда, когда серверу Битрикса посылается запрос, отбирающий много ресурсов сервера
(например, на создание 2500 лидов), то сервер не выдерживает даже стандартных
темпов подачи запросов, описанных в официальной документации, возвращая 500 Internal Server Error
после нескольких первых запросов.
В такой ситуации помогает замедление запросов при
помощи контекстного менеджера slow
:
# временно снижаем скорость до 1.2 запроса в секунду
slower_speed = 1.2
with slow(slower_speed):
b.call('crm.lead.add', [{} for x in range(2500)])
# а теперь несемся с прежней скоростью
leads = b.get_all('crm.lead.list')
...
slow(requests_per_second: float = 0.5)
Снижает скорость запросов. По вызовам Bitrix, происходящим внутри вызова этого контекстного менеджера:
- скорость запросов гарантированно не превысит
requests_per_second
- механика "пула запросов" отключается - считается, что размер пула равен 0, и запросы подаются равномерно
После выхода из контекстного менеджера механика пула восстанавливается, однако пул считается пустым и начинает наполняться с обычной скоростью 2 запроса в секунду.
Параметры
requests_per_second: float = 0.5
- требуемая замедленная скорость запросов. По умолчанию 0.5 запросов в секунду.
Советы и подсказки
А как мне сформировать запрос к Битриксу, чтобы ...?
- Поищите в официальной документации по REST API.
- Если на ваш вопрос там нет ответа - попробуйте задать его в группе "Партнерский REST API" в Сообществе разработчиков Битрикс24.
- Спросите в Телеграме в группе разработчиков Битрикс24.
- Спросите в Телеграме в группе пользователей fast_bitrix24.
- Спросите на русском StackOverflow.
Я хочу добавить несколько лидов списком, но получаю ошибку сервера.
Оберните вызов call()
в slow
, установив скорость запросов в 1 - 1,3 в секунду:
with slow(1.2):
results = b.call('crm.lead.add', tasks)
Я хочу вызвать call()
только один раз, а не по списку.
Передавайте параметры запроса методу call()
, он может делать как запросы по списку, так и единичный запрос:
method = 'crm.lead.add'
params = {'fields': {
'TITLE': 'Чпок'
}}
b.call(method, params)
Результатом будет ответ сервера по этому одному элементу.
Однако, если такие вызовы делаются несколько раз, то более эффективно формировать из них список и вызывать call()
единожды по всему списку.
Как сортируются результаты при вызове get_all()
?
Пока что никак.
Все обращения к серверу происходят асинхронно и список результатов отсортирован в том порядке, в котором сервер возвращал ответы. Если вам требуется сортировка, то вам нужно делать ее самостоятельно, например:
deals = b.get_all('crm.deal.list')
deals.sort(key = lambda d: int(d['ID']))
Как связаться с автором
- telegram: https://t.me/fast_bitrix24
- создать новый github issue: https://github.com/leshchenko1979/fast_bitrix24/issues/new
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for fast_bitrix24-0.5.3-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | d1467d3d07f3f155f3c483b7dafcba54095be3080802968c19e5178af6521a45 |
|
MD5 | ffde062acbce69c8ef32c04d9fcde755 |
|
BLAKE2b-256 | 77f798ed2e3daa348e47474e5fe516b66ef94ff9467ceff3674295ed6fa5974a |