{"id":415673,"date":"2024-06-30T00:30:49","date_gmt":"2024-06-30T00:30:49","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=415673"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=415673","title":{"rendered":"<span>\u041a\u0440\u0430\u0442\u043a\u043e: \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a API \u0438 \u0440\u0430\u0437\u0431\u043e\u0440 XML-\u043e\u0442\u0432\u0435\u0442\u043e\u0432. Python<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u042d\u0442\u043e\u0442 \u043f\u043e\u0441\u0442 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u0432 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0434\u043b\u044f \u043d\u043e\u0432\u0438\u0447\u043a\u043e\u0432 \u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435, \u0432\u043f\u0435\u0440\u0432\u044b\u0435 \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u0432\u0448\u0438\u0445\u0441\u044f \u0441 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c\u044e \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c post\/get \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a \u043a\u0430\u043a\u043e\u043c\u0443-\u043d\u0438\u0431\u0443\u0434\u044c API \u0438 \u043f\u0440\u043e\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u0432 XML \u043e\u0442\u0432\u0435\u0442. \u041f\u043e\u0441\u0442\u0430\u0440\u0430\u043b\u0430\u0441\u044c \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435.<\/p>\n<h2>1. \u041d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e API<\/h2>\n<p>\u041e\u043d\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0442 \u0432\u0430\u0448\u0438\u0445 \u043a\u043e\u043b\u043b\u0435\u0433, \u043f\u0430\u0440\u0442\u043d\u0435\u0440\u043e\u0432, \u0437\u0430\u043a\u0430\u0437\u0447\u0438\u043a\u043e\u0432, \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432. \u0420\u0430\u0437\u043d\u043e\u0439 \u0441\u0442\u0435\u043f\u0435\u043d\u0438 \u0433\u043e\u0442\u043e\u0432\u043d\u043e\u0441\u0442\u0438 \u0438 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438. \u041d\u043e \u0443 \u043d\u0435\u0433\u043e \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e \u0435\u0441\u0442\u044c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043e\u0442\u0432\u0435\u0442\u0430 \u0438 \u0441\u0442\u0430\u0442\u0443\u0441-\u043a\u043e\u0434\u044b \u043e\u0442\u0432\u0435\u0442\u043e\u0432. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/5d5\/b03\/5da\/5d5b035dad0cdc0679eeb2c8cca0e35e.png\" width=\"648\" height=\"871\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5d5\/b03\/5da\/5d5b035dad0cdc0679eeb2c8cca0e35e.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0441\u0430\u043c \u043c\u0435\u0442\u043e\u0434 \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e curl &#8212; \u043c\u043e\u0436\u043d\u043e \u0441\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442\u044c \u0441\u0435\u0431\u0435 \u043c\u043d\u043e\u0433\u043e \u043d\u0435\u0440\u0432\u043e\u0432 \u0438 \u0441\u0438\u043b, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e \u0435\u0441\u043b\u0438 API \u0434\u043e\u043f\u0438\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0441 \u0432\u0430\u0448\u0435\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439. \u041f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0432\u043e\u0442 \u0442\u0430\u043a\u0438\u043c \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u043c <a href=\"https:\/\/reqbin.com\/req\/python\/c-xgafmluu\/convert-curl-to-python-requests\" rel=\"noopener noreferrer nofollow\">https:\/\/reqbin.com\/req\/python\/c-xgafmluu\/convert-curl-to-python-requests<\/a> \u0434\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e \u0431\u044b \u043f\u0435\u0440\u0435\u0432\u0435\u0441\u0442\u0438 curl-\u0437\u0430\u043f\u0440\u043e\u0441 \u0432 \u043a\u043e\u0434 \u043f\u043e\u0434 \u043b\u0438\u0431\u0443 requests. <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/531\/fd3\/fbc\/531fd3fbcbbf135fd4b41561126b486a.png\" width=\"1643\" height=\"677\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/531\/fd3\/fbc\/531fd3fbcbbf135fd4b41561126b486a.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0412\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u043c\u043e\u0434\u0443\u043b\u0435\u043c CaseInsensitiveDict \u0438\u0437 requests.structures \u0434\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e \u0431\u044b \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0432 \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u044b\u0435 headers. \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0435 files. \u0422\u043e\u0433\u0434\u0430 \u0434\u043b\u044f \u043c\u0435\u0442\u043e\u0434\u0430 \u0441 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0441\u043a\u0440\u0438\u043d\u0430 post-\u0437\u0430\u043f\u0440\u043e\u0441 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"python\">import requests from requests.structures import CaseInsensitiveDict  base_url = 'https:\/\/myaccount.ispringlearn.ru' headers = CaseInsensitiveDict() headers[\"Host\"] = 'api-learn.ispringlearn.ru' headers[\"X-Auth-Account-Url\"] = \"https:\/\/myaccount.ispringlearn.ru\/\" headers[\"X-Auth-Email\"] = \" email@email.com\" headers[\"X-Auth-Password\"] = \"12345Q\"  id_test_course = '14b847e8-c10f-11ea-b4e1-ae33e75597e9' id_test_enrollment = 'e1f2c50e-c1ae-11ea-8592-a6eabe1809b' url = f\"{base_url}\/statistics\/course\" files = {'courseId': (None, f'{id_test_course}'),          'enrollmentIds': (None, f'{id_test_enrollment}'),          'status': (None, 'automatic')                  } responce = requests.post(url=url, headers=headers, files=files) if responce.status_code != 200:     raise ValueError(f\"Request add_user failed {responce.status_code}\") resp_xml_content = responce.content print(f\"{resp_xml_content}\")<\/code><\/pre>\n<p>\u0412\u0430\u0440\u0438\u0430\u043d\u0442 \u0441 \u043e\u0442\u0432\u0435\u0442\u043e\u043c \u0432 json \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c \u043d\u0435 \u0431\u0443\u0434\u0443, \u043f\u043e \u043d\u0435\u043c\u0443 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e \u043e\u0447\u0435\u043d\u044c \u043c\u043d\u043e\u0433\u043e \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u0432, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u044e\u0441\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043d\u0430 XML.<\/p>\n<h2>2. XML. \u0427\u0442\u0435\u043d\u0438\u0435 \u0438 \u0440\u0430\u0437\u0431\u043e\u0440<\/h2>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f XML-\u043f\u043e\u0440\u0442\u044f\u043d\u043a\u0438 \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u043e\u0442\u043b\u0430\u0434\u043a\u0438 \u043d\u0435 \u043b\u0438\u0448\u043d\u0438\u043c \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u043e \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u043d\u0435\u0439. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u0435\u0440\u0432\u0438\u0441\u0430  <a href=\"https:\/\/jsonformatter.org\/xml-parser\" rel=\"noopener noreferrer nofollow\">https:\/\/jsonformatter.org\/xml-parser<\/a>.<\/p>\n<p>\u0412 \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0449\u0435\u043c \u0440\u0435\u0441\u043f\u043e\u043d\u0441\u0435 \u0431\u0430\u0439\u0442\u043e\u0432\u0430\u044f \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0430(\u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430\u044f \u0434\u043b\u044f \u0440\u0430\u0441\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u043d\u0438\u044f xml \u043f\u043e \u0434\u0435\u0440\u0435\u0432\u0443) \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0435 content. \u043f\u0435\u0440\u0435\u043f\u0438\u0448\u0435\u043c \u0434\u043b\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u0435\u0433\u043e \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e responce_xml_content.<\/p>\n<p>\u0412 \u0434\u0435\u0431\u0430\u0433\u0435\u0440\u0435 \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u0445\u043e\u0436\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0430\u0442\u0440\u0438\u0431\u0443\u0442 text \u0443 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0433\u043e responce, \u043d\u043e \u043e\u043d \u0442\u0430\u043c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043a\u0430\u043a utf-8.  <\/p>\n<p>\u0411\u043e\u043b\u044c\u0448\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u043c\u0430\u043d\u0443\u0430\u043b\u043e\u0432 \u043f\u043e \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0443 xml \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u043f\u043e\u0434 \u0447\u0442\u0435\u043d\u0438\u0435 \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 \u0438 \u043f\u043e\u0434 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 etree. \u0418 \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0441\u0442\u0440\u043e\u043a\u0438 \u0438\u0437 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 fromstring \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e \u0440\u0430\u0437\u043d\u043e\u043c\u0443. <\/p>\n<p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c \u0441\u0447\u0438\u0442\u0430\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 etree \u0438\u0437 \u043c\u043e\u0434\u0443\u043b\u044f lxml. \u0421 \u043d\u0438\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f get-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f post-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043b\u0430\u043a\u043e\u043d\u0438\u0447\u043d\u043e.<\/p>\n<pre><code class=\"python\">import re, os import requests from requests.structures import CaseInsensitiveDict from config import Config from lxml import etree from loguru import logger   class ApiRequest:     def init(self, new_user) -> None:         self.base_url = Config.base_url         self.headers = CaseInsensitiveDict()         self.headers[\"Host\"] = Config.Host         self.headers[\"X-Auth-Account-Url\"] = Config.X_Auth_Account_Url         self.headers[\"X-Auth-Email\"] = Config.X_Auth_Email         self.headers[\"X-Auth-Password\"] = Config.X_Auth_Password         self.new_user = new_user         self.default_department_id = Config.default_department_id         self.dueDate = Config.dueDate         self.re_login = re.compile('(?P&lt;login>\\w+)@', re.M | re.S)              def check_exist_user(self) -> bool:         \"\"\"example of get request\"\"\"         url = f\"{self.base_url}\/user\"         email = self.new_user.email         resp = requests.get(url, headers=self.headers)         if resp.status_code != 200:             raise ValueError(f\"Request check_exist_user failed {resp.status_code}\")         resp_xml_content = resp.content         tree = etree.XML(resp_xml_content)         user_by_email = tree.xpath(             f'\/response\/userProfile\/fields\/field[name = \"EMAIL\" and value = \"{email}\"]')         if user_by_email:             logger.info(f\"\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0441 email {email} \u0435\u0449\u0435 \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442\")             return False         logger.info(f\"\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0441 email {email} \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442\")         self.new_user.user_id = (tree.xpath(             f\".\/\/userProfile[.\/fields\/field\/name[contains(text(), 'EMAIL')] and .\/fields\/field\/value[contains(text(), '{email}')]]\/userId\"))[             0].text         return True       def add_user(self) -> bool:         \"\"\"example of post request\"\"\"         url = f\"{self.base_url}\/user\"         login = self.re_login.search(self.new_user.email).group('login')          files = {             'departmentId': (None, f'{self.default_department_id}'),             'fields[email]': (None, f'{self.new_user.email}'),             'fields[login]': (None, f'{login}'),         }          response = requests.post(url=url, headers=self.headers, files=files)          if response.status_code != 201:             raise ValueError(f\"Request add_user failed {response.status_code}\")         resp_xml_content = resp.content         try:             self.new_user.user_id = etree.XML(resp_xml_content).text             logger.info(f\"Add new user successful. User_id: {self.new_user.user_id}\")             return True         except Exception as ex:             logger.error(f\"Error get user_id from responce {ex}\")             return False  <\/code><\/pre>\n<h2>3. \u0410\u043d\u0430\u043b\u0438\u0437 XML. XPath \u0438\u043b\u0438 Bs4<\/h2>\n<p>XPath &#8212; \u044f\u0437\u044b\u043a \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0430\u0432\u0430\u0442\u044c \u0446\u0435\u043f\u043e\u0447\u043a\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432. \u0418 \u043d\u0430 \u043d\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0438\u0441\u0430\u0442\u044c \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u043f\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c \u043e\u0442\u0432\u0435\u0442\u0430.<\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0447\u0442\u043e \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u0438 \u0437\u043d\u0430\u044e\u0442 \u043e \u0441\u0432\u043e\u0438\u0445 \u0434\u0435\u0442\u044f\u0445, \u043d\u043e \u0434\u0435\u0442\u0438 \u043d\u0435 \u0437\u043d\u0430\u044e\u0442 \u043e \u0441\u0432\u043e\u0438\u0445 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044f\u0445. \u041d\u0430\u043f\u0440\u044f\u043c\u0443\u044e, \u0437\u0430\u0434\u0430\u0432 \u043f\u0443\u0442\u044c \u0434\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u043d\u0430 \u043f\u044f\u0442\u043e\u043c \u0443\u0440\u043e\u0432\u043d\u0435 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u0438, \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0435\u0441\u043b\u0438 \u0442\u0430\u043a\u043e\u0439 \u043d\u0430\u0439\u0434\u0435\u043d, \u0437\u0430\u0431\u0440\u0430\u0442\u044c \u0430\u0442\u0440\u0438\u0431\u0443\u0442 \u0441 \u0435\u0433\u043e \u0442\u0440\u0435\u0442\u044c\u0435\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f. <\/p>\n<p>\u041e\u0434\u0438\u043d \u0438\u0437 \u043d\u0435\u043c\u043d\u043e\u0433\u0438\u0445 \u043c\u0430\u043d\u0443\u0430\u043b\u043e\u0432 \u043f\u043e \u0442\u043e\u043c\u0443 \u043a\u0430\u043a \u0441 \u043d\u0438\u043c \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f <a href=\"http:\/\/www.k-press.ru\/cs\/2001\/2\/XPath\/XPath4.asp\" rel=\"noopener noreferrer nofollow\">http:\/\/www.k-press.ru\/cs\/2001\/2\/XPath\/XPath4.asp<\/a><\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/24e\/11a\/8ae\/24e11a8aefe610e7a9074f73d47d6f61.png\" width=\"662\" height=\"596\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/24e\/11a\/8ae\/24e11a8aefe610e7a9074f73d47d6f61.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0434\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e \u0431\u044b \u0434\u043e\u0441\u0442\u0430\u0442\u044c \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 id \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043f\u043e \u0438\u0441\u043a\u043e\u043c\u043e\u043c\u0443 email, \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0435\u0433\u043e\u0441\u044f \u0432 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0435 value \u0432 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0435 \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0430\u0442\u0440\u0438\u0431\u0443\u0442 name \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c email \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<pre><code class=\"python\">self.new_user.user_id = (tree.xpath(             f\".\/\/userProfile[.\/fields\/field\/name[contains(text(), 'EMAIL')] and .\/fields\/field\/value[contains(text(), '{email}')]]\/userId\"))[             0].text<\/code><\/pre>\n<p>\u0415\u0441\u0442\u044c \u0435\u0449\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e Bs4. \u0422\u043e\u0433\u0434\u0430 \u0442\u043e\u0442 \u0436\u0435 \u043f\u043e\u0438\u0441\u043a \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<pre><code class=\"python\">import bs4 import re soup = bs4.BeautifulSoup(html, 'lxml') found_user = soup.find_all('value', text=re.compile(f'{email}')) userProfile = (found_user[0]).parent.parent.parent userid = (userProfile.find('userid')).text<\/code><\/pre>\n<h2>4. \u0420\u0430\u0437\u043c\u0435\u0449\u0430\u0435\u043c \u044d\u0442\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 flask.<\/h2>\n<p>\u0420\u0435\u043a\u043e\u043c\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0441\u0442\u0440\u0430\u043d\u0438\u0446. <\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/077\/13d\/098\/07713d0987eb1648cb4f80e6b8ccdaa2.png\" width=\"309\" height=\"253\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/077\/13d\/098\/07713d0987eb1648cb4f80e6b8ccdaa2.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0412 api.py \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0438\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u0442\u0440\u0430\u043d\u0438\u0446. \u0414\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 post-\u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0441 json-\u043e\u043c \u0438 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u043c \u0444\u043e\u0440\u043c\u044b. \u0414\u043b\u044f \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0441\u0430\u043c\u044b\u043c \u043b\u0430\u043a\u043e\u043d\u0438\u0447\u043d\u044b\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u0431\u0443\u0434\u0435\u0442 pydantic,\u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f BaseModel, ValidationError, validator<\/p>\n<p>\u0415\u0441\u043b\u0438 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f styles.css \u0442\u043e \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u0442\u044c\u0441\u044f \u0435\u043c\u0443 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0432 \/static\/css.<\/p>\n<pre><code class=\"python\">from flask import Flask, jsonify, request, render_template, url_for, escape, make_response from flask_wtf import FlaskForm from loguru import logger from pydantic import BaseModel, ValidationError, validator from wtforms import StringField import re, os from api_requests import ApiRequest   DEBUG = True SECRET_KEY = ''  app = Flask(__name__) app.config.from_object(__name__)   class User(BaseModel):      \"\"\"     \u041c\u043e\u0434\u0435\u043b\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0421 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u043c \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 JSON     \"\"\"      name: str     surname: str     email: str     phone: str     user_id: str = ''     course_id: str      @validator(\"name\")     def validate_name(cls, name: str) -> str:         if not re.search('^(?P&lt;name>[\u0430-\u044f\u0410-\u042f]{2,})($|)', name):             raise ValueError(\"Incorrect name\")         return name.capitalize()      @validator(\"surname\")     def validate_surname(cls, surname: str) -> str:         if not re.search('^(?P&lt;surname>[\u0430-\u044f\u0410-\u042f]{2,})($|)', surname):             raise ValueError(\"Incorrect surname\")         return surname.capitalize()      @validator(\"phone\")     def validate_phone(cls, phone: str) -> str:         founds_phone = re.search('^(?P&lt;phone>(?P&lt;pre>\\+7|8|)(?P&lt;num>\\d{10}))($|)', phone, re.M|re.S)         if founds_phone is None:             raise ValueError(\"Incorrect phone\")         phone = f\"8{founds_phone.group('num')}\"         return phone      @validator(\"email\")     def validate_email(cls, email: str) -> str:         if not re.search('^(?P&lt;email>(?P&lt;mnaim>\\S+)\\@(?P&lt;host>\\S+)\\.(?P&lt;domain>\\w+))($|)', email):             raise ValueError(\"Incorrect email\")         return email.lower()   class RegistrationForm(FlaskForm):      \"\"\"\u0412\u0430\u0434\u0438\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u0437 POST \u0444\u043e\u0440\u043c\u044b\"\"\"      name = StringField()     surname = StringField()     email = StringField()     phone = StringField()     course_id = StringField()   @app.route(\"\/api\/v1\/register_post\", methods=[\"POST\"]) def isp_registration():     \"\"\"\u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432 isp post-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c\"\"\"          logger.debug(f'request.form = {request.form}')     if request.data:         try:             new_user = User.parse_raw(request.data)             processing_requests = ApiRequest(new_user)             processing_requests.api_requests()             logger.info(f'\u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f: {new_user}')             return new_user.json(ensure_ascii=False, indent=2)         except ValidationError as e:             logger.debug(f'\u041e\u0448\u0438\u0431\u043a\u0438 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 JSON: {e.json()}')             return e.json(), 400  @app.route(\"\/api\/register_form\", methods=['POST', \"GET\"]) def ispring_registration_from_form():     \"\"\"example http:\/\/127.0.0.1:5000\/api\/register_form?course_id=cc624f10-cf4b-11eb-82aa-4e8520552baf\"\"\"      logger.debug(f'request.form = {request.form}')     if request.method == 'POST':         form = RegistrationForm()         if form.validate_on_submit():             new_user = User(name=form.name.data, surname=form.surname.data, email=form.email.data,                             phone=form.phone.data, course_id=form.course_id.data)             req = ApiRequest(new_user)             req.api_requests()             logger.debug(f'\u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f: {new_user}')             return make_response(new_user.json(ensure_ascii=False, indent=2), status_code=200)          logger.debug(f'\u041e\u0448\u0438\u0431\u043a\u0438 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0444\u043e\u0440\u043c\u044b: {form.errors}')         return jsonify(form.errors), 400     return render_template('test_register_form1.html', course_id=request.args.get('course_id'))    if __name__ == '__main__':     app.config[\"WTF_CSRF_ENABLED\"] = True      app.run(host='0.0.0.0', debug=False, port=os.getenv(\"HOST\"))   <\/code><\/pre>\n<p>\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0435 \u043c\u0435\u0441\u0442\u043e \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432 \u0441\u0442\u0440\u0430\u043d\u0438\u0446 &#8212; \/templates. Base.html \u0434\u043b\u044f \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0431\u0449\u0435\u0433\u043e \u0441\u0442\u0438\u043b\u044f. <\/p>\n<pre><code class=\"css\">&lt;!DOCTYPE html> &lt;html lang=\"ru\"> &lt;head>     &lt;meta charset=\"UTF-8\">     &lt;link type=\"text\/css\" href=\"{{ url_for('static', filename='css\/styles.css') }}\" rel=\"stylesheet\"\/>     {% block title -%}         {% if title %}             &lt;title>\u0424\u043e\u0440\u043c\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 - {{ title }}&lt;\/title>         {% else %}             &lt;title>\u0424\u043e\u0440\u043c\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438&lt;\/title>         {% endif %}     {% endblock %} &lt;\/head> &lt;body> {% block content -%} {% block mainmenu -%} &lt;ul class=\"mainmenu\"> &lt;\/ul> {% endblock mainmenu -%} &lt;div class=\"clear\">&lt;\/div> &lt;div class=\"content\">     {% if title %}         &lt;h1>\u0424\u043e\u0440\u043c\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 - {{ title }}&lt;\/h1>     {% else %}         &lt;h1>\u0424\u043e\u0440\u043c\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 &lt;\/h1>     {% endif %} {% endblock content -%} &lt;\/div> &lt;\/body> &lt;\/html><\/code><\/pre>\n<p>\u0424\u043e\u0440\u043c\u0443 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0432 \u0442\u0430\u043a\u043e\u043c \u0432\u0438\u0434\u0435<\/p>\n<pre><code class=\"css\">&lt;!DOCTYPE html> &lt;html lang=\"ru\"> &lt;head>     &lt;meta charset=\"UTF-8\">     &lt;title> \u0424\u043e\u0440\u043c\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438&lt;\/title> &lt;\/head> &lt;body>  &lt;div>     &lt;h1>\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f&lt;\/h1>     &lt;form action=\"http:\/\/127.0.0.1:5000\/api\/register_form\" method=\"post\">         &lt;p>             &lt;input id=\"course_id\" type=\"text\" name=\"course_id\" hidden value={{ course_id }}>         &lt;\/p>         &lt;p>             &lt;label for=\"id_user\">name&lt;\/label>             &lt;input id=\"id_user\" type=\"text\" name=\"name\">         &lt;\/p>         &lt;p>             &lt;label for=\"id_surname\">surname&lt;\/label>             &lt;input id=\"id_surname\" type=\"text\" name=\"surname\">         &lt;\/p>         &lt;p>             &lt;label for=\"id_email\">email&lt;\/label>             &lt;input id=\"id_email\" type=\"text\" name=\"email\">         &lt;\/p>         &lt;p>             &lt;label for=\"id_phone\">phone&lt;\/label>             &lt;input id=\"id_phone\" type=\"text\" name=\"phone\">         &lt;\/p>         &lt;button>\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f&lt;\/button>     &lt;\/form> &lt;\/div>  &lt;\/body> &lt;\/html><\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c post-\u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a \u043d\u0430\u0448\u0435\u043c\u0443 \u0441\u0435\u0440\u0432\u0438\u0441\u0443, \u0442\u0430\u043a\u0438\u043c \u0436\u0435 \u043e\u0431\u0440\u0430\u0437\u043e\u043c, curl-\u043e\u043c, \u0447\u0435\u0440\u0435\u0437 postman \u0438\u043b\u0438  \u0440\u0443\u043a\u0430\u043c\u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u044f \u0444\u043e\u0440\u043c\u044b \u043d\u0430 \u0432\u0435\u0431-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435.<\/p>\n<p><a href=\"https:\/\/github.com\/OlgaPy\/Use_API_example_for_habr\" rel=\"noopener noreferrer nofollow\"><strong>\u0412\u0435\u0441\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0443 \u0437\u0434\u0435\u0441\u044c<\/strong><\/a><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/570852\/\"> https:\/\/habr.com\/ru\/articles\/570852\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u042d\u0442\u043e\u0442 \u043f\u043e\u0441\u0442 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u0432 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0434\u043b\u044f \u043d\u043e\u0432\u0438\u0447\u043a\u043e\u0432 \u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435, \u0432\u043f\u0435\u0440\u0432\u044b\u0435 \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u0432\u0448\u0438\u0445\u0441\u044f \u0441 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c\u044e \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c post\/get \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a \u043a\u0430\u043a\u043e\u043c\u0443-\u043d\u0438\u0431\u0443\u0434\u044c API \u0438 \u043f\u0440\u043e\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u0432 XML \u043e\u0442\u0432\u0435\u0442. \u041f\u043e\u0441\u0442\u0430\u0440\u0430\u043b\u0430\u0441\u044c \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435.<\/p>\n<h2>1. \u041d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e API<\/h2>\n<p>\u041e\u043d\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0442 \u0432\u0430\u0448\u0438\u0445 \u043a\u043e\u043b\u043b\u0435\u0433, \u043f\u0430\u0440\u0442\u043d\u0435\u0440\u043e\u0432, \u0437\u0430\u043a\u0430\u0437\u0447\u0438\u043a\u043e\u0432, \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432. \u0420\u0430\u0437\u043d\u043e\u0439 \u0441\u0442\u0435\u043f\u0435\u043d\u0438 \u0433\u043e\u0442\u043e\u0432\u043d\u043e\u0441\u0442\u0438 \u0438 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438. \u041d\u043e \u0443 \u043d\u0435\u0433\u043e \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e \u0435\u0441\u0442\u044c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043e\u0442\u0432\u0435\u0442\u0430 \u0438 \u0441\u0442\u0430\u0442\u0443\u0441-\u043a\u043e\u0434\u044b \u043e\u0442\u0432\u0435\u0442\u043e\u0432. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0441\u0430\u043c \u043c\u0435\u0442\u043e\u0434 \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e curl &#8212; \u043c\u043e\u0436\u043d\u043e \u0441\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442\u044c \u0441\u0435\u0431\u0435 \u043c\u043d\u043e\u0433\u043e \u043d\u0435\u0440\u0432\u043e\u0432 \u0438 \u0441\u0438\u043b, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e \u0435\u0441\u043b\u0438 API \u0434\u043e\u043f\u0438\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0441 \u0432\u0430\u0448\u0435\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439. \u041f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0432\u043e\u0442 \u0442\u0430\u043a\u0438\u043c \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u043c <a href=\"https:\/\/reqbin.com\/req\/python\/c-xgafmluu\/convert-curl-to-python-requests\" rel=\"noopener noreferrer nofollow\">https:\/\/reqbin.com\/req\/python\/c-xgafmluu\/convert-curl-to-python-requests<\/a> \u0434\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e \u0431\u044b \u043f\u0435\u0440\u0435\u0432\u0435\u0441\u0442\u0438 curl-\u0437\u0430\u043f\u0440\u043e\u0441 \u0432 \u043a\u043e\u0434 \u043f\u043e\u0434 \u043b\u0438\u0431\u0443 requests. <\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0412\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u043c\u043e\u0434\u0443\u043b\u0435\u043c CaseInsensitiveDict \u0438\u0437 requests.structures \u0434\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e \u0431\u044b \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0432 \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u044b\u0435 headers. \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0435 files. \u0422\u043e\u0433\u0434\u0430 \u0434\u043b\u044f \u043c\u0435\u0442\u043e\u0434\u0430 \u0441 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0441\u043a\u0440\u0438\u043d\u0430 post-\u0437\u0430\u043f\u0440\u043e\u0441 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"python\">import requests from requests.structures import CaseInsensitiveDict  base_url = 'https:\/\/myaccount.ispringlearn.ru' headers = CaseInsensitiveDict() headers[\"Host\"] = 'api-learn.ispringlearn.ru' headers[\"X-Auth-Account-Url\"] = \"https:\/\/myaccount.ispringlearn.ru\/\" headers[\"X-Auth-Email\"] = \" email@email.com\" headers[\"X-Auth-Password\"] = \"12345Q\"  id_test_course = '14b847e8-c10f-11ea-b4e1-ae33e75597e9' id_test_enrollment = 'e1f2c50e-c1ae-11ea-8592-a6eabe1809b' url = f\"{base_url}\/statistics\/course\" files = {'courseId': (None, f'{id_test_course}'),          'enrollmentIds': (None, f'{id_test_enrollment}'),          'status': (None, 'automatic')                  } responce = requests.post(url=url, headers=headers, files=files) if responce.status_code != 200:     raise ValueError(f\"Request add_user failed {responce.status_code}\") resp_xml_content = responce.content print(f\"{resp_xml_content}\")<\/code><\/pre>\n<p>\u0412\u0430\u0440\u0438\u0430\u043d\u0442 \u0441 \u043e\u0442\u0432\u0435\u0442\u043e\u043c \u0432 json \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c \u043d\u0435 \u0431\u0443\u0434\u0443, \u043f\u043e \u043d\u0435\u043c\u0443 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e \u043e\u0447\u0435\u043d\u044c \u043c\u043d\u043e\u0433\u043e \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u0432, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u044e\u0441\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043d\u0430 XML.<\/p>\n<h2>2. XML. \u0427\u0442\u0435\u043d\u0438\u0435 \u0438 \u0440\u0430\u0437\u0431\u043e\u0440<\/h2>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f XML-\u043f\u043e\u0440\u0442\u044f\u043d\u043a\u0438 \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u043e\u0442\u043b\u0430\u0434\u043a\u0438 \u043d\u0435 \u043b\u0438\u0448\u043d\u0438\u043c \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u043e \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u043d\u0435\u0439. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u0435\u0440\u0432\u0438\u0441\u0430  <a href=\"https:\/\/jsonformatter.org\/xml-parser\" rel=\"noopener noreferrer nofollow\">https:\/\/jsonformatter.org\/xml-parser<\/a>.<\/p>\n<p>\u0412 \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0449\u0435\u043c \u0440\u0435\u0441\u043f\u043e\u043d\u0441\u0435 \u0431\u0430\u0439\u0442\u043e\u0432\u0430\u044f \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0430(\u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430\u044f \u0434\u043b\u044f \u0440\u0430\u0441\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u043d\u0438\u044f xml \u043f\u043e \u0434\u0435\u0440\u0435\u0432\u0443) \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0435 content. \u043f\u0435\u0440\u0435\u043f\u0438\u0448\u0435\u043c \u0434\u043b\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u0435\u0433\u043e \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e responce_xml_content.<\/p>\n<p>\u0412 \u0434\u0435\u0431\u0430\u0433\u0435\u0440\u0435 \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u0445\u043e\u0436\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0430\u0442\u0440\u0438\u0431\u0443\u0442 text \u0443 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0433\u043e responce, \u043d\u043e \u043e\u043d \u0442\u0430\u043c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043a\u0430\u043a utf-8.  <\/p>\n<p>\u0411\u043e\u043b\u044c\u0448\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u043c\u0430\u043d\u0443\u0430\u043b\u043e\u0432 \u043f\u043e \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0443 xml \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u043f\u043e\u0434 \u0447\u0442\u0435\u043d\u0438\u0435 \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 \u0438 \u043f\u043e\u0434 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 etree. \u0418 \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0441\u0442\u0440\u043e\u043a\u0438 \u0438\u0437 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 fromstring \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e \u0440\u0430\u0437\u043d\u043e\u043c\u0443. <\/p>\n<p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c \u0441\u0447\u0438\u0442\u0430\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 etree \u0438\u0437 \u043c\u043e\u0434\u0443\u043b\u044f lxml. \u0421 \u043d\u0438\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f get-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f post-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043b\u0430\u043a\u043e\u043d\u0438\u0447\u043d\u043e.<\/p>\n<pre><code class=\"python\">import re, os import requests from requests.structures import CaseInsensitiveDict from config import Config from lxml import etree from loguru import logger   class ApiRequest:     def init(self, new_user) -> None:         self.base_url = Config.base_url         self.headers = CaseInsensitiveDict()         self.headers[\"Host\"] = Config.Host         self.headers[\"X-Auth-Account-Url\"] = Config.X_Auth_Account_Url         self.headers[\"X-Auth-Email\"] = Config.X_Auth_Email         self.headers[\"X-Auth-Password\"] = Config.X_Auth_Password         self.new_user = new_user         self.default_department_id = Config.default_department_id         self.dueDate = Config.dueDate         self.re_login = re.compile('(?P&lt;login>\\w+)@', re.M | re.S)              def check_exist_user(self) -> bool:         \"\"\"example of get request\"\"\"         url = f\"{self.base_url}\/user\"         email = self.new_user.email         resp = requests.get(url, headers=self.headers)         if resp.status_code != 200:             raise ValueError(f\"Request check_exist_user failed {resp.status_code}\")         resp_xml_content = resp.content         tree = etree.XML(resp_xml_content)         user_by_email = tree.xpath(             f'\/response\/userProfile\/fields\/field[name = \"EMAIL\" and value = \"{email}\"]')         if user_by_email:             logger.info(f\"\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0441 email {email} \u0435\u0449\u0435 \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442\")             return False         logger.info(f\"\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0441 email {email} \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442\")         self.new_user.user_id = (tree.xpath(             f\".\/\/userProfile[.\/fields\/field\/name[contains(text(), 'EMAIL')] and .\/fields\/field\/value[contains(text(), '{email}')]]\/userId\"))[             0].text         return True       def add_user(self) -> bool:         \"\"\"example of post request\"\"\"         url = f\"{self.base_url}\/user\"         login = self.re_login.search(self.new_user.email).group('login')          files = {             'departmentId': (None, f'{self.default_department_id}'),             'fields[email]': (None, f'{self.new_user.email}'),             'fields[login]': (None, f'{login}'),         }          response = requests.post(url=url, headers=self.headers, files=files)          if response.status_code != 201:             raise ValueError(f\"Request add_user failed {response.status_code}\")         resp_xml_content = resp.content         try:             self.new_user.user_id = etree.XML(resp_xml_content).text             logger.info(f\"Add new user successful. User_id: {self.new_user.user_id}\")             return True         except Exception as ex:             logger.error(f\"Error get user_id from responce {ex}\")             return False  <\/code><\/pre>\n<h2>3. \u0410\u043d\u0430\u043b\u0438\u0437 XML. XPath \u0438\u043b\u0438 Bs4<\/h2>\n<p>XPath &#8212; \u044f\u0437\u044b\u043a \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0430\u0432\u0430\u0442\u044c \u0446\u0435\u043f\u043e\u0447\u043a\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432. \u0418 \u043d\u0430 \u043d\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0438\u0441\u0430\u0442\u044c \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u043f\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c \u043e\u0442\u0432\u0435\u0442\u0430.<\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0447\u0442\u043e \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u0438 \u0437\u043d\u0430\u044e\u0442 \u043e \u0441\u0432\u043e\u0438\u0445 \u0434\u0435\u0442\u044f\u0445, \u043d\u043e \u0434\u0435\u0442\u0438 \u043d\u0435 \u0437\u043d\u0430\u044e\u0442 \u043e \u0441\u0432\u043e\u0438\u0445 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044f\u0445. \u041d\u0430\u043f\u0440\u044f\u043c\u0443\u044e, \u0437\u0430\u0434\u0430\u0432 \u043f\u0443\u0442\u044c \u0434\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u043d\u0430 \u043f\u044f\u0442\u043e\u043c \u0443\u0440\u043e\u0432\u043d\u0435 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u0438, \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0435\u0441\u043b\u0438 \u0442\u0430\u043a\u043e\u0439 \u043d\u0430\u0439\u0434\u0435\u043d, \u0437\u0430\u0431\u0440\u0430\u0442\u044c \u0430\u0442\u0440\u0438\u0431\u0443\u0442 \u0441 \u0435\u0433\u043e \u0442\u0440\u0435\u0442\u044c\u0435\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f. <\/p>\n<p>\u041e\u0434\u0438\u043d \u0438\u0437 \u043d\u0435\u043c\u043d\u043e\u0433\u0438\u0445 \u043c\u0430\u043d\u0443\u0430\u043b\u043e\u0432 \u043f\u043e \u0442\u043e\u043c\u0443 \u043a\u0430\u043a \u0441 \u043d\u0438\u043c \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f <a href=\"http:\/\/www.k-press.ru\/cs\/2001\/2\/XPath\/XPath4.asp\" rel=\"noopener noreferrer nofollow\">http:\/\/www.k-press.ru\/cs\/2001\/2\/XPath\/XPath4.asp<\/a><\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0434\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e \u0431\u044b \u0434\u043e\u0441\u0442\u0430\u0442\u044c \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 id \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043f\u043e \u0438\u0441\u043a\u043e\u043c\u043e\u043c\u0443 email, \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0435\u0433\u043e\u0441\u044f \u0432 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0435 value \u0432 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0435 \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0430\u0442\u0440\u0438\u0431\u0443\u0442 name \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c email \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<pre><code class=\"python\">self.new_user.user_id = (tree.xpath(             f\".\/\/userProfile[.\/fields\/field\/name[contains(text(), 'EMAIL')] and .\/fields\/field\/value[contains(text(), '{email}')]]\/userId\"))[             0].text<\/code><\/pre>\n<p>\u0415\u0441\u0442\u044c \u0435\u0449\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e Bs4. \u0422\u043e\u0433\u0434\u0430 \u0442\u043e\u0442 \u0436\u0435 \u043f\u043e\u0438\u0441\u043a \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<pre><code class=\"python\">import bs4 import re soup = bs4.BeautifulSoup(html, 'lxml') found_user = soup.find_all('value', text=re.compile(f'{email}')) userProfile = (found_user[0]).parent.parent.parent userid = (userProfile.find('userid')).text<\/code><\/pre>\n<h2>4. \u0420\u0430\u0437\u043c\u0435\u0449\u0430\u0435\u043c \u044d\u0442\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 flask.<\/h2>\n<p>\u0420\u0435\u043a\u043e\u043c\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0441\u0442\u0440\u0430\u043d\u0438\u0446. <\/p>\n<figure class=\"\"><figcaption><\/figcaption><\/figure>\n<p>\u0412 api.py \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0438\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u0442\u0440\u0430\u043d\u0438\u0446. \u0414\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 post-\u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0441 json-\u043e\u043c \u0438 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u043c \u0444\u043e\u0440\u043c\u044b. \u0414\u043b\u044f \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0441\u0430\u043c\u044b\u043c \u043b\u0430\u043a\u043e\u043d\u0438\u0447\u043d\u044b\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u0431\u0443\u0434\u0435\u0442 pydantic,\u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f BaseModel, ValidationError, validator<\/p>\n<p>\u0415\u0441\u043b\u0438 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f styles.css \u0442\u043e \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u0442\u044c\u0441\u044f \u0435\u043c\u0443 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0432 \/static\/css.<\/p>\n<pre><code class=\"python\">from flask import Flask, jsonify, request, render_template, url_for, escape, make_response from flask_wtf import FlaskForm from loguru import logger from pydantic import BaseModel, ValidationError, validator from wtforms import StringField import re, os from api_requests import ApiRequest   DEBUG = True SECRET_KEY = ''  app = Flask(__name__) app.config.from_object(__name__)   class User(BaseModel):      \"\"\"     \u041c\u043e\u0434\u0435\u043b\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0421 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u043c \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 JSON     \"\"\"      name: str     surname: str     email: str     phone: str     user_id: str = ''     course_id: str      @validator(\"name\")     def validate_name(cls, name: str) -> str:         if not re.search('^(?P&lt;name>[\u0430-\u044f\u0410-\u042f]{2,})($|)', name):             raise ValueError(\"Incorrect name\")         return name.capitalize()      @validator(\"surname\")     def validate_surname(cls, surname: str) -> str:         if not re.search('^(?P&lt;surname>[\u0430-\u044f\u0410-\u042f]{2,})($|)', surname):             raise ValueError(\"Incorrect surname\")         return surname.capitalize()      @validator(\"phone\")     def validate_phone(cls, phone: str) -> str:         founds_phone = re.search('^(?P&lt;phone>(?P&lt;pre>\\+7|8|)(?P&lt;num>\\d{10}))($|)', phone, re.M|re.S)         if founds_phone is None:             raise ValueError(\"Incorrect phone\")         phone = f\"8{founds_phone.group('num')}\"         return phone      @validator(\"email\")     def validate_email(cls, email: str) -> str:         if not re.search('^(?P&lt;email>(?P&lt;mnaim>\\S+)\\@(?P&lt;host>\\S+)\\.(?P&lt;domain>\\w+))($|)', email):             raise ValueError(\"Incorrect email\")         return email.lower()   class RegistrationForm(FlaskForm):      \"\"\"\u0412\u0430\u0434\u0438\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u0437 POST \u0444\u043e\u0440\u043c\u044b\"\"\"      name = StringField()     surname = StringField()     email = StringField()     phone = StringField()     course_id = StringField()   @app.route(\"\/api\/v1\/register_post\", methods=[\"POST\"]) def isp_registration():     \"\"\"\u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432 isp post-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c\"\"\"          logger.debug(f'request.form = {request.form}')     if request.data:         try:             new_user = User.parse_raw(request.data)             processing_requests = ApiRequest(new_user)             processing_requests.api_requests()             logger.info(f'\u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f: {new_user}')             return new_user.json(ensure_ascii=False, indent=2)         except ValidationError as e:             logger.debug(f'\u041e\u0448\u0438\u0431\u043a\u0438 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 JSON: {e.json()}')             return e.json(), 400  @app.route(\"\/api\/register_form\", methods=['POST', \"GET\"]) def<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-415673","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/415673","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=415673"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/415673\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=415673"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=415673"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=415673"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}