Skip to main content

Yandex business API client

Project description

Yandex business (sprav) API client codecov

Installation

# Sync only mode
pip install ya_business_api[sync]
# Async only mode
pip install ya_business_api[async]
# All modes
pip install ya_business_api[all]

Instantiating

There are several ways to work with the API (synchronous and asynchronous). Both interfaces have the same signatures, the only difference is the need to use async/await keywords.

from ya_business_api.sync_api import SyncAPI		# Sync mode
from ya_business_api.async_api import AsyncAPI		# Async mode


def main() -> None:
	api = SyncAPI.build(
		session_id=...,
		session_id2=...,
		csrf_token=...,		# Optional
	)

	# Do things here...


async def main() -> None:
	api = await AsyncAPI.build(
		session_id=...,
		session_id2=...,
		csrf_token=...,		# Optional
	)

	# Do things here...

	await api.session.close()

Where can I get the data for the client?

On the reviews page (https://yandex.ru/sprav/.../edit/reviews), open the developer console (usually F12) from the first request, copy values of cookies (Session_id and sessionid2).

In the console, run the following script:

function getData() {
	console.info({
		"CSRFToken": window?.__PRELOAD_DATA?.initialState?.env?.csrf,
		"PermanentId": window?.__PRELOAD_DATA?.initialState?.edit?.company?.permanent_id,
	})
}

getData()

/**
 * {CSRFToken: "...", PermanentId: 00000000000}
*/

⚠️WARNING⚠️

  1. The PermanentId belong to certain companies and cannot be used to respond to reviews from another company.
  2. The CSRFToken can be fetched automatically if it is not explicitly specified when calling the build method.

Reviews

Reviews fetching

  • Async mode support: ✅;
  • Validation disabling: ✅.
# Sync mode
from ya_business_api.sync_api import SyncAPI
from ya_business_api.reviews.dataclasses.requests import ReviewsRequest


api = SyncAPI.build(...)
# Requesting unread reviews only
request = ReviewsRequest(
	permanent_id=<permanent_id>,
	unread=True,
	ranking=Ranking.BY_RATING_DESC,			# Optional
	continue_token="CONTINUE_TOKEN",		# Optional
)
# Requesting all reviews
request = ReviewsRequest(
	permanent_id=<permanent_id>,
	page=9999,								# Optional
	ranking=Ranking.BY_RATING_DESC,			# Optional
)
response = api.reviews.get_reviews(
	request,
	raw=False,		# Optional
)

Answering to reviews

  • Async mode support: ✅;
  • Validation disabling: ❌.
from ya_business_api.sync_api import SyncAPI
from ya_business_api.reviews.dataclasses.requests import AnswerRequest


api = SyncAPI.build(...)
reviews = api.reviews.get_reviews()
# Legacy
request = AnswerRequest(
	review_id=reviews.list.items[0].id,
	text="Thank you!",
	reviews_csrf_token=reviews.list.csrf_token,
	answer_csrf_token=reviews.list.items[0].business_answer_csrf_token,
)
# New
request = AnswerRequest(
	review_id=reviews.list.items[0].id,
	text="Thank you!",
	reviews_csrf_token="",
)
response = api.reviews.send_answer(request)

Companies

Receiving companies

  • Async mode support: ✅;
  • Validation disabling: ✅.
from ya_business_api.sync_api import SyncAPI
from ya_business_api.companies.dataclasses.requests import CompaniesRequest


api = SyncAPI.build(...)
request = CompaniesRequest(filter="My Company", page=5)
response = api.companies.get_companies(
	request,		# Optional
	raw=False,		# Optional
)

Receiving company chain branches

Some companies have several branches, in such cases the company will have the "chain" type. This method will allow you to get a list of all branches.

  • Async mode support: ✅;
  • Validation disabling: ✅.
from ya_business_api.sync_api import SyncAPI
from ya_business_api.companies.dataclasses.requests import ChainBranchesRequest


api = SyncAPI.build(...)
request = ChainListRequest(
	tycoon_id=<tycoon_id>,		# Note: Some API endpoints returns companies without `tycoon_id`.
	permanent_id=<permanent_id>,
	geo_id=<address.geo_id>,
	page=1,						# Optional
)
response = api.companies.get_chain_branches(
	request,
	raw=False,		# Optional
)

Service

Receiving CSRF token

  • Async mode support: ✅;
  • Validation disabling: ❌.
from ya_business_api.sync_api import SyncAPI


api = SyncAPI.build(...)
csrf_token = api.service.get_csrf_token()

Shortcuts

Answers deleting

api.reviews.send_answer(AnswerRequest(text="", ...))

Automatic closing of the session (async mode)

async with await AsyncAPI.make_session(session_id=..., session_id2=...) as session:
	api = AsyncAPI(permanent_id=..., csrf_token=..., session=session)
	...

Examples

Receiving all unread reviews from all companies

from ya_business_api.async_api import AsyncAPI
from ya_business_api.companies.dataclasses.requests import CompaniesRequest, ChainBranchesRequest
from ya_business_api.reviews.dataclasses.requests import ReviewsRequest
from ya_business_api.reviews.dataclasses.reviews import Review
from ya_business_api.core.dataclass.base_company import BaseCompany

from asyncio import run
from os import getenv
from typing import AsyncGenerator
from logging import basicConfig, DEBUG


async def get_companies(api: AsyncAPI) -> AsyncGenerator[BaseCompany, None]:
	page = 1
	companies_response = await api.companies.get_companies()

	while companies_response.list_companies:
		for company in companies_response.list_companies:
			if company.type == "ordinal":
				yield company
			elif company.type == "chain":
				async for branch in get_ordinal_branches(api, company.tycoon_id):
					yield branch
			else:
				print(f"Company {company.permanent_id} with unknown type '{company.type}' was skipped")

		page += 1
		companies_request = CompaniesRequest(page=page)
		companies_response = await api.companies.get_companies(companies_request)


async def get_ordinal_branches(api: AsyncAPI, tycoon_id: int) -> AsyncGenerator[BaseCompany, None]:
	page = 1
	chain_branches_request = ChainBranchesRequest(tycoon_id=tycoon_id)
	chain_branches_response = await api.companies.get_chain_branches(chain_branches_request)

	while chain_branches_response.chain_data.companies:
		for company in chain_branches_response.chain_data.companies:
			if company.type == "ordinal":
				yield company
			elif company.type == "chain":
				raise RuntimeError(f"Unexpected chain company {company.permanent_id}")
			else:
				print(f"Company {company.permanent_id} with unknown type '{company.type}' was skipped")

		page += 1
		chain_branches_request = ChainBranchesRequest(tycoon_id=tycoon_id, page=page)
		chain_branches_response = await api.companies.get_chain_branches(chain_branches_request)


async def get_reviews(api: AsyncAPI, company_permanent_id: int) -> AsyncGenerator[Review, None]:
	request = ReviewsRequest(permanent_id=company_permanent_id, unread=True)
	response = await api.reviews.get_reviews(request)

	while response.list.items:
		for review in response.list.items:
			yield review

		continue_token = response.list.pager.continue_token
		request = ReviewsRequest(permanent_id=company_permanent_id, unread=True, continue_token=continue_token)
		response = await api.reviews.get_reviews(request)


async def main():
	basicConfig(
		format='[%(levelname)s | %(asctime)s | %(name)s] %(message)s',
		level=getenv('LOG_LEVEL', DEBUG),
	)
	session_id = getenv("YM_SESSION_ID")
	session_id2 = getenv("YM_SESSION_ID2")

	if not session_id:
		raise RuntimeError("YM_SESSION_ID is required")

	if not session_id2:
		raise RuntimeError("YM_SESSION_ID2 is required")

	api = await AsyncAPI.build(session_id=session_id, session_id2=session_id2)

	try:
		async for company in get_companies(api):
			print(company.permanent_id, company.display_name)

			async for review in get_reviews(api, company.permanent_id):
				print(review.id, review.full_text)

	finally:
		await api.session.close()


if __name__ == "__main__":
	run(main())

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ya_business_api-4.0.1.tar.gz (165.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ya_business_api-4.0.1-py3-none-any.whl (24.5 kB view details)

Uploaded Python 3

File details

Details for the file ya_business_api-4.0.1.tar.gz.

File metadata

  • Download URL: ya_business_api-4.0.1.tar.gz
  • Upload date:
  • Size: 165.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ya_business_api-4.0.1.tar.gz
Algorithm Hash digest
SHA256 746e8c60eeb2574232de922f6ca25b90756cd6aa25207570b1e1326885f31e8d
MD5 7aa6073cbf4877cfbee78a030ef560dd
BLAKE2b-256 2e73ab38970554343da074189cd97d88fd223e85a86840c96a42149e265a63ea

See more details on using hashes here.

Provenance

The following attestation bundles were made for ya_business_api-4.0.1.tar.gz:

Publisher: publish.yml on Kirill-Lekhov/ya-business-api

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ya_business_api-4.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for ya_business_api-4.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 451b17a6d1e1ba2229d8695a6c180f77be47ed495299c56e4f8053ad2edb1772
MD5 9b66166dee3b3f788e1c58087f73b266
BLAKE2b-256 07d85d8d937ed3ef915e950f042898131939e260830a37d1dca02270158397e8

See more details on using hashes here.

Provenance

The following attestation bundles were made for ya_business_api-4.0.1-py3-none-any.whl:

Publisher: publish.yml on Kirill-Lekhov/ya-business-api

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page