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()
:
# список пользователей
users = b.get_all('user.get')
Метод get_all()
возвращает список, где каждый элемент списка является словарем, описывающим одну сущность из запрошенного списка.
Вы также можете использовать параметр params
, чтобы кастомизировать запрос:
# список сделок в работе, включая пользовательские поля
deals = b.get_all('crm.deal.list', params={
'select': ['*', 'UF_*'],
'filter': {'CLOSED': 'N'}
})
Если у вас есть список 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()
:
# вставим в начало названия всех сделок их 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()
:
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
происходит проверка корректности самых популярных параметров, передаваемых к серверу, и поднимаются исключения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
).
- Существует пул из 50 запросов, которые можно направить без ожидания.
- Пул пополняется со скоростью 2 запроса в секунду.
- При исчерпании пула и несоблюдении режима ожидания сервер выдаёт ответ
403 Too Many Requests
.
Объект класса Bitrix
создаётся, чтобы через него выполнять все запросы к серверу Битрикс24.
Внутри объекта ведётся учёт скорости отправки запросов к серверу, поэтому важно, чтобы все запросы приложения в отношении одного аккаунта с одного IP-адреса отправлялись из одного экземпляра Bitrix
.
Создаёт экземпляр объекта Bitrix
.
-
webhook: str
- URL вебхука, полученного от сервера Битрикс. -
verbose: bool = True
- показывать прогрессбар при выполнении запроса.
Получить полный список сущностей по запросу 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
.
Вызвать метод REST API. Самый универсальный метод,
применяемый, когда get_all
и get_by_ID
не подходят.
-
method: str
- метод REST API -
items
- параметры вызываемого метода. Может быть списком, и тогда метод будет вызван для каждого элемента списка, а может быть одним словарем параметров для единичного вызова.
call()
вызывает method
, последовательно подставляя в параметры запроса все элементы items
, и возвращает список ответов сервера для каждого из отправленных запросов. Либо, если items
- не список, а словарь с параметрами, то происходит единичный вызов и возвращается его результат.
Вызвать метод 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,
...
}
Иногда, когда серверу Битрикса посылается запрос, отбирающий много ресурсов сервера
(например, на создание 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')
...
Снижает скорость запросов. По вызовам 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()
, он может делать как запросы по списку, так и единичный запрос:
method = 'crm.lead.add'
params = {'fields': {
'TITLE': 'Чпок'
}}
b.call(method, params)
Результатом будет ответ сервера по этому одному элементу.
Однако, если такие вызовы делаются несколько раз, то более эффективно формировать из них список и вызывать call()
единожды по всему списку.
Пока что никак.
Все обращения к серверу происходят асинхронно и список результатов отсортирован в том порядке, в котором сервер возвращал ответы. Если вам требуется сортировка, то вам нужно делать ее самостоятельно, например:
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