{"id":501926,"date":"2026-11-06T11:56:52","date_gmt":"2026-11-06T08:56:52","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=501926"},"modified":"2026-11-06T11:56:52","modified_gmt":"2026-11-06T08:56:52","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=501926","title":{"rendered":"\u041a\u0430\u043a \u044f \u043f\u0430\u0440\u0441\u0438\u043b \u043a\u0430\u0437\u0430\u0445\u0441\u0442\u0430\u043d\u0441\u043a\u0438\u0435 \u0433\u043e\u0441\u0441\u0430\u0439\u0442\u044b \u0447\u0435\u0440\u0435\u0437 COM"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041e\u0442\u0434\u0435\u043b \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0438 FMCG-\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u043f\u043e\u043d\u0435\u0434\u0435\u043b\u044c\u043d\u0438\u043a \u043d\u0430\u0447\u0438\u043d\u0430\u043b \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e: \u0447\u0435\u043b\u043e\u0432\u0435\u043a \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u043b <a href=\"http:\/\/stat.gov.kz\" rel=\"noopener nofollow\">stat.gov.kz<\/a>, \u043a\u0430\u0447\u0430\u043b \u043f\u0430\u0447\u043a\u0443 Excel-\u0442\u0430\u0431\u043b\u0438\u0446, \u043f\u043e\u0442\u043e\u043c \u0448\u0451\u043b \u043d\u0430 \u0441\u0430\u0439\u0442 \u041d\u0430\u0446\u0431\u0430\u043d\u043a\u0430 \u0437\u0430 \u043a\u0443\u0440\u0441\u0430\u043c\u0438, \u043f\u043e\u0442\u043e\u043c \u043d\u0430 KASE, \u043f\u043e\u0442\u043e\u043c \u0437\u0430 \u043c\u0438\u0440\u043e\u0432\u044b\u043c\u0438 \u0446\u0435\u043d\u0430\u043c\u0438 \u043d\u0430 \u0441\u0430\u0445\u0430\u0440 \u0438 \u043a\u0430\u043a\u0430\u043e \u043a FAO. \u0427\u0430\u0441\u0430 \u0447\u0435\u0440\u0435\u0437 \u0434\u0432\u0430 \u0432\u0441\u0451 \u044d\u0442\u043e \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u043b\u043e\u0441\u044c \u0432 \u043e\u0431\u0449\u0435\u0439 \u043f\u0430\u043f\u043a\u0435 \u043f\u043e\u0434 \u0438\u043c\u0435\u043d\u0430\u043c\u0438 \u0432\u0440\u043e\u0434\u0435 <code>data(1).xlsx<\/code><br \/>\u0418 \u043c\u043d\u0435 \u0441\u043a\u0430\u0437\u0430\u043b\u0438 &#171;\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u0443\u0439&#187;. <br \/>\u0414\u0430\u043b\u0438 \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u0430\u0439\u0442\u043e\u0439 \u043e\u0442\u043a\u0443\u0434\u0430 \u043e\u043d\u0438 \u0431\u0435\u0440\u0443\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 <\/p>\n<p>\u0421\u043f\u0438\u0441\u043e\u043a \u0431\u044b\u043b \u0442\u0430\u043a\u043e\u0432, \u043d\u043e \u043e\u043d \u0440\u043e\u0441 \u043f\u043e \u0445\u043e\u0434\u0443:<\/p>\n<ul>\n<li>\n<p><strong>\u041a\u0430\u0437\u0430\u0445\u0441\u0442\u0430\u043d:<\/strong> <a href=\"http:\/\/stat.gov.kz\" rel=\"noopener nofollow\">stat.gov.kz<\/a> (\u0411\u044e\u0440\u043e \u043d\u0430\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438), KASE, \u041d\u0430\u0446\u0431\u0430\u043d\u043a, <a href=\"http:\/\/goszakup.gov.kz\" rel=\"noopener nofollow\">goszakup.gov.kz<\/a>, <a href=\"http:\/\/adilet.zan.kz\" rel=\"noopener nofollow\">adilet.zan.kz<\/a> \u2014 \u0442\u0430\u043c \u0437\u0430\u043a\u043e\u043d\u044b, \u0438\u0445 \u0442\u043e\u0436\u0435 \u0437\u0430\u0445\u043e\u0442\u0435\u043b\u0438, \u043f\u0440\u0438\u0447\u0451\u043c \u0441 \u0440\u0430\u0437\u0431\u0438\u0432\u043a\u043e\u0439 \u043f\u043e \u0441\u0442\u0430\u0442\u044c\u044f\u043c;<\/p>\n<\/li>\n<li>\n<p><strong>\u0441\u044b\u0440\u044c\u0451 \u0438 \u0435\u0434\u0430:<\/strong> FAOSTAT, UN Comtrade, UNdata \u2014 \u043b\u0438\u043c\u043e\u043d\u043d\u0430\u044f \u043a\u0438\u0441\u043b\u043e\u0442\u0430, \u043a\u043e\u0444\u0435\u0438\u043d, \u0447\u0451\u0440\u043d\u044b\u0439 \u0447\u0430\u0439. \u0440\u044f\u0434\u044b FRED \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 BLS;<\/p>\n<\/li>\n<li>\n<p><strong>\u0444\u0438\u043d\u0430\u043d\u0441\u044b:<\/strong> ECB SDMX API, \u0426\u0411 \u0441\u043e\u0441\u0435\u0434\u0435\u0439, MOEX ISS, \u043c\u0438\u0440\u043e\u0432\u044b\u0435 \u0438\u043d\u0434\u0435\u043a\u0441\u044b \u0438 \u0444\u044c\u044e\u0447\u0435\u0440\u0441\u044b;<\/p>\n<\/li>\n<li>\n<p><strong>World Bank<\/strong> (\u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440\u044b, LPI), Open-Meteo \u043f\u043e \u0433\u043e\u0440\u043e\u0434\u0430\u043c \u041a\u0430\u0437\u0430\u0445\u0441\u0442\u0430\u043d\u0430.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0435\u0440\u0432\u0430\u044f \u043c\u044b\u0441\u043b\u044c \u0431\u044b\u043b\u0430 \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e\u0439: Airbyte, Meltano, \u0447\u0442\u043e-\u043d\u0438\u0431\u0443\u0434\u044c \u043d\u0430 Singer-\u0442\u0430\u043f\u0430\u0445. \u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043b. \u041a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440\u043e\u0432 \u043a <a href=\"http:\/\/stat.gov.kz\" rel=\"noopener nofollow\">stat.gov.kz<\/a>, KASE \u0438\u043b\u0438 \u0430\u0434\u0438\u043b\u0435\u0442\u0443 \u0442\u0430\u043c \u043d\u0435\u0442 \u0438 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442, \u0430 \u0438\u0445 \u0442\u0443\u0442 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e. \u041f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0431\u044b \u0432 \u043b\u044e\u0431\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0442\u043e\u043b\u044c\u043a\u043e \u0443\u0436\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 \u0447\u0443\u0436\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u2014 \u0438 \u0442\u0430\u0449\u0438\u0442\u044c \u0440\u0430\u0434\u0438 \u044d\u0442\u043e\u0433\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0441 \u043e\u0440\u043a\u0435\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u043e\u043c.<\/p>\n<p>CKAN \u0438 \u043f\u0440\u043e\u0447\u0438\u0435 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0440\u0435\u0448\u0430\u044e\u0442 \u0434\u0440\u0443\u0433\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443. \u041e\u043d\u0438 \u0445\u0440\u0430\u043d\u044f\u0442 \u0438 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442, \u043d\u043e \u043d\u0435 \u0432\u044b\u043a\u043e\u0432\u044b\u0440\u0438\u0432\u0430\u044e\u0442 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0438\u0437 HTML-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0433\u043e\u0441\u0441\u0430\u0439\u0442\u0430, \u0433\u0434\u0435 \u00ab\u0441\u043a\u0430\u0447\u0430\u0442\u044c\u00bb \u2014 \u044d\u0442\u043e <code>&lt;a&gt;<\/code> \u0431\u0435\u0437 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f, \u043e\u0442\u0434\u0430\u044e\u0449\u0438\u0439 <code>.xls<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 HTML.<\/p>\n<blockquote>\n<p>ImportError: <code>Import lxml<\/code> failed.  Use pip or conda to install the lxml package.<\/p>\n<\/blockquote>\n<p>\u042d\u0442\u043e, \u043a\u0441\u0442\u0430\u0442\u0438, \u043d\u0435 \u0432\u044b\u0434\u0443\u043c\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430: \u043e\u043d\u0430 \u043f\u044f\u0442\u044c \u0440\u0430\u0437 \u043b\u0435\u0436\u0438\u0442 \u0432 \u0436\u0443\u0440\u043d\u0430\u043b\u0435 \u0438\u043d\u0433\u0435\u0441\u0442\u043e\u0432. \u041f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c lxml \u043c\u043e\u0436\u043d\u043e, \u043d\u043e \u044f \u043a \u0442\u043e\u043c\u0443 \u043c\u043e\u043c\u0435\u043d\u0442\u0443 \u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0441\u0432\u043e\u0439 \u0440\u0430\u0437\u0431\u043e\u0440 \u0442\u0430\u0431\u043b\u0438\u0446 \u043d\u0430 BeautifulSoup \u2014 \u0441 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439 <code>&lt;th&gt;<\/code> \u0438 \u0441\u0442\u0440\u043e\u043a \u0440\u0430\u0437\u043d\u043e\u0439 \u0434\u043b\u0438\u043d\u044b. \u0422\u0430\u043a \u0438 \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c.<\/p>\n<p>\u041a\u043e\u0440\u043e\u0447\u0435, \u043f\u0438\u0441\u0430\u043b \u0441\u0430\u043c.<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/extt\/78\/8c\/eb\/788ceb9df1bb8acea8f1060f7f1bc97b.png\" alt=\"\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0437\u0430 30 \u0441\u0435\u043a\u0443\u043d\u0434\" title=\"\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0437\u0430 30 \u0441\u0435\u043a\u0443\u043d\u0434\" width=\"1024\" height=\"223\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/extt\/78\/8c\/eb\/788ceb9df1bb8acea8f1060f7f1bc97b.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/extt\/78\/8c\/eb\/788ceb9df1bb8acea8f1060f7f1bc97b.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0437\u0430 30 \u0441\u0435\u043a\u0443\u043d\u0434<\/figcaption><\/div>\n<\/figure>\n<p>\u0423 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440\u0430 \u0442\u0440\u0438 \u043c\u0435\u0442\u043e\u0434\u0430:<\/p>\n<pre><code class=\"python\">class BaseConnector(ABC):    source_name: str = \"unknown\"    source_type: str = \"web_api\"    @abstractmethod    def discover(self) -&gt; list[DiscoveredDataset]: ...   # \u0447\u0442\u043e \u0432\u043e\u043e\u0431\u0449\u0435 \u0435\u0441\u0442\u044c \u043d\u0430 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0435    @abstractmethod    def fetch(self, dataset: DiscoveredDataset) -&gt; bytes: ...   # \u0441\u044b\u0440\u044b\u0435 \u0431\u0430\u0439\u0442\u044b    @abstractmethod    def fetch_as_dataframe(self, dataset: DiscoveredDataset): ...   # \u0435\u0441\u043b\u0438 \u043f\u043e\u0432\u0435\u0437\u0451\u0442 \u2014 \u0441\u0440\u0430\u0437\u0443 \u0442\u0430\u0431\u043b\u0438\u0446\u0430<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper\"><\/span><\/a><\/div><\/pre>\n<p>\u041f\u0430\u0439\u043f\u043b\u0430\u0439\u043d \u0434\u0432\u0443\u0445\u0444\u0430\u0437\u043d\u044b\u0439. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 <code>discover<\/code>: \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440 \u043e\u0431\u0445\u043e\u0434\u0438\u0442 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0431\u0440\u0430\u0442\u044c. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u043e \u0444\u0440\u043e\u043d\u0442\u0435 \u0441\u0442\u0430\u0432\u0438\u0442 \u0433\u0430\u043b\u043e\u0447\u043a\u0438. \u041f\u043e\u0442\u043e\u043c <code>ingest<\/code>: \u0437\u0430\u0431\u0438\u0440\u0430\u0435\u043c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0435, \u043a\u043b\u0430\u0434\u0451\u043c \u0432 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435, \u043f\u0438\u0448\u0435\u043c \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u043a\u0430\u0442\u0430\u043b\u043e\u0433.\u0420\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u044f\u0432\u0438\u043b\u043e\u0441\u044c \u043d\u0435 \u043e\u0442 \u043b\u044e\u0431\u0432\u0438 \u043a \u043a\u0440\u0430\u0441\u043e\u0442\u0435. Discover \u0443 KASE \u2014 \u044d\u0442\u043e 16 \u0440\u0430\u0437\u0434\u0435\u043b\u043e\u0432 \u0441\u0430\u0439\u0442\u0430 \u0441 \u043f\u0430\u0443\u0437\u043e\u0439 0.4 \u0441\u0435\u043a\u0443\u043d\u0434\u044b \u043c\u0435\u0436\u0434\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0441\u043b\u043e\u0432\u0438\u0442\u044c \u0431\u0430\u043d. \u0413\u043e\u043d\u044f\u0442\u044c \u0435\u0433\u043e \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u043b\u0438\u043a \u043d\u0438\u043a\u0442\u043e \u043d\u0435 \u0431\u0443\u0434\u0435\u0442.<\/p>\n<pre><code class=\"python\">def make_session(verify_ssl: bool = False) -&gt; requests.Session:    s = requests.Session()    s.trust_env = False      # \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u043f\u0440\u043e\u043a\u0441\u0438 \u0438\u0437 env \u043b\u043e\u043c\u0430\u043b \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432    s.verify = verify_ssl    # \u0434\u0430, SSL \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d. \u0441\u043c. \u043d\u0438\u0436\u0435    retry = Retry(        total=3, connect=3, read=3, status=3,        backoff_factor=0.6,        status_forcelist=(429, 500, 502, 503, 504),        allowed_methods=(\"GET\", \"HEAD\", \"OPTIONS\"),        raise_on_status=False,    )    adapter = HTTPAdapter(max_retries=retry, pool_connections=20, pool_maxsize=20)    s.mount(\"http:\/\/\", adapter)    s.mount(\"https:\/\/\", adapter)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p><code>verify=False<\/code> \u2014 \u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0438\u0441\u0441, \u0437\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043d\u0435 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0441\u0442\u044b\u0434\u043d\u043e. \u0427\u0430\u0441\u0442\u044c \u0433\u043e\u0441\u0443\u0434\u0430\u0440\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0441\u0430\u0439\u0442\u043e\u0432 \u043e\u0442\u0434\u0430\u0451\u0442 \u043a\u0440\u0438\u0432\u0443\u044e \u0446\u0435\u043f\u043e\u0447\u043a\u0443 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0432, \u0438 \u0441 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u043e\u0439 \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440 \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u0441\u0442\u0430\u0440\u0442\u0443\u0435\u0442. \u0427\u0438\u0442\u0430\u0435\u043c \u043c\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u043d\u0438\u0447\u0435\u0433\u043e \u0441\u0435\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u043d\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b, \u0447\u0442\u043e \u044d\u0442\u043e \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u043e. \u041d\u043e \u0432 \u043f\u0440\u043e\u0434\u0435 \u0441 \u0447\u0443\u0432\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u044f \u0431\u044b \u0442\u0430\u043a \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435 \u0441\u0442\u0430\u043b.<\/p>\n<p>\u0420\u0435\u0442\u0440\u0430\u0438 \u043d\u0430 5xx \u0441\u043f\u0430\u0441\u0430\u044e\u0442 \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e. FRED, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0438\u043d\u043e\u0433\u0434\u0430 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0442\u0430\u043a:<\/p>\n<blockquote>\n<p>504 Server Error: Gateway Time-out for url: <a href=\"https:\/\/fred.stlouisfed.org\/graph\/fredgraph.csv?id=WPU057\" rel=\"noopener nofollow\">https:\/\/fred.stlouisfed.org\/graph\/fredgraph.csv?id=WPU057<\/a><\/p>\n<\/blockquote>\n<p>\u0422\u0440\u0438 \u0442\u0430\u043a\u0438\u0445 \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0436\u0443\u0440\u043d\u0430\u043b\u0435 \u2014 \u044d\u0442\u043e \u0443\u0436\u0435 \u043f\u043e\u0441\u043b\u0435 \u0442\u0440\u0451\u0445 \u0440\u0435\u0442\u0440\u0430\u0435\u0432 \u0441 \u0431\u044d\u043a\u043e\u0444\u0444\u043e\u043c. \u0411\u0435\u0437 \u043d\u0438\u0445 \u0438\u0445 \u0431\u044b\u043b\u043e \u0431\u044b \u0437\u0430\u043c\u0435\u0442\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0435.<\/p>\n<p>\u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430: \u0432\u0435\u0440\u0438\u0442\u044c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044e \u0444\u0430\u0439\u043b\u0430 \u043d\u0435\u043b\u044c\u0437\u044f. \u0418 <code>Content-Type<\/code> \u0442\u043e\u0436\u0435. \u0413\u043e\u0441\u0441\u0430\u0439\u0442\u044b \u043e\u0442\u0434\u0430\u044e\u0442 <code>.xlsx<\/code>, \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0441\u0442\u0430\u0440\u044b\u0439 OLE-\u0444\u043e\u0440\u043c\u0430\u0442, \u0438\u043b\u0438 <code>application\/octet-stream<\/code> \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0430 \u0432\u0441\u0451 \u043f\u043e\u0434\u0440\u044f\u0434.\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0444\u043e\u0440\u043c\u0430\u0442 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e \u043c\u0430\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u0431\u0430\u0439\u0442\u0430\u043c, \u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0442\u043e\u043c \u043f\u043e \u0438\u043c\u0435\u043d\u0438:<\/p>\n<pre><code class=\"python\">def detect_data_format(name: str = \"\", content_type: str = \"\", payload: bytes | None = None) -&gt; str:    ...    leading = payload[:16]    if leading.startswith(b\"PK\\x03\\x04\"):                          # zip-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u2192 xlsx        return \"xlsx\"    if leading.startswith(b\"\\xd0\\xcf\\x11\\xe0\\xa1\\xb1\\x1a\\xe1\"):    # OLE2 \u2192 \u0441\u0442\u0430\u0440\u044b\u0439 xls        return \"xls\"    if leading.startswith(b\"PAR1\"):        return \"parquet\"    if lower_name.endswith(\".csv\") or \"csv\" in lower_type:        return \"csv\"<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0410 \u043f\u0440\u0438 \u0441\u0442\u0430\u0440\u0442\u0435 \u0431\u044d\u043a\u0435\u043d\u0434 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u043f\u043e \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0443 \u0438 \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u044b\u0432\u0430\u0435\u0442 \u0444\u0430\u0439\u043b\u044b, \u0443 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u043d\u0435 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0435\u0442 \u0441 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c (<code>repair_file_extensions_by_content<\/code>). \u041a\u043e\u0441\u0442\u044b\u043b\u044c? \u0414\u0430. \u041d\u043e openpyxl, \u043f\u043e\u043b\u0443\u0447\u0438\u0432\u0448\u0438\u0439 OLE-\u0444\u0430\u0439\u043b \u043f\u043e\u0434 \u0438\u043c\u0435\u043d\u0435\u043c <code>.xlsx<\/code>, \u043f\u0430\u0434\u0430\u0435\u0442 \u0441 \u0442\u0430\u043a\u043e\u0439 \u043e\u0448\u0438\u0431\u043a\u043e\u0439, \u0447\u0442\u043e \u043f\u043e \u043d\u0435\u0439 \u043d\u0435 \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u0439\u043c\u0451\u0448\u044c, \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e.\u0421 CSV \u0441\u0432\u043e\u044f \u043f\u0435\u0441\u043d\u044f. \u0420\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u044c \u0431\u044b\u0432\u0430\u0435\u0442 \u0437\u0430\u043f\u044f\u0442\u043e\u0439, \u0442\u043e\u0447\u043a\u043e\u0439 \u0441 \u0437\u0430\u043f\u044f\u0442\u043e\u0439 \u0438\u043b\u0438 \u0442\u0430\u0431\u043e\u043c, \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0430 \u2014 UTF-8 \u0441 BOM, \u0431\u0435\u0437 BOM \u0438\u043b\u0438 cp1251. \u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u0442\u0443\u043f\u043e\u0435 \u0438 \u0440\u0430\u0431\u043e\u0447\u0435\u0435 \u2014 \u043f\u0435\u0440\u0435\u0431\u043e\u0440:<\/p>\n<pre><code class=\"python\">def decode_bytes(data: bytes) -&gt; str:    for encoding in (\"utf-8-sig\", \"utf-8\", \"cp1251\", \"latin-1\"):        try:            return data.decode(encoding)        except UnicodeDecodeError:            continue    return data.decode(\"utf-8\", errors=\"replace\")<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<pre><code class=\"python\">attempts.extend([    {\"sep\": \",\",  \"engine\": \"python\"},    {\"sep\": \";\",  \"engine\": \"python\"},    {\"sep\": \"\\t\", \"engine\": \"python\"},    {\"sep\": None, \"engine\": \"python\"},   # \u043f\u0443\u0441\u0442\u044c csv.Sniffer \u0433\u0430\u0434\u0430\u0435\u0442    # \u0438 \u0442\u0435 \u0436\u0435 \u0447\u0435\u0442\u044b\u0440\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u0441 on_bad_lines=\"skip\" \u2014 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0440\u0443\u0431\u0435\u0436])<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p><code>latin-1<\/code> \u0432 \u043a\u043e\u043d\u0446\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 \u0434\u0435\u043a\u043e\u0434\u0438\u0440\u0443\u0435\u0442 \u0432\u043e\u043e\u0431\u0449\u0435 \u0447\u0442\u043e \u0443\u0433\u043e\u0434\u043d\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u043e <code>errors=\"replace\"<\/code> \u0434\u0435\u043b\u043e \u043e\u0431\u044b\u0447\u043d\u043e \u043d\u0435 \u0434\u043e\u0445\u043e\u0434\u0438\u0442. \u0417\u0430\u0442\u043e \u0435\u0441\u043b\u0438 \u0444\u0430\u0439\u043b \u0431\u044b\u043b \u0432 cp1251, \u0430 <code>utf-8<\/code> \u0432\u0434\u0440\u0443\u0433 \u043f\u0440\u043e\u0448\u0451\u043b (\u0431\u044b\u0432\u0430\u0435\u0442 \u043d\u0430 \u043a\u043e\u0440\u043e\u0442\u043a\u0438\u0445 \u0444\u0430\u0439\u043b\u0430\u0445 \u0438\u0437 \u043e\u0434\u043d\u043e\u0439 \u043b\u0430\u0442\u0438\u043d\u0438\u0446\u044b), \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043a\u0440\u0430\u0441\u0438\u0432\u044b\u0435 \u043a\u0440\u0430\u043a\u043e\u0437\u044f\u0431\u0440\u044b. \u041b\u043e\u0432\u0438\u043b \u043f\u0430\u0440\u0443 \u0440\u0430\u0437.<\/p>\n<p>\u0422\u0438\u043f\u0438\u0447\u043d\u0430\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u0430 \u0441 <a href=\"http:\/\/stat.gov.kz\" rel=\"noopener nofollow\">stat.gov.kz<\/a>: \u0442\u0440\u0438 \u0441\u0442\u0440\u043e\u043a\u0438 \u0448\u0430\u043f\u043a\u0438 \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c \u0432\u0435\u0434\u043e\u043c\u0441\u0442\u0432\u0430, \u043f\u0443\u0441\u0442\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430, \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0451\u043d\u043d\u044b\u0435 \u044f\u0447\u0435\u0439\u043a\u0438, \u0438 \u0433\u0434\u0435-\u0442\u043e \u043d\u0430 \u043f\u044f\u0442\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438. <a href=\"http:\/\/pd.read\" rel=\"noopener nofollow\"><code>pd.read<\/code><\/a><code>_excel(header=0)<\/code> \u0447\u0435\u0441\u0442\u043d\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430\u043c\u0438 \u00ab\u0411\u044e\u0440\u043e \u043d\u0430\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438\u00bb \u0438 \u043f\u044f\u0442\u044c <code>Unnamed<\/code>.\u042d\u0432\u0440\u0438\u0441\u0442\u0438\u043a\u0430 \u043f\u0440\u043e\u0441\u0442\u0430\u044f: \u0432 \u043f\u0435\u0440\u0432\u044b\u0445 15 \u0441\u0442\u0440\u043e\u043a\u0430\u0445 \u0438\u0449\u0435\u043c \u0442\u0443, \u0433\u0434\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u0445 \u044f\u0447\u0435\u0435\u043a, \u0438 \u0441\u0447\u0438\u0442\u0430\u0435\u043c \u0435\u0451 \u0448\u0430\u043f\u043a\u043e\u0439.<\/p>\n<pre><code class=\"python\">scan_limit = min(len(cleaned), 15)header_idx = 0best_cells = -1for idx in range(scan_limit):    filled = int(cleaned.iloc[idx].notna().sum())    if filled &gt; best_cells:           # \u0441\u0442\u0440\u043e\u0433\u043e \u0431\u043e\u043b\u044c\u0448\u0435: \u043f\u0440\u0438 \u0440\u0430\u0432\u0435\u043d\u0441\u0442\u0432\u0435 \u043f\u043e\u0431\u0435\u0436\u0434\u0430\u0435\u0442 \u0432\u0435\u0440\u0445\u043d\u044f\u044f        best_cells = filled        header_idx = idx<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0418\u0437 \u0432\u0441\u0435\u0445 \u043b\u0438\u0441\u0442\u043e\u0432 \u043a\u043d\u0438\u0433\u0438 \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u0442, \u0433\u0434\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u0434\u0430\u043d\u043d\u044b\u0445: <code>score = \u043d\u0435\u043f\u0443\u0441\u0442\u044b\u0435_\u044f\u0447\u0435\u0439\u043a\u0438 + \u043a\u043e\u043b\u043e\u043d\u043a\u0438 * 10<\/code>. \u0412\u0435\u0441 \u0443 \u043a\u043e\u043b\u043e\u043d\u043e\u043a \u0437\u0430\u0432\u044b\u0448\u0435\u043d \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u2014 \u0438\u043d\u0430\u0447\u0435 \u0432\u044b\u0438\u0433\u0440\u044b\u0432\u0430\u043b \u043b\u0438\u0441\u0442 \u00ab\u041c\u0435\u0442\u043e\u0434\u043e\u043b\u043e\u0433\u0438\u044f\u00bb \u0441 \u043e\u0434\u043d\u043e\u0439 \u043a\u043e\u043b\u043e\u043d\u043a\u043e\u0439 \u0434\u043b\u0438\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0430.\u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430. \u041d\u043e \u043b\u0443\u0447\u0448\u0435, \u0447\u0435\u043c <code>Unnamed: 0<\/code>.<\/p>\n<p>\u0422\u0443\u0442 \u0431\u0443\u0434\u0435\u0442 \u0441\u0442\u044b\u0434\u043d\u043e, \u043d\u043e \u0447\u0435\u0441\u0442\u043d\u043e.<\/p>\n<p>\u0414\u043b\u044f <code>.xls<\/code> pandas \u043d\u0443\u0436\u0435\u043d xlrd. \u0415\u0433\u043e \u043d\u0435 \u0431\u044b\u043b\u043e, \u0438 pandas \u043e\u0442\u0432\u0435\u0447\u0430\u043b \u0442\u0430\u043a:<\/p>\n<blockquote>\n<p>ImportError: <code>Import xlrd<\/code> failed. Install xlrd &gt;= 2.0.1 for xls Excel support<\/p>\n<\/blockquote>\n<p>\u0412\u043c\u0435\u0441\u0442\u043e \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043e\u0434\u043d\u0443 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443, \u044f (\u0432 \u0442\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442 \u044d\u0442\u043e \u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0433\u0435\u043d\u0438\u0430\u043b\u044c\u043d\u044b\u043c) \u0440\u0435\u0448\u0438\u043b \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c <code>.xls<\/code> \u0432 <code>.xlsx<\/code> \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u043c Excel \u0447\u0435\u0440\u0435\u0437 COM. \u0418\u0437 Python. \u0427\u0435\u0440\u0435\u0437 PowerShell.<\/p>\n<pre><code class=\"python\">command = f\"\"\"$excel = $null$workbook = $nulltry {{  $excel = New-Object -ComObject Excel.Application  $excel.Visible = $false  $excel.DisplayAlerts = $false  $workbook = $excel.Workbooks.Open('{ps_source}')  $workbook.SaveAs('{ps_target}', 51)       # 51 = xlOpenXMLWorkbook}} finally {{  if ($workbook -ne $null) {{ $workbook.Close($false) }}  if ($excel -ne $null) {{ $excel.Quit() }}}}\"\"\"result = subprocess.run([\"powershell\", \"-NoProfile\", \"-NonInteractive\", \"-Command\", command],                        capture_output=True, text=True, timeout=60)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0421\u0430\u043c\u043e\u0435 \u0441\u043c\u0435\u0448\u043d\u043e\u0435 \u2014 \u043e\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442. \u041d\u0430 \u043c\u043e\u0435\u0439 \u043c\u0430\u0448\u0438\u043d\u0435 \u0441 Office.<\/p>\n<p>\u041f\u0440\u043e\u0431\u043b\u0435\u043c \u0440\u043e\u0432\u043d\u043e \u0442\u0440\u0438:<br \/>\u041f\u043e\u0441\u043b\u0435 <code>Quit()<\/code> Excel \u0435\u0449\u0451 \u043a\u0430\u043a\u043e\u0435-\u0442\u043e \u0432\u0440\u0435\u043c\u044f \u0434\u0435\u0440\u0436\u0438\u0442 \u0444\u0430\u0439\u043b. <code>shutil.rmtree(temp_dir, ignore_errors=True)<\/code> \u043c\u043e\u043b\u0447\u0430 \u043d\u0435 \u0443\u0434\u0430\u043b\u044f\u0435\u0442 \u043f\u0430\u043f\u043a\u0443, \u0438 \u0432 <code>.tmp_excel_conversion\/<\/code> \u0443 \u043c\u0435\u043d\u044f \u0434\u043e \u0441\u0438\u0445 \u043f\u043e\u0440 \u043b\u0435\u0436\u0430\u0442 \u0447\u0435\u0442\u044b\u0440\u0435 \u043e\u0441\u0438\u0440\u043e\u0442\u0435\u0432\u0448\u0438\u0445 <code>job_*\/source.xls<\/code>.<br \/>\u041a\u0430\u0432\u044b\u0447\u043a\u0438 \u0432 \u043f\u0443\u0442\u0438 \u044d\u043a\u0440\u0430\u043d\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 <code>replace(\"'\", \"''\")<\/code>. \u0414\u043b\u044f \u043e\u0434\u0438\u043d\u0430\u0440\u043d\u044b\u0445 \u043a\u0430\u0432\u044b\u0447\u0435\u043a PowerShell \u044d\u0442\u043e\u0433\u043e \u0445\u0432\u0430\u0442\u0430\u0435\u0442, \u043d\u043e \u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0441\u0442\u0440\u043e\u043a\u0438 \u2014 \u0442\u0430\u043a \u0441\u0435\u0431\u0435 \u0438\u0434\u0435\u044f.<br \/>Docker-\u043e\u0431\u0440\u0430\u0437 \u0443 \u0431\u044d\u043a\u0435\u043d\u0434\u0430 \u2014 <code>python:3.12-slim<\/code>. \u0422\u0430\u043c \u043d\u0435\u0442 \u043d\u0438 PowerShell, \u043d\u0438 Excel. \u0422\u043e \u0435\u0441\u0442\u044c \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435 \u0432\u0441\u044f \u044d\u0442\u0430 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.<\/p>\n<p>\u041f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u0444\u0438\u043a\u0441 \u2014 <code>pip install xlrd<\/code> (\u0438\u043b\u0438 LibreOffice headless, \u0435\u0441\u043b\u0438 \u0444\u0430\u0439\u043b\u044b \u0441\u043e\u0432\u0441\u0435\u043c \u044d\u043a\u0437\u043e\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435). \u041e\u043d \u0441\u0442\u043e\u0438\u0442 \u0443 \u043c\u0435\u043d\u044f \u043f\u0435\u0440\u0432\u044b\u043c \u0432 TODO, \u0438 \u043c\u043d\u0435 \u0437\u0430 \u043d\u0435\u0433\u043e \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043d\u0435\u043b\u043e\u0432\u043a\u043e.<\/p>\n<p><strong>\u041a\u0430\u0442\u0430\u043b\u043e\u0433 \u043d\u0430 \u043e\u0434\u043d\u043e\u043c JSON<\/strong><\/p>\n<p>\u0421\u0430\u043c\u0430\u044f \u0441\u043f\u043e\u0440\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c. \u0412\u0441\u0435 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u2014 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438, \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u044b, \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043e\u043a, \u043a\u044d\u0448 discover \u2014 \u043b\u0435\u0436\u0430\u0442 \u0432 \u043e\u0434\u043d\u043e\u043c <code>catalog.json<\/code>. \u0412 S3-\u0440\u0435\u0436\u0438\u043c\u0435 \u044d\u0442\u043e \u043e\u0434\u0438\u043d \u043e\u0431\u044a\u0435\u043a\u0442 <code>meta\/catalog.json<\/code>.<br \/>\u041f\u043e\u0447\u0435\u043c\u0443 \u043d\u0435 <strong>Postgres<\/strong>? \u041e\u043d \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043d: \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0435\u0441\u0442\u044c <code>catalog\/db.py<\/code> \u0441 <strong>SQLAlchemy<\/strong>-\u043c\u043e\u0434\u0435\u043b\u044f\u043c\u0438 \u0438 \u0444\u043b\u0430\u0433 <code>USE_DATABASE<\/code> \u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0435. \u041d\u043e \u043a API \u043e\u043d \u043d\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0451\u043d. \u041f\u0435\u0440\u0432\u044b\u0435 \u043d\u0435\u0434\u0435\u043b\u0438 \u043d\u0443\u0436\u0435\u043d \u0431\u044b\u043b \u043a\u0430\u0442\u0430\u043b\u043e\u0433, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u0433\u043b\u0430\u0437\u0430\u043c\u0438, \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0440\u0443\u043a\u0430\u043c\u0438 \u0438 \u0437\u0430\u043a\u043e\u043c\u043c\u0438\u0442\u0438\u0442\u044c \u043a\u0430\u043a \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0443. JSON \u044d\u0442\u043e \u0434\u0430\u0432\u0430\u043b, \u0430 \u043f\u043e\u0442\u043e\u043c \u0442\u0430\u043a \u0438 \u043f\u0440\u0438\u0436\u0438\u043b\u0441\u044f. \u0412\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u043a\u0430\u043a \u043e\u0431\u044b\u0447\u043d\u043e, \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0441\u0430\u043c\u044b\u043c \u0434\u043e\u043b\u0433\u043e\u0436\u0438\u0432\u0443\u0449\u0438\u043c.<\/p>\n<p><strong>\u041f\u0435\u0440\u0432\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0438: \u0430\u0442\u043e\u043c\u0430\u0440\u043d\u044b\u0439 replace<\/strong><\/p>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u044f \u0441\u0434\u0435\u043b\u0430\u043b \u00ab\u043f\u043e \u0443\u0447\u0435\u0431\u043d\u0438\u043a\u0443\u00bb: \u043f\u0438\u0448\u0435\u043c \u0432\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b, \u043f\u043e\u0442\u043e\u043c <code>os.replace<\/code> \u043f\u043e\u0432\u0435\u0440\u0445 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e, \u0430 \u043c\u0435\u0436\u0434\u0443 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430\u043c\u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u0443\u0435\u043c\u0441\u044f \u0447\u0435\u0440\u0435\u0437 lock-\u0444\u0430\u0439\u043b \u0441 <code>O_CREAT | O_EXCL<\/code>:<\/p>\n<pre><code class=\"python\">fd = os.open(lock_path, os.O_CREAT | os.O_EXCL | os.O_WRONLY)os.write(fd, str(os.getpid()).encode(\"utf-8\"))<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u041d\u0430 Linux \u044d\u0442\u043e \u043a\u043b\u0430\u0441\u0441\u0438\u043a\u0430. \u041d\u0430 Windows <code>os.replace<\/code> \u043f\u0430\u0434\u0430\u0435\u0442, \u0435\u0441\u043b\u0438 \u0446\u0435\u043b\u0435\u0432\u043e\u0439 \u0444\u0430\u0439\u043b \u043a\u0442\u043e-\u0442\u043e \u0434\u0435\u0440\u0436\u0438\u0442 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u2014 \u0430 \u0434\u0435\u0440\u0436\u0430\u043b \u0435\u0433\u043e \u0442\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 uvicorn \u0441 <code>--reload<\/code>, \u0442\u043e \u0430\u043d\u0442\u0438\u0432\u0438\u0440\u0443\u0441, \u0442\u043e \u044f \u0441\u0430\u043c \u0432 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435:<\/p>\n<blockquote>\n<p>PermissionError: [Errno 13] \u041e\u0442\u043a\u0430\u0437\u0430\u043d\u043e \u0432 \u0434\u043e\u0441\u0442\u0443\u043f\u0435<\/p>\n<\/blockquote>\n<p>\u041e\u0442 \u0442\u043e\u0439 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438 \u043e\u0441\u0442\u0430\u043b\u0438\u0441\u044c \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u044b: \u0432 <code>.tmp_api_smoke\/<\/code> \u043b\u0435\u0436\u0438\u0442 <code>catalog.json.tmp.20872.14844<\/code> (\u0438\u043c\u044f \u0441\u043e\u0431\u0440\u0430\u043d\u043e \u0438\u0437 PID \u0438 thread id) \u0438 <code>catalog.json.lock<\/code> \u0441 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c <code>20872<\/code>. \u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0443\u043c\u0435\u0440, \u0430 lock \u043e\u0441\u0442\u0430\u043b\u0441\u044f. \u0420\u043e\u0432\u043d\u043e \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 <code><em>acquire<\/em>file_lock<\/code> \u043f\u043e\u0442\u043e\u043c \u043f\u043e\u044f\u0432\u0438\u043b\u043e\u0441\u044c <code>stale_after = 30<\/code> \u0441\u0435\u043a\u0443\u043d\u0434: lock \u0441\u0442\u0430\u0440\u0448\u0435 30 \u0441\u0435\u043a\u0443\u043d\u0434 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0442\u0443\u0445\u0448\u0438\u043c \u0438 \u0443\u0434\u0430\u043b\u044f\u0435\u0442\u0441\u044f.<\/p>\n<p><strong>\u0422\u0435\u043a\u0443\u0449\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f<\/strong><\/p>\n<pre><code class=\"python\">def _save(self):    payload = json.dumps(self._data, ensure_ascii=False, indent=2, default=str).encode(\"utf-8\")    with open(target, \"a+b\") as file_obj:          # a+b: \u043d\u0435 \u043e\u0431\u043d\u0443\u043b\u044f\u0435\u0442 \u0444\u0430\u0439\u043b \u043f\u0440\u0438 \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0438        file_obj.seek(0)        if os.name == \"nt\":            msvcrt.locking(file_obj.fileno(), msvcrt.LK_LOCK, 1)   # \u043b\u043e\u0447\u0438\u043c \u043f\u0435\u0440\u0432\u044b\u0439 \u0431\u0430\u0439\u0442        else:            fcntl.flock(file_obj.fileno(), fcntl.LOCK_EX)        try:            existing = file_obj.read()            if existing:                with open(backup_path, \"wb\") as backup_obj:   # \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u2014 \u0431\u044d\u043a\u0430\u043f \u0441\u0442\u0430\u0440\u043e\u0433\u043e                    backup_obj.write(existing)                    backup_obj.flush()                    os.fsync(backup_obj.fileno())            file_obj.seek(0)            file_obj.truncate()            file_obj.write(payload)            file_obj.flush()            os.fsync(file_obj.fileno())        finally:            <\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u042d\u0442\u043e \u043d\u0435 \u0430\u0442\u043e\u043c\u0430\u0440\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c. \u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0443\u043c\u0440\u0451\u0442 \u043c\u0435\u0436\u0434\u0443 <code>truncate()<\/code> \u0438 <code>write()<\/code>, \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0444\u0430\u0439\u043b \u043e\u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043f\u0443\u0441\u0442\u044b\u043c \u0438\u043b\u0438 \u043e\u0431\u0440\u0435\u0437\u0430\u043d\u043d\u044b\u043c. \u0417\u0430\u0442\u043e \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c\u044b\u043c: <code>_load<\/code> \u043b\u043e\u0432\u0438\u0442 <code>JSONDecodeError<\/code> \u0438 \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442 <code>catalog.json.bak<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043a \u044d\u0442\u043e\u043c\u0443 \u043c\u043e\u043c\u0435\u043d\u0442\u0443 \u0443\u0436\u0435 \u043b\u0435\u0436\u0438\u0442 \u043d\u0430 \u0434\u0438\u0441\u043a\u0435 \u0441 fsync.<\/p>\n<pre><code class=\"python\">def _load(self) -&gt; dict:    if os.path.exists(self.filepath):        try:            return self._read_json_file(self.filepath)        except json.JSONDecodeError:            backup_path = self._backup_path()            if os.path.exists(backup_path):                return self._read_json_file(backup_path)            raise<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0418 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e \u0440\u0435\u0436\u0438\u043c <code>a+b<\/code>. \u0421 <code>wb<\/code> \u0444\u0430\u0439\u043b \u043e\u0431\u043d\u0443\u043b\u044f\u0435\u0442\u0441\u044f \u0435\u0449\u0451 \u0434\u043e \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043c\u044b \u0432\u0437\u044f\u043b\u0438 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443, \u0438 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u0439 \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u044c \u0432\u0438\u0434\u0438\u0442 \u043f\u0443\u0441\u0442\u043e\u0442\u0443.<br \/>\u0415\u0449\u0451 \u043e\u0434\u043d\u0430 \u0434\u0435\u0442\u0430\u043b\u044c, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u044f \u0437\u0430\u043c\u0435\u0442\u0438\u043b, \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u0433\u0434\u0430 \u043f\u0435\u0440\u0435\u0447\u0438\u0442\u044b\u0432\u0430\u043b \u043a\u043e\u0434 \u0434\u043b\u044f \u0441\u0442\u0430\u0442\u044c\u0438: \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code><em>acquire<\/em>file_lock<\/code> \u0441 O_EXCL-\u043b\u043e\u0433\u0438\u043a\u043e\u0439 \u0438 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 \u043f\u0440\u043e\u0442\u0443\u0445\u0448\u0438\u0445 \u043b\u043e\u043a\u043e\u0432 \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u0430\u0441\u044c, \u043d\u043e <code>_save<\/code> \u0435\u0451 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442. \u041c\u0451\u0440\u0442\u0432\u044b\u0439 \u043a\u043e\u0434, \u043f\u0430\u043c\u044f\u0442\u043d\u0438\u043a \u043f\u0435\u0440\u0432\u043e\u0439 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438.<\/p>\n<p><strong>\u0414\u0435\u0434\u0443\u043f\u043b\u0438\u043a\u0430\u0446\u0438\u044f \u043f\u043e \u0445\u044d\u0448\u0443 \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430<\/strong><\/p>\n<p>\u041f\u043e\u043b\u043e\u0432\u0438\u043d\u0430 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0440\u0430\u0437 \u0432 \u043c\u0435\u0441\u044f\u0446, \u0430 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0438 \u0436\u043c\u0443\u0442 \u00ab\u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c\u00bb \u043a\u0430\u0436\u0434\u044b\u0439 \u0434\u0435\u043d\u044c. \u041f\u043b\u043e\u0434\u0438\u0442\u044c \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0435 CSV \u043d\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c.<\/p>\n<pre><code class=\"python\">content_hash = compute_df_hash(df)         # sha256 \u043e\u0442 df.to_csv()schema_hash = compute_schema_hash(df)      # \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e: \u0438\u043c\u0435\u043d\u0430 \u043a\u043e\u043b\u043e\u043d\u043e\u043a + dtypesif (    existing_dataset    and existing_dataset.get(\"content_hash\") == content_hash    and dataset_file_is_available(existing_dataset.get(\"file_path\", \"\"))):    catalog.add_ingestion(..., message=\"Dataset unchanged; existing file reused\")    return {..., \"reused\": True}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0425\u044d\u0448 \u0441\u0445\u0435\u043c\u044b \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e: \u0435\u0441\u043b\u0438 \u0432\u0435\u0434\u043e\u043c\u0441\u0442\u0432\u043e \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043b\u043e \u043a\u043e\u043b\u043e\u043d\u043a\u0443, \u044d\u0442\u043e \u0432\u0438\u0434\u043d\u043e \u0441\u0440\u0430\u0437\u0443, \u0434\u0430\u0436\u0435 \u043a\u043e\u0433\u0434\u0430 \u0446\u0438\u0444\u0440\u044b \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0438\u0441\u044c.<br \/>\u0422\u0440\u0435\u0442\u044c\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u0435 \u2014 <code>dataset_file_is_available<\/code> \u2014 \u043f\u043e\u044f\u0432\u0438\u043b\u043e\u0441\u044c \u043f\u043e\u0441\u043b\u0435 \u0433\u0440\u0430\u0431\u043b\u0438, \u043e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043d\u0438\u0436\u0435. \u0411\u0435\u0437 \u043d\u0435\u0433\u043e \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0440\u0430\u0434\u043e\u0441\u0442\u043d\u043e \u043e\u0442\u0432\u0435\u0447\u0430\u043b\u0430 \u00ab\u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0438\u0441\u044c, \u0444\u0430\u0439\u043b \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u00bb \u0438 \u043e\u0442\u0434\u0430\u0432\u0430\u043b\u0430 \u043f\u0443\u0442\u044c \u043a \u0444\u0430\u0439\u043b\u0443, \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0434\u0430\u0432\u043d\u043e \u043d\u0435\u0442.<\/p>\n<p><strong>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u044b<\/strong><\/p>\n<p><strong>\u041a\u0430\u0432\u044b\u0447\u043a\u0438 \u0432 \u0438\u043c\u0435\u043d\u0438 \u0444\u0430\u0439\u043b\u0430<\/strong><\/p>\n<p>KASE \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u0442 \u043d\u043e\u0432\u043e\u0441\u0442\u0438 \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f\u043c\u0438 \u0432\u0440\u043e\u0434\u0435 <code>\u0410\u041e \"\u0411\u0430\u043d\u043a \u0420\u0430\u0437\u0432\u0438\u0442\u0438\u044f \u041a\u0430\u0437\u0430\u0445\u0441\u0442\u0430\u043d\u0430\" \u043f\u0440\u0438\u043d\u044f\u043b \u0440\u0435\u0448\u0435\u043d\u0438\u0435...<\/code>. \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u0430 \u0438\u0434\u0451\u0442 \u0432 \u043f\u0443\u0442\u044c. Windows \u043a\u0430\u0432\u044b\u0447\u043a\u0438 \u0432 \u0438\u043c\u0435\u043d\u0430\u0445 \u043d\u0435 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442:<\/p>\n<blockquote>\n<p>[WinError 123] \u0421\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u0432 \u0438\u043c\u0435\u043d\u0438 \u0444\u0430\u0439\u043b\u0430, \u0438\u043c\u0435\u043d\u0438 \u043f\u0430\u043f\u043a\u0438 \u0438\u043b\u0438 \u043c\u0435\u0442\u043a\u0435 \u0442\u043e\u043c\u0430:&#8217;D:\\\\&#8230;\\\\data_storage\\\\<a href=\"http:\/\/kase.kz\" rel=\"noopener nofollow\">kase.kz<\/a>\\\\KASE_Global_\u2192_\u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439_\u0430\u043a\u0446\u0438\u043e\u043d\u0435\u0440_\u0410\u041e_&#187;\u0411\u0430\u043d\u043a_\u0420\u0430\u0437\u0432\u0438\u0442\u0438\u044f_\u041a\u0430\u0437\u0430\u0445\u0441\u0442\u0430\u043d\u0430&#187;_\u043f\u0440\u0438\u043d\u044f\u043b_\u0440\u0435\u0448\u0435\u043d\u0438\u0435&#8217;<\/p>\n<\/blockquote>\n<p><strong>29 \u0443\u043f\u0430\u0432\u0448\u0438\u0445 \u0437\u0430\u0433\u0440\u0443\u0437\u043e\u043a, \u043f\u043e\u043a\u0430 \u043d\u0435 \u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0441\u0430\u043d\u0438\u0442\u0438\u0437\u0430\u0446\u0438\u0438:<\/strong><\/p>\n<pre><code class=\"python\">def sanitize_path_component(value: str, max_length: int = 120) -&gt; str:    text = str(value or \"\").strip()    text = text.replace(\"\\xa0\", \" \")                        # \u043d\u0435\u0440\u0430\u0437\u0440\u044b\u0432\u043d\u044b\u0439 \u043f\u0440\u043e\u0431\u0435\u043b \u0441 \u0433\u043e\u0441\u0441\u0430\u0439\u0442\u043e\u0432    text = re.sub(r'[&lt;&gt;:\"\/\\\\|?*\\x00-\\x1f]', \"_\", text)    text = re.sub(r\"\\s+\", \"_\", text)    text = re.sub(r\"_+\", \"_\", text)    text = text.rstrip(\" ._\")                               # Windows \u043d\u0435 \u043b\u044e\u0431\u0438\u0442 \u0442\u043e\u0447\u043a\u0443 \u0432 \u043a\u043e\u043d\u0446\u0435    reserved_names = {\"CON\", \"PRN\", \"AUX\", \"NUL\", \"COM1\", ..., \"LPT9\"}    if text.upper() in reserved_names:        text = f\"_{text}\"    return text[:max_length] or \"file\"<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0417\u0430\u0440\u0435\u0437\u0435\u0440\u0432\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0438\u043c\u0435\u043d\u0430 \u2014 \u043d\u0435 \u043f\u0430\u0440\u0430\u043d\u043e\u0439\u044f. \u0414\u0430\u0442\u0430\u0441\u0435\u0442 \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <code>CON<\/code> \u043d\u0430 Windows \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043d\u0435 \u0444\u0430\u0439\u043b, \u0430 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043a \u043a\u043e\u043d\u0441\u043e\u043b\u0438.<\/p>\n<p><strong>118 \u043c\u0438\u043b\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434 \u043d\u0430 \u043a\u0430\u0436\u0434\u0443\u044e \u0441\u0442\u0440\u043e\u0447\u043a\u0443 \u0438\u0441\u0442\u043e\u0440\u0438\u0438<\/strong><\/p>\n<p>\u041a\u0430\u0442\u0430\u043b\u043e\u0433 \u0441\u0435\u0439\u0447\u0430\u0441 \u0432\u0435\u0441\u0438\u0442 6.33 \u041c\u0411. \u041a\u0430\u0436\u0434\u044b\u0439 \u0432\u044b\u0437\u043e\u0432 <code>add_ingestion<\/code> \u2014 \u044d\u0442\u043e \u043f\u043e\u043b\u043d\u0430\u044f \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f, \u0431\u044d\u043a\u0430\u043f \u0438 \u0434\u0432\u0430 fsync. \u0417\u0430\u043c\u0435\u0440 \u043d\u0430 \u043a\u043e\u043f\u0438\u0438 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430, 30 \u0432\u044b\u0437\u043e\u0432\u043e\u0432 \u043f\u043e\u0434\u0440\u044f\u0434:<\/p>\n<blockquote>\n<p>load_s 0.063add_ingestion ms p50 117.7 p95 122.7save_peak_MB 29.4file_MB 6.33<\/p>\n<\/blockquote>\n<p>\u0418\u0437 \u044d\u0442\u0438\u0445 118 \u043c\u0441 \u043e\u043a\u043e\u043b\u043e 56 \u0443\u0445\u043e\u0434\u0438\u0442 \u043d\u0430 <code>json.dumps(..., indent=2)<\/code>, \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u2014 \u0437\u0430\u043f\u0438\u0441\u044c \u0431\u044d\u043a\u0430\u043f\u0430 \u0438 fsync. \u041f\u0438\u043a\u043e\u0432\u0430\u044f \u043f\u0430\u043c\u044f\u0442\u044c \u043d\u0430 \u043e\u0434\u043d\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u2014 29 \u041c\u0411, \u043f\u043e\u0447\u0442\u0438 \u0432 4.6 \u0440\u0430\u0437\u0430 \u0431\u043e\u043b\u044c\u0448\u0435 \u0441\u0430\u043c\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430.<\/p>\n<p>\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043e\u0434\u043d\u043e\u0433\u043e \u043d\u043e\u0432\u043e\u0433\u043e \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u0430 \u2014 \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0434\u0432\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f (<code>add_dataset<\/code> + <code>add_ingestion<\/code>), \u0430 \u0435\u0441\u043b\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u0430\u044f, \u0442\u043e \u0435\u0449\u0451 \u0438 <code>update_dataset<\/code>. \u0414\u043b\u044f 1789 \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u043e\u0432 \u044d\u0442\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0441\u0435\u043c\u044c \u043c\u0438\u043d\u0443\u0442 \u0447\u0438\u0441\u0442\u043e\u0439 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0438\u0441\u0438 JSON. \u0418 \u0441 \u043a\u0430\u0436\u0434\u044b\u043c \u0438\u043d\u0433\u0435\u0441\u0442\u043e\u043c \u0444\u0430\u0439\u043b \u0440\u0430\u0441\u0442\u0451\u0442, \u0442\u0430\u043a \u0447\u0442\u043e \u0434\u0430\u043b\u044c\u0448\u0435 \u0431\u0443\u0434\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u0435\u0435 \u2014 O(n) \u043d\u0430 \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u0447\u0438\u0441\u0442\u043e\u043c \u0432\u0438\u0434\u0435.<\/p>\n<p><strong>\u0412\u0430\u043b\u0438\u0434\u0430\u0442\u043e\u0440 \u0441\u0441\u044b\u043b\u043e\u043a \u0441 \u043b\u043e\u0436\u043d\u044b\u043c\u0438 \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043d\u0438\u044f\u043c\u0438<\/strong><\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 discover \u0431\u0438\u0442\u044b\u0435 \u0441\u0441\u044b\u043b\u043a\u0438 \u043e\u0442\u0441\u0435\u0438\u0432\u0430\u044e\u0442\u0441\u044f: HEAD, \u0435\u0441\u043b\u0438 \u043d\u0435 \u0432\u044b\u0448\u043b\u043e \u2014 GET \u0441\u043e <code>stream=True<\/code>. \u041e\u0442\u0432\u0435\u0442 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u0431\u0438\u0442\u044b\u043c, \u0435\u0441\u043b\u0438 \u0432 \u043f\u0435\u0440\u0432\u044b\u0445 400 \u0441\u0438\u043c\u0432\u043e\u043b\u0430\u0445 \u0435\u0441\u0442\u044c <code>\"not found\"<\/code> \u0438\u043b\u0438 <code>\"exception\"<\/code>.<\/p>\n<p>\u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u043f\u043e\u043a\u0430 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u0440\u0430\u0437\u0434\u0435\u043b\u0430 \u043d\u0435\u0442 \u043d\u043e\u0432\u043e\u0441\u0442\u0438 \u0441\u043e \u0441\u043b\u043e\u0432\u043e\u043c \u00abexception\u00bb \u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0443 KASE \u0438 custom URL \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0430 \u0444\u043b\u0430\u0433\u043e\u043c <code>validate_discovered_links = False<\/code>. \u041f\u043b\u044e\u0441 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0438\u0434\u0451\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u0441 \u0442\u0430\u0439\u043c\u0430\u0443\u0442\u043e\u043c 12 \u0441\u0435\u043a\u0443\u043d\u0434 \u0438 \u0442\u0440\u0435\u043c\u044f \u0440\u0435\u0442\u0440\u0430\u044f\u043c\u0438, \u0442\u0430\u043a \u0447\u0442\u043e \u0441\u043e\u0442\u043d\u044f \u043c\u0451\u0440\u0442\u0432\u044b\u0445 \u0441\u0441\u044b\u043b\u043e\u043a \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442 discover \u0432 \u043f\u0435\u0440\u0435\u043a\u0443\u0440.<\/p>\n<p><strong>\u0421\u0431\u0440\u043e\u0441 \u043a\u044d\u0448\u0430 \u0447\u0435\u0440\u0435\u0437 \u0441\u0442\u0430\u0440\u0442\u0430\u043f<\/strong><\/p>\n<p>\u0412 \u043d\u0430\u0447\u0430\u043b\u0435 <code>api.py<\/code> \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0432\u043e\u0442 \u0442\u0430\u043a\u043e\u0435:<\/p>\n<pre><code class=\"python\">catalog.delete_discovery(\"food_inputs_kz\")catalog.delete_discovery(\"stat.gov.kz\")catalog.delete_discovery(\"ecb_cis_banks\")# ...\u0435\u0449\u0451 \u0434\u0435\u0432\u044f\u0442\u044c \u0448\u0442\u0443\u043acatalog.purge_datasets_by_external_ids([\"kgd_taxpayer\"])catalog.purge_ingestions_by_error_substrings([\"kgd.gov.kz\"])<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u042d\u0442\u043e \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0431\u0435\u0434\u043d\u043e\u0433\u043e \u0447\u0435\u043b\u043e\u0432\u0435\u043a\u0430. \u041a\u043e\u0433\u0434\u0430 \u044f \u043c\u0435\u043d\u044f\u043b \u043b\u043e\u0433\u0438\u043a\u0443 \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440\u0430, \u0441\u0442\u0430\u0440\u044b\u0439 \u043a\u044d\u0448 discover \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0441\u044f \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u043c, \u0438 \u043f\u0440\u043e\u0449\u0435 \u0432\u0441\u0435\u0433\u043e \u0431\u044b\u043b\u043e \u0434\u0440\u043e\u043f\u0430\u0442\u044c \u0435\u0433\u043e \u043f\u0440\u0438 \u0441\u0442\u0430\u0440\u0442\u0435. \u041a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440 \u043a <a href=\"http:\/\/kgd.gov.kz\" rel=\"noopener nofollow\">kgd.gov.kz<\/a> \u0432\u044b\u043f\u0438\u043b\u0438\u043b\u0438 \u0446\u0435\u043b\u0438\u043a\u043e\u043c, \u0430 \u0435\u0433\u043e \u0441\u043b\u0435\u0434\u044b \u0434\u043e \u0441\u0438\u0445 \u043f\u043e\u0440 \u0432\u044b\u0447\u0438\u0449\u0430\u044e\u0442\u0441\u044f \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435. \u041d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u2014 \u0432\u0435\u0440\u0441\u0438\u044f \u0441\u0445\u0435\u043c\u044b \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440\u0430 \u0432 \u043a\u043b\u044e\u0447\u0435 \u043a\u044d\u0448\u0430. \u0421\u0434\u0435\u043b\u0430\u044e.<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<td data-colwidth=\"258\" width=\"258\">\n<p align=\"left\">\u041c\u0435\u0442\u0440\u0438\u043a\u0430<\/p>\n<\/td>\n<td data-colwidth=\"246\" width=\"246\">\n<p align=\"left\">\u0417\u043d\u0430\u0447\u0435\u043d\u0438\u0435<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"258\" width=\"258\">\n<p align=\"left\">\u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432 \u0432 \u0440\u0435\u0435\u0441\u0442\u0440\u0435 \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440\u043e\u0432<\/p>\n<\/td>\n<td data-colwidth=\"246\" width=\"246\">\n<p align=\"left\">16<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"258\" width=\"258\">\n<p align=\"left\">\u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432 \u0432 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435 (\u0441 custom URL)<\/p>\n<\/td>\n<td data-colwidth=\"246\" width=\"246\">\n<p align=\"left\">32<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"258\" width=\"258\">\n<p align=\"left\">\u0414\u0430\u0442\u0430\u0441\u0435\u0442\u043e\u0432 \u0432 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435<\/p>\n<\/td>\n<td data-colwidth=\"246\" width=\"246\">\n<p align=\"left\">1 789<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"258\" width=\"258\">\n<p align=\"left\">\u0421\u0442\u0440\u043e\u043a \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u0443\u043c\u043c\u0430\u0440\u043d\u043e<\/p>\n<\/td>\n<td data-colwidth=\"246\" width=\"246\">\n<p align=\"left\">~2.76 \u043c\u043b\u043d<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"258\" width=\"258\">\n<p align=\"left\">\u0424\u043e\u0440\u043c\u0430\u0442\u044b<\/p>\n<\/td>\n<td data-colwidth=\"246\" width=\"246\">\n<p align=\"left\">CSV 1180, HTML 435, JSON 105, HTML-\u0442\u0430\u0431\u043b\u0438\u0446\u044b 43, PDF 23, XML 3<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"258\" width=\"258\">\n<p align=\"left\">\u0418\u043d\u0433\u0435\u0441\u0442\u043e\u0432 \u0432\u0441\u0435\u0433\u043e<\/p>\n<\/td>\n<td data-colwidth=\"246\" width=\"246\">\n<p align=\"left\">2 918<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"258\" width=\"258\">\n<p align=\"left\">\u0423\u0441\u043f\u0435\u0448\u043d\u044b\u0445<\/p>\n<\/td>\n<td data-colwidth=\"246\" width=\"246\">\n<p align=\"left\">2 522 (86.4%)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"258\" width=\"258\">\n<p align=\"left\">\u0423\u043f\u0430\u0432\u0448\u0438\u0445<\/p>\n<\/td>\n<td data-colwidth=\"246\" width=\"246\">\n<p align=\"left\">396 (13.6%)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"258\" width=\"258\">\n<p align=\"left\">\u041f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043e \u043f\u043e \u0445\u044d\u0448\u0443<\/p>\n<\/td>\n<td data-colwidth=\"246\" width=\"246\">\n<p align=\"left\">313<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"258\" width=\"258\">\n<p align=\"left\">\u0420\u0430\u0437\u043c\u0435\u0440 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430<\/p>\n<\/td>\n<td data-colwidth=\"246\" width=\"246\">\n<p align=\"left\">6.33 \u041c\u0411<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"258\" width=\"258\">\n<p align=\"left\">\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430 \u043f\u0440\u0438 \u0441\u0442\u0430\u0440\u0442\u0435<\/p>\n<\/td>\n<td data-colwidth=\"246\" width=\"246\">\n<p align=\"left\">63 \u043c\u0441<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"258\" width=\"258\">\n<p align=\"left\">\u0417\u0430\u043f\u0438\u0441\u044c \u0432 \u043a\u0430\u0442\u0430\u043b\u043e\u0433, p50 \/ p95<\/p>\n<\/td>\n<td data-colwidth=\"246\" width=\"246\">\n<p align=\"left\">117.7 \/ 122.7 \u043c\u0441<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"258\" width=\"258\">\n<p align=\"left\">\u041f\u0438\u043a\u043e\u0432\u0430\u044f \u043f\u0430\u043c\u044f\u0442\u044c \u043d\u0430 \u043e\u0434\u043d\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435<\/p>\n<\/td>\n<td data-colwidth=\"246\" width=\"246\">\n<p align=\"left\">29.4 \u041c\u0411<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"258\" width=\"258\">\n<p align=\"left\">Python-\u043a\u043e\u0434\u0430<\/p>\n<\/td>\n<td data-colwidth=\"246\" width=\"246\">\n<p align=\"left\">~9.4 \u0442\u044b\u0441. \u0441\u0442\u0440\u043e\u043a<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u0418\u0437 \u0447\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u0442 396 \u043f\u0430\u0434\u0435\u043d\u0438\u0439:<\/p>\n<pre><code class=\"python\">131 | Structured source could not be parsed as xlsx 81 | Structured source could not be parsed as json 52 | Structured source could not be parsed as csv 36 | Structured source could not be parsed as xls 32 | This source only links to an informational page and has no structured dataset 29 | [WinError 123] \u0421\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u0432 \u0438\u043c\u0435\u043d\u0438 \u0444\u0430\u0439\u043b\u0430...  7 | No nested xlsx\/xls\/csv\/json resources found on price statistics page  5 | `Import lxml` failed.  3 | 504 Server Error: Gateway Time-out (FRED)  1 | 'DataFrame' object has no attribute 'dtype'<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u041b\u0438\u0434\u0435\u0440 \u2014 xlsx. \u041f\u043e\u0434\u043e\u0437\u0440\u0435\u0432\u0430\u044e, \u0447\u0442\u043e \u0447\u0430\u0441\u0442\u044c \u044d\u0442\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u0435\u0432 \u2014 \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 Excel: \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 <code>PK\\x03\\x04<\/code> \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043d\u0430 \u043b\u044e\u0431\u043e\u0439 zip, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0430\u0440\u0445\u0438\u0432\u044b \u0441 CSV \u0432\u043d\u0443\u0442\u0440\u0438 \u0438 <code>.docx<\/code>. \u041c\u0430\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0431\u0430\u0439\u0442\u044b \u0433\u043e\u0432\u043e\u0440\u044f\u0442, \u0447\u0442\u043e \u044d\u0442\u043e \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440, \u043d\u043e \u043d\u0435 \u0433\u043e\u0432\u043e\u0440\u044f\u0442, \u0447\u0442\u043e \u0432 \u043d\u0451\u043c \u043b\u0435\u0436\u0438\u0442. <\/p>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0448\u0430\u0433 \u2014 \u0437\u0430\u0433\u043b\u044f\u0434\u044b\u0432\u0430\u0442\u044c \u0432 <code>[Content_Types].xml<\/code>.\u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0446\u0438\u0444\u0440\u0430 \u0434\u043b\u044f \u0431\u0438\u0437\u043d\u0435\u0441\u0430 \u0434\u0440\u0443\u0433\u0430\u044f: \u043f\u043e\u043d\u0435\u0434\u0435\u043b\u044c\u043d\u0438\u0447\u043d\u044b\u0439 \u0440\u0438\u0442\u0443\u0430\u043b \u043d\u0430 \u0434\u0432\u0430 \u0447\u0430\u0441\u0430 \u0438\u0441\u0447\u0435\u0437. \u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u0444\u0440\u043e\u043d\u0442, \u0436\u043c\u0451\u0442 \u00ab\u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c\u00bb \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 CSV, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u2014 \u044d\u0442\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438, \u0430 \u043d\u0435 \u00ab\u0411\u044e\u0440\u043e \u043d\u0430\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438\u00bb.<\/p>\n<p><strong>\u0427\u0442\u043e \u0434\u0430\u043b\u044c\u0448e<\/strong><\/p>\n<ol>\n<li>\n<p><code>pip install xlrd<\/code> \u0438 \u0443\u0434\u0430\u043b\u0438\u0442\u044c COM-\u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u044e. \u0412\u043e\u043e\u0431\u0449\u0435.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0443\u0442\u0438 \u0432 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u043a\u0430\u0442\u0430\u043b\u043e\u0433 \u0432 Postgres \u2014 \u043c\u043e\u0434\u0435\u043b\u0438 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c, \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c. JSON \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043a\u0430\u043a \u0444\u043e\u0440\u043c\u0430\u0442 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0442\u043e\u043a\u043e\u0432\u044b\u0439 \u0445\u044d\u0448 \u0438 \u043e\u0434\u043d\u0430 \u0437\u0430\u043f\u0438\u0441\u044c CSV \u0432\u043c\u0435\u0441\u0442\u043e \u0442\u0440\u0451\u0445 \u043a\u043e\u043f\u0438\u0439 \u0432 \u043f\u0430\u043c\u044f\u0442\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0412\u0435\u0440\u0441\u0438\u044f \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440\u0430 \u0432 \u043a\u043b\u044e\u0447\u0435 \u043a\u044d\u0448\u0430 discover \u0432\u043c\u0435\u0441\u0442\u043e <code>delete_discovery<\/code> \u043f\u0440\u0438 \u0441\u0442\u0430\u0440\u0442\u0435.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u0441\u044b\u043b\u043e\u043a.<\/p>\n<\/li>\n<\/ol>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u0442\u043e\u0436\u0435 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0441 \u0433\u043e\u0441\u0441\u0430\u0439\u0442\u043e\u0432 \u0421\u041d\u0413 \u2014 \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0438\u0442\u0435 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445, \u043a\u0430\u043a\u043e\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u043e\u0442\u0434\u0430\u044e\u0442 \u0443 \u0432\u0430\u0441. \u0421\u0442\u0430\u0432\u043b\u044e \u043d\u0430 HTML \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\u043c <code>.xls<\/code><\/p>\n<\/div>\n<p>\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\/1104370\/\">https:\/\/habr.com\/ru\/articles\/1104370\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u041e\u0442\u0434\u0435\u043b \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0438 FMCG-\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u043f\u043e\u043d\u0435\u0434\u0435\u043b\u044c\u043d\u0438\u043a \u043d\u0430\u0447\u0438\u043d\u0430\u043b \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e: \u0447\u0435\u043b\u043e\u0432\u0435\u043a \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u043b stat.gov.kz, \u043a\u0430\u0447\u0430\u043b \u043f\u0430\u0447\u043a\u0443 Excel-\u0442\u0430\u0431\u043b\u0438\u0446, \u043f\u043e\u0442\u043e\u043c \u0448\u0451\u043b \u043d\u0430 \u0441\u0430\u0439\u0442 \u041d\u0430\u0446\u0431\u0430\u043d\u043a\u0430 \u0437\u0430 \u043a\u0443\u0440\u0441\u0430\u043c\u0438, \u043f\u043e\u0442\u043e\u043c \u043d\u0430 KASE, \u043f\u043e\u0442\u043e\u043c \u0437\u0430 \u043c\u0438\u0440\u043e\u0432\u044b\u043c\u0438 \u0446\u0435\u043d\u0430\u043c\u0438 \u043d\u0430 \u0441\u0430\u0445\u0430\u0440 \u0438 \u043a\u0430\u043a\u0430\u043e \u043a FAO. \u0427\u0430\u0441\u0430 \u0447\u0435\u0440\u0435\u0437 \u0434\u0432\u0430 \u0432\u0441\u0451 \u044d\u0442\u043e \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u043b\u043e\u0441\u044c \u0432 \u043e\u0431\u0449\u0435\u0439 \u043f\u0430\u043f\u043a\u0435 \u043f\u043e\u0434 \u0438\u043c\u0435\u043d\u0430\u043c\u0438 \u0432\u0440\u043e\u0434\u0435 data(1).xlsx\u0418 \u043c\u043d\u0435 \u0441\u043a\u0430\u0437\u0430\u043b\u0438 &#171;\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u0443\u0439&#187;. \u0414\u0430\u043b\u0438 \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u0430\u0439\u0442\u043e\u0439 \u043e\u0442\u043a\u0443\u0434\u0430 \u043e\u043d\u0438 \u0431\u0435\u0440\u0443\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0421\u043f\u0438\u0441\u043e\u043a \u0431\u044b\u043b \u0442\u0430\u043a\u043e\u0432, \u043d\u043e \u043e\u043d \u0440\u043e\u0441 \u043f\u043e \u0445\u043e\u0434\u0443:\u041a\u0430\u0437\u0430\u0445\u0441\u0442\u0430\u043d: stat.gov.kz (\u0411\u044e\u0440\u043e \u043d\u0430\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438), KASE, \u041d\u0430\u0446\u0431\u0430\u043d\u043a, goszakup.gov.kz, adilet.zan.kz \u2014 \u0442\u0430\u043c \u0437\u0430\u043a\u043e\u043d\u044b, \u0438\u0445 \u0442\u043e\u0436\u0435 \u0437\u0430\u0445\u043e\u0442\u0435\u043b\u0438, \u043f\u0440\u0438\u0447\u0451\u043c \u0441 \u0440\u0430\u0437\u0431\u0438\u0432\u043a\u043e\u0439 \u043f\u043e \u0441\u0442\u0430\u0442\u044c\u044f\u043c;\u0441\u044b\u0440\u044c\u0451 \u0438 \u0435\u0434\u0430: FAOSTAT, UN Comtrade, UNdata \u2014 \u043b\u0438\u043c\u043e\u043d\u043d\u0430\u044f \u043a\u0438\u0441\u043b\u043e\u0442\u0430, \u043a\u043e\u0444\u0435\u0438\u043d, \u0447\u0451\u0440\u043d\u044b\u0439 \u0447\u0430\u0439. \u0440\u044f\u0434\u044b FRED \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 BLS;\u0444\u0438\u043d\u0430\u043d\u0441\u044b: ECB SDMX API, \u0426\u0411 \u0441\u043e\u0441\u0435\u0434\u0435\u0439, MOEX ISS, \u043c\u0438\u0440\u043e\u0432\u044b\u0435 \u0438\u043d\u0434\u0435\u043a\u0441\u044b \u0438 \u0444\u044c\u044e\u0447\u0435\u0440\u0441\u044b;World Bank (\u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440\u044b, LPI), Open-Meteo \u043f\u043e \u0433\u043e\u0440\u043e\u0434\u0430\u043c \u041a\u0430\u0437\u0430\u0445\u0441\u0442\u0430\u043d\u0430.\u041f\u0435\u0440\u0432\u0430\u044f \u043c\u044b\u0441\u043b\u044c \u0431\u044b\u043b\u0430 \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e\u0439: Airbyte, Meltano, \u0447\u0442\u043e-\u043d\u0438\u0431\u0443\u0434\u044c \u043d\u0430 Singer-\u0442\u0430\u043f\u0430\u0445. \u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043b. \u041a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440\u043e\u0432 \u043a stat.gov.kz, KASE \u0438\u043b\u0438 \u0430\u0434\u0438\u043b\u0435\u0442\u0443 \u0442\u0430\u043c \u043d\u0435\u0442 \u0438 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442, \u0430 \u0438\u0445 \u0442\u0443\u0442 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e. \u041f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0431\u044b \u0432 \u043b\u044e\u0431\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0442\u043e\u043b\u044c\u043a\u043e \u0443\u0436\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 \u0447\u0443\u0436\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u2014 \u0438 \u0442\u0430\u0449\u0438\u0442\u044c \u0440\u0430\u0434\u0438 \u044d\u0442\u043e\u0433\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0441 \u043e\u0440\u043a\u0435\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u043e\u043c.CKAN \u0438 \u043f\u0440\u043e\u0447\u0438\u0435 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0440\u0435\u0448\u0430\u044e\u0442 \u0434\u0440\u0443\u0433\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443. \u041e\u043d\u0438 \u0445\u0440\u0430\u043d\u044f\u0442 \u0438 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442, \u043d\u043e \u043d\u0435 \u0432\u044b\u043a\u043e\u0432\u044b\u0440\u0438\u0432\u0430\u044e\u0442 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0438\u0437 HTML-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0433\u043e\u0441\u0441\u0430\u0439\u0442\u0430, \u0433\u0434\u0435 \u00ab\u0441\u043a\u0430\u0447\u0430\u0442\u044c\u00bb \u2014 \u044d\u0442\u043e &lt;a&gt; \u0431\u0435\u0437 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f, \u043e\u0442\u0434\u0430\u044e\u0449\u0438\u0439 .xls, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 HTML.ImportError: Import lxml failed.  Use pip or conda to install the lxml package.\u042d\u0442\u043e, \u043a\u0441\u0442\u0430\u0442\u0438, \u043d\u0435 \u0432\u044b\u0434\u0443\u043c\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430: \u043e\u043d\u0430 \u043f\u044f\u0442\u044c \u0440\u0430\u0437 \u043b\u0435\u0436\u0438\u0442 \u0432 \u0436\u0443\u0440\u043d\u0430\u043b\u0435 \u0438\u043d\u0433\u0435\u0441\u0442\u043e\u0432. \u041f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c lxml \u043c\u043e\u0436\u043d\u043e, \u043d\u043e \u044f \u043a \u0442\u043e\u043c\u0443 \u043c\u043e\u043c\u0435\u043d\u0442\u0443 \u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0441\u0432\u043e\u0439 \u0440\u0430\u0437\u0431\u043e\u0440 \u0442\u0430\u0431\u043b\u0438\u0446 \u043d\u0430 BeautifulSoup \u2014 \u0441 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439 &lt;th&gt; \u0438 \u0441\u0442\u0440\u043e\u043a \u0440\u0430\u0437\u043d\u043e\u0439 \u0434\u043b\u0438\u043d\u044b. \u0422\u0430\u043a \u0438 \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c.\u041a\u043e\u0440\u043e\u0447\u0435, \u043f\u0438\u0441\u0430\u043b \u0441\u0430\u043c.\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0437\u0430 30 \u0441\u0435\u043a\u0443\u043d\u0434\u0423 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440\u0430 \u0442\u0440\u0438 \u043c\u0435\u0442\u043e\u0434\u0430:class BaseConnector(ABC):    source_name: str = &#171;unknown&#187;    source_type: str = &#171;web_api&#187;    @abstractmethod    def discover(self) -&gt; list[DiscoveredDataset]: &#8230;   # \u0447\u0442\u043e \u0432\u043e\u043e\u0431\u0449\u0435 \u0435\u0441\u0442\u044c \u043d\u0430 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0435    @abstractmethod    def fetch(self, dataset: DiscoveredDataset) -&gt; bytes: &#8230;   # \u0441\u044b\u0440\u044b\u0435 \u0431\u0430\u0439\u0442\u044b    @abstractmethod    def fetch_as_dataframe(self, dataset: DiscoveredDataset): &#8230;   # \u0435\u0441\u043b\u0438 \u043f\u043e\u0432\u0435\u0437\u0451\u0442 \u2014 \u0441\u0440\u0430\u0437\u0443 \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u041f\u0430\u0439\u043f\u043b\u0430\u0439\u043d \u0434\u0432\u0443\u0445\u0444\u0430\u0437\u043d\u044b\u0439. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 discover: \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440 \u043e\u0431\u0445\u043e\u0434\u0438\u0442 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0431\u0440\u0430\u0442\u044c. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u043e \u0444\u0440\u043e\u043d\u0442\u0435 \u0441\u0442\u0430\u0432\u0438\u0442 \u0433\u0430\u043b\u043e\u0447\u043a\u0438. \u041f\u043e\u0442\u043e\u043c ingest: \u0437\u0430\u0431\u0438\u0440\u0430\u0435\u043c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0435, \u043a\u043b\u0430\u0434\u0451\u043c \u0432 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435, \u043f\u0438\u0448\u0435\u043c \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u043a\u0430\u0442\u0430\u043b\u043e\u0433.\u0420\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u044f\u0432\u0438\u043b\u043e\u0441\u044c \u043d\u0435 \u043e\u0442 \u043b\u044e\u0431\u0432\u0438 \u043a \u043a\u0440\u0430\u0441\u043e\u0442\u0435. Discover \u0443 KASE \u2014 \u044d\u0442\u043e 16 \u0440\u0430\u0437\u0434\u0435\u043b\u043e\u0432 \u0441\u0430\u0439\u0442\u0430 \u0441 \u043f\u0430\u0443\u0437\u043e\u0439 0.4 \u0441\u0435\u043a\u0443\u043d\u0434\u044b \u043c\u0435\u0436\u0434\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0441\u043b\u043e\u0432\u0438\u0442\u044c \u0431\u0430\u043d. \u0413\u043e\u043d\u044f\u0442\u044c \u0435\u0433\u043e \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u043b\u0438\u043a \u043d\u0438\u043a\u0442\u043e \u043d\u0435 \u0431\u0443\u0434\u0435\u0442.def make_session(verify_ssl: bool = False) -&gt; requests.Session:    s = requests.Session()    s.trust_env = False      # \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u043f\u0440\u043e\u043a\u0441\u0438 \u0438\u0437 env \u043b\u043e\u043c\u0430\u043b \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432    s.verify = verify_ssl    # \u0434\u0430, SSL \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d. \u0441\u043c. \u043d\u0438\u0436\u0435    retry = Retry(        total=3, connect=3, read=3, status=3,        backoff_factor=0.6,        status_forcelist=(429, 500, 502, 503, 504),        allowed_methods=(&#171;GET&#187;, &#171;HEAD&#187;, &#171;OPTIONS&#187;),        raise_on_status=False,    )    adapter = HTTPAdapter(max_retries=retry, pool_connections=20, pool_maxsize=20)    s.mount(&#171;http:\/\/&#187;, adapter)    s.mount(&#171;https:\/\/&#187;, adapter)verify=False \u2014 \u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0438\u0441\u0441, \u0437\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043d\u0435 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0441\u0442\u044b\u0434\u043d\u043e. \u0427\u0430\u0441\u0442\u044c \u0433\u043e\u0441\u0443\u0434\u0430\u0440\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0441\u0430\u0439\u0442\u043e\u0432 \u043e\u0442\u0434\u0430\u0451\u0442 \u043a\u0440\u0438\u0432\u0443\u044e \u0446\u0435\u043f\u043e\u0447\u043a\u0443 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0432, \u0438 \u0441 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u043e\u0439 \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440 \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u0441\u0442\u0430\u0440\u0442\u0443\u0435\u0442. \u0427\u0438\u0442\u0430\u0435\u043c \u043c\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u043d\u0438\u0447\u0435\u0433\u043e \u0441\u0435\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u043d\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b, \u0447\u0442\u043e \u044d\u0442\u043e \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u043e. \u041d\u043e \u0432 \u043f\u0440\u043e\u0434\u0435 \u0441 \u0447\u0443\u0432\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u044f \u0431\u044b \u0442\u0430\u043a \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435 \u0441\u0442\u0430\u043b.\u0420\u0435\u0442\u0440\u0430\u0438 \u043d\u0430 5xx \u0441\u043f\u0430\u0441\u0430\u044e\u0442 \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e. FRED, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0438\u043d\u043e\u0433\u0434\u0430 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0442\u0430\u043a:504 Server Error: Gateway Time-out for url: https:\/\/fred.stlouisfed.org\/graph\/fredgraph.csv?id=WPU057\u0422\u0440\u0438 \u0442\u0430\u043a\u0438\u0445 \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0436\u0443\u0440\u043d\u0430\u043b\u0435 \u2014 \u044d\u0442\u043e \u0443\u0436\u0435 \u043f\u043e\u0441\u043b\u0435 \u0442\u0440\u0451\u0445 \u0440\u0435\u0442\u0440\u0430\u0435\u0432 \u0441 \u0431\u044d\u043a\u043e\u0444\u0444\u043e\u043c. \u0411\u0435\u0437 \u043d\u0438\u0445 \u0438\u0445 \u0431\u044b\u043b\u043e \u0431\u044b \u0437\u0430\u043c\u0435\u0442\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0435.\u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430: \u0432\u0435\u0440\u0438\u0442\u044c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044e \u0444\u0430\u0439\u043b\u0430 \u043d\u0435\u043b\u044c\u0437\u044f. \u0418 Content-Type \u0442\u043e\u0436\u0435. \u0413\u043e\u0441\u0441\u0430\u0439\u0442\u044b \u043e\u0442\u0434\u0430\u044e\u0442 .xlsx, \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0441\u0442\u0430\u0440\u044b\u0439 OLE-\u0444\u043e\u0440\u043c\u0430\u0442, \u0438\u043b\u0438 application\/octet-stream \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0430 \u0432\u0441\u0451 \u043f\u043e\u0434\u0440\u044f\u0434.\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0444\u043e\u0440\u043c\u0430\u0442 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e \u043c\u0430\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u0431\u0430\u0439\u0442\u0430\u043c, \u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0442\u043e\u043c \u043f\u043e \u0438\u043c\u0435\u043d\u0438:def detect_data_format(name: str = &#171;&#187;, content_type: str = &#171;&#187;, payload: bytes | None = None) -&gt; str:    &#8230;    leading = payload[:16]    if leading.startswith(b&#187;PK\\x03\\x04&#8243;):                          # zip-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u2192 xlsx        return &#171;xlsx&#187;    if leading.startswith(b&#187;\\xd0\\xcf\\x11\\xe0\\xa1\\xb1\\x1a\\xe1&#8243;):    # OLE2 \u2192 \u0441\u0442\u0430\u0440\u044b\u0439 xls        return &#171;xls&#187;    if leading.startswith(b&#187;PAR1&#8243;):        return &#171;parquet&#187;    if lower_name.endswith(&#171;.csv&#187;) or &#171;csv&#187; in lower_type:        return &#171;csv&#187;\u0410 \u043f\u0440\u0438 \u0441\u0442\u0430\u0440\u0442\u0435 \u0431\u044d\u043a\u0435\u043d\u0434 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u043f\u043e \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0443 \u0438 \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u044b\u0432\u0430\u0435\u0442 \u0444\u0430\u0439\u043b\u044b, \u0443 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u043d\u0435 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0435\u0442 \u0441 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c (repair_file_extensions_by_content). \u041a\u043e\u0441\u0442\u044b\u043b\u044c? \u0414\u0430. \u041d\u043e openpyxl, \u043f\u043e\u043b\u0443\u0447\u0438\u0432\u0448\u0438\u0439 OLE-\u0444\u0430\u0439\u043b \u043f\u043e\u0434 \u0438\u043c\u0435\u043d\u0435\u043c .xlsx, \u043f\u0430\u0434\u0430\u0435\u0442 \u0441 \u0442\u0430\u043a\u043e\u0439 \u043e\u0448\u0438\u0431\u043a\u043e\u0439, \u0447\u0442\u043e \u043f\u043e \u043d\u0435\u0439 \u043d\u0435 \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u0439\u043c\u0451\u0448\u044c, \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e.\u0421 CSV \u0441\u0432\u043e\u044f \u043f\u0435\u0441\u043d\u044f. \u0420\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u044c \u0431\u044b\u0432\u0430\u0435\u0442 \u0437\u0430\u043f\u044f\u0442\u043e\u0439, \u0442\u043e\u0447\u043a\u043e\u0439 \u0441 \u0437\u0430\u043f\u044f\u0442\u043e\u0439 \u0438\u043b\u0438 \u0442\u0430\u0431\u043e\u043c, \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0430 \u2014 UTF-8 \u0441 BOM, \u0431\u0435\u0437 BOM \u0438\u043b\u0438 cp1251. \u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u0442\u0443\u043f\u043e\u0435 \u0438 \u0440\u0430\u0431\u043e\u0447\u0435\u0435 \u2014 \u043f\u0435\u0440\u0435\u0431\u043e\u0440:def decode_bytes(data: bytes) -&gt; str:    for encoding in (&#171;utf-8-sig&#187;, &#171;utf-8&#187;, &#171;cp1251&#187;, &#171;latin-1&#187;):        try:            return data.decode(encoding)        except UnicodeDecodeError:            continue    return data.decode(&#171;utf-8&#8243;, errors=&#187;replace&#187;)attempts.extend([    {&#171;sep&#187;: &#171;,&#187;,  &#171;engine&#187;: &#171;python&#187;},    {&#171;sep&#187;: &#171;;&#187;,  &#171;engine&#187;: &#171;python&#187;},    {&#171;sep&#187;: &#171;\\t&#187;, &#171;engine&#187;: &#171;python&#187;},    {&#171;sep&#187;: None, &#171;engine&#187;: &#171;python&#187;},   # \u043f\u0443\u0441\u0442\u044c csv.Sniffer \u0433\u0430\u0434\u0430\u0435\u0442    # \u0438 \u0442\u0435 \u0436\u0435 \u0447\u0435\u0442\u044b\u0440\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u0441 on_bad_lines=&#187;skip&#187; \u2014 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0440\u0443\u0431\u0435\u0436])latin-1 \u0432 \u043a\u043e\u043d\u0446\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 \u0434\u0435\u043a\u043e\u0434\u0438\u0440\u0443\u0435\u0442 \u0432\u043e\u043e\u0431\u0449\u0435 \u0447\u0442\u043e \u0443\u0433\u043e\u0434\u043d\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u043e errors=&#187;replace&#187; \u0434\u0435\u043b\u043e \u043e\u0431\u044b\u0447\u043d\u043e \u043d\u0435 \u0434\u043e\u0445\u043e\u0434\u0438\u0442. \u0417\u0430\u0442\u043e \u0435\u0441\u043b\u0438 \u0444\u0430\u0439\u043b \u0431\u044b\u043b \u0432 cp1251, \u0430 utf-8 \u0432\u0434\u0440\u0443\u0433 \u043f\u0440\u043e\u0448\u0451\u043b (\u0431\u044b\u0432\u0430\u0435\u0442 \u043d\u0430 \u043a\u043e\u0440\u043e\u0442\u043a\u0438\u0445 \u0444\u0430\u0439\u043b\u0430\u0445 \u0438\u0437 \u043e\u0434\u043d\u043e\u0439 \u043b\u0430\u0442\u0438\u043d\u0438\u0446\u044b), \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043a\u0440\u0430\u0441\u0438\u0432\u044b\u0435 \u043a\u0440\u0430\u043a\u043e\u0437\u044f\u0431\u0440\u044b. \u041b\u043e\u0432\u0438\u043b \u043f\u0430\u0440\u0443 \u0440\u0430\u0437.\u0422\u0438\u043f\u0438\u0447\u043d\u0430\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u0430 \u0441 stat.gov.kz: \u0442\u0440\u0438 \u0441\u0442\u0440\u043e\u043a\u0438 \u0448\u0430\u043f\u043a\u0438 \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c \u0432\u0435\u0434\u043e\u043c\u0441\u0442\u0432\u0430, \u043f\u0443\u0441\u0442\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430, \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0451\u043d\u043d\u044b\u0435 \u044f\u0447\u0435\u0439\u043a\u0438, \u0438 \u0433\u0434\u0435-\u0442\u043e \u043d\u0430 \u043f\u044f\u0442\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438. pd.read_excel(header=0) \u0447\u0435\u0441\u0442\u043d\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430\u043c\u0438 \u00ab\u0411\u044e\u0440\u043e \u043d\u0430\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438\u00bb \u0438 \u043f\u044f\u0442\u044c Unnamed.\u042d\u0432\u0440\u0438\u0441\u0442\u0438\u043a\u0430 \u043f\u0440\u043e\u0441\u0442\u0430\u044f: \u0432 \u043f\u0435\u0440\u0432\u044b\u0445 15 \u0441\u0442\u0440\u043e\u043a\u0430\u0445 \u0438\u0449\u0435\u043c \u0442\u0443, \u0433\u0434\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u0445 \u044f\u0447\u0435\u0435\u043a, \u0438 \u0441\u0447\u0438\u0442\u0430\u0435\u043c \u0435\u0451 \u0448\u0430\u043f\u043a\u043e\u0439.scan_limit = min(len(cleaned), 15)header_idx = 0best_cells = -1for idx in range(scan_limit):    filled = int(cleaned.iloc[idx].notna().sum())    if filled &gt; best_cells:           # \u0441\u0442\u0440\u043e\u0433\u043e \u0431\u043e\u043b\u044c\u0448\u0435: \u043f\u0440\u0438 \u0440\u0430\u0432\u0435\u043d\u0441\u0442\u0432\u0435 \u043f\u043e\u0431\u0435\u0436\u0434\u0430\u0435\u0442 \u0432\u0435\u0440\u0445\u043d\u044f\u044f        best_cells = filled        header_idx = idx\u0418\u0437 \u0432\u0441\u0435\u0445 \u043b\u0438\u0441\u0442\u043e\u0432 \u043a\u043d\u0438\u0433\u0438 \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u0442, \u0433\u0434\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u0434\u0430\u043d\u043d\u044b\u0445: score = \u043d\u0435\u043f\u0443\u0441\u0442\u044b\u0435_\u044f\u0447\u0435\u0439\u043a\u0438 + \u043a\u043e\u043b\u043e\u043d\u043a\u0438 * 10. \u0412\u0435\u0441 \u0443 \u043a\u043e\u043b\u043e\u043d\u043e\u043a \u0437\u0430\u0432\u044b\u0448\u0435\u043d \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u2014 \u0438\u043d\u0430\u0447\u0435 \u0432\u044b\u0438\u0433\u0440\u044b\u0432\u0430\u043b \u043b\u0438\u0441\u0442 \u00ab\u041c\u0435\u0442\u043e\u0434\u043e\u043b\u043e\u0433\u0438\u044f\u00bb \u0441 \u043e\u0434\u043d\u043e\u0439 \u043a\u043e\u043b\u043e\u043d\u043a\u043e\u0439 \u0434\u043b\u0438\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0430.\u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430. \u041d\u043e \u043b\u0443\u0447\u0448\u0435, \u0447\u0435\u043c Unnamed: 0.\u0422\u0443\u0442 \u0431\u0443\u0434\u0435\u0442 \u0441\u0442\u044b\u0434\u043d\u043e, \u043d\u043e \u0447\u0435\u0441\u0442\u043d\u043e.\u0414\u043b\u044f .xls pandas \u043d\u0443\u0436\u0435\u043d xlrd. \u0415\u0433\u043e \u043d\u0435 \u0431\u044b\u043b\u043e, \u0438 pandas \u043e\u0442\u0432\u0435\u0447\u0430\u043b \u0442\u0430\u043a:ImportError: Import xlrd failed. Install xlrd &gt;= 2.0.1 for xls Excel support\u0412\u043c\u0435\u0441\u0442\u043e \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043e\u0434\u043d\u0443 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443, \u044f (\u0432 \u0442\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442 \u044d\u0442\u043e \u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0433\u0435\u043d\u0438\u0430\u043b\u044c\u043d\u044b\u043c) \u0440\u0435\u0448\u0438\u043b \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c .xls \u0432 .xlsx \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u043c Excel \u0447\u0435\u0440\u0435\u0437 COM. \u0418\u0437 Python. \u0427\u0435\u0440\u0435\u0437 PowerShell.command = f&#187;&#187;&#187;$excel = $null$workbook = $nulltry {{  $excel = New-Object -ComObject Excel.Application  $excel.Visible = $false  $excel.DisplayAlerts = $false  $workbook = $excel.Workbooks.Open(&#8216;{ps_source}&#8217;)  $workbook.SaveAs(&#8216;{ps_target}&#8217;, 51)       # 51 = xlOpenXMLWorkbook}} finally {{  if ($workbook -ne $null) {{ $workbook.Close($false) }}  if ($excel -ne $null) {{ $excel.Quit() }}}}&#187;&#187;&#187;result = subprocess.run([&#171;powershell&#187;, &#171;-NoProfile&#187;, &#171;-NonInteractive&#187;, &#171;-Command&#187;, command],                        capture_output=True, text=True, timeout=60)\u0421\u0430\u043c\u043e\u0435 \u0441\u043c\u0435\u0448\u043d\u043e\u0435 \u2014 \u043e\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442. \u041d\u0430 \u043c\u043e\u0435\u0439 \u043c\u0430\u0448\u0438\u043d\u0435 \u0441 Office.\u041f\u0440\u043e\u0431\u043b\u0435\u043c \u0440\u043e\u0432\u043d\u043e \u0442\u0440\u0438:\u041f\u043e\u0441\u043b\u0435 Quit() Excel \u0435\u0449\u0451 \u043a\u0430\u043a\u043e\u0435-\u0442\u043e \u0432\u0440\u0435\u043c\u044f \u0434\u0435\u0440\u0436\u0438\u0442 \u0444\u0430\u0439\u043b. shutil.rmtree(temp_dir, ignore_errors=True) \u043c\u043e\u043b\u0447\u0430 \u043d\u0435 \u0443\u0434\u0430\u043b\u044f\u0435\u0442 \u043f\u0430\u043f\u043a\u0443, \u0438 \u0432 .tmp_excel_conversion\/ \u0443 \u043c\u0435\u043d\u044f \u0434\u043e \u0441\u0438\u0445 \u043f\u043e\u0440 \u043b\u0435\u0436\u0430\u0442 \u0447\u0435\u0442\u044b\u0440\u0435 \u043e\u0441\u0438\u0440\u043e\u0442\u0435\u0432\u0448\u0438\u0445 job_*\/source.xls.\u041a\u0430\u0432\u044b\u0447\u043a\u0438 \u0432 \u043f\u0443\u0442\u0438 \u044d\u043a\u0440\u0430\u043d\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 replace(&#171;&#8216;&#187;, &#171;&#187;&#187;). \u0414\u043b\u044f \u043e\u0434\u0438\u043d\u0430\u0440\u043d\u044b\u0445 \u043a\u0430\u0432\u044b\u0447\u0435\u043a PowerShell \u044d\u0442\u043e\u0433\u043e \u0445\u0432\u0430\u0442\u0430\u0435\u0442, \u043d\u043e \u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0441\u0442\u0440\u043e\u043a\u0438 \u2014 \u0442\u0430\u043a \u0441\u0435\u0431\u0435 \u0438\u0434\u0435\u044f.Docker-\u043e\u0431\u0440\u0430\u0437 \u0443 \u0431\u044d\u043a\u0435\u043d\u0434\u0430 \u2014 python:3.12-slim. \u0422\u0430\u043c \u043d\u0435\u0442 \u043d\u0438 PowerShell, \u043d\u0438 Excel. \u0422\u043e \u0435\u0441\u0442\u044c \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435 \u0432\u0441\u044f \u044d\u0442\u0430 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.\u041f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u0444\u0438\u043a\u0441 \u2014 pip install xlrd (\u0438\u043b\u0438 LibreOffice headless, \u0435\u0441\u043b\u0438 \u0444\u0430\u0439\u043b\u044b \u0441\u043e\u0432\u0441\u0435\u043c \u044d\u043a\u0437\u043e\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435). \u041e\u043d \u0441\u0442\u043e\u0438\u0442 \u0443 \u043c\u0435\u043d\u044f \u043f\u0435\u0440\u0432\u044b\u043c \u0432 TODO, \u0438 \u043c\u043d\u0435 \u0437\u0430 \u043d\u0435\u0433\u043e \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043d\u0435\u043b\u043e\u0432\u043a\u043e.\u041a\u0430\u0442\u0430\u043b\u043e\u0433 \u043d\u0430 \u043e\u0434\u043d\u043e\u043c JSON\u0421\u0430\u043c\u0430\u044f \u0441\u043f\u043e\u0440\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c. \u0412\u0441\u0435 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u2014 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438, \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u044b, \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043e\u043a, \u043a\u044d\u0448 discover \u2014 \u043b\u0435\u0436\u0430\u0442 \u0432 \u043e\u0434\u043d\u043e\u043c catalog.json. \u0412 S3-\u0440\u0435\u0436\u0438\u043c\u0435 \u044d\u0442\u043e \u043e\u0434\u0438\u043d \u043e\u0431\u044a\u0435\u043a\u0442 meta\/catalog.json.\u041f\u043e\u0447\u0435\u043c\u0443 \u043d\u0435 Postgres? \u041e\u043d \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043d: \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0435\u0441\u0442\u044c catalog\/db.py \u0441 SQLAlchemy-\u043c\u043e\u0434\u0435\u043b\u044f\u043c\u0438 \u0438 \u0444\u043b\u0430\u0433 USE_DATABASE \u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0435. \u041d\u043e \u043a API \u043e\u043d \u043d\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0451\u043d. \u041f\u0435\u0440\u0432\u044b\u0435 \u043d\u0435\u0434\u0435\u043b\u0438 \u043d\u0443\u0436\u0435\u043d \u0431\u044b\u043b \u043a\u0430\u0442\u0430\u043b\u043e\u0433, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u0433\u043b\u0430\u0437\u0430\u043c\u0438, \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0440\u0443\u043a\u0430\u043c\u0438 \u0438 \u0437\u0430\u043a\u043e\u043c\u043c\u0438\u0442\u0438\u0442\u044c \u043a\u0430\u043a \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0443. JSON \u044d\u0442\u043e \u0434\u0430\u0432\u0430\u043b, \u0430 \u043f\u043e\u0442\u043e\u043c \u0442\u0430\u043a \u0438 \u043f\u0440\u0438\u0436\u0438\u043b\u0441\u044f. \u0412\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u043a\u0430\u043a \u043e\u0431\u044b\u0447\u043d\u043e, \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0441\u0430\u043c\u044b\u043c \u0434\u043e\u043b\u0433\u043e\u0436\u0438\u0432\u0443\u0449\u0438\u043c.\u041f\u0435\u0440\u0432\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0438: \u0430\u0442\u043e\u043c\u0430\u0440\u043d\u044b\u0439 replace\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u044f \u0441\u0434\u0435\u043b\u0430\u043b \u00ab\u043f\u043e \u0443\u0447\u0435\u0431\u043d\u0438\u043a\u0443\u00bb: \u043f\u0438\u0448\u0435\u043c \u0432\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b, \u043f\u043e\u0442\u043e\u043c os.replace \u043f\u043e\u0432\u0435\u0440\u0445 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e, \u0430 \u043c\u0435\u0436\u0434\u0443 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430\u043c\u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u0443\u0435\u043c\u0441\u044f \u0447\u0435\u0440\u0435\u0437 lock-\u0444\u0430\u0439\u043b \u0441 O_CREAT | O_EXCL:fd = os.open(lock_path, os.O_CREAT | os.O_EXCL | os.O_WRONLY)os.write(fd, str(os.getpid()).encode(&#171;utf-8&#187;))\u041d\u0430 Linux \u044d\u0442\u043e \u043a\u043b\u0430\u0441\u0441\u0438\u043a\u0430. \u041d\u0430 Windows os.replace \u043f\u0430\u0434\u0430\u0435\u0442, \u0435\u0441\u043b\u0438 \u0446\u0435\u043b\u0435\u0432\u043e\u0439 \u0444\u0430\u0439\u043b \u043a\u0442\u043e-\u0442\u043e \u0434\u0435\u0440\u0436\u0438\u0442 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u2014 \u0430 \u0434\u0435\u0440\u0436\u0430\u043b \u0435\u0433\u043e \u0442\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 uvicorn \u0441 &#8212;reload, \u0442\u043e \u0430\u043d\u0442\u0438\u0432\u0438\u0440\u0443\u0441, \u0442\u043e \u044f \u0441\u0430\u043c \u0432 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435:PermissionError: [Errno 13] \u041e\u0442\u043a\u0430\u0437\u0430\u043d\u043e \u0432 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u041e\u0442 \u0442\u043e\u0439 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438 \u043e\u0441\u0442\u0430\u043b\u0438\u0441\u044c \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u044b: \u0432 .tmp_api_smoke\/ \u043b\u0435\u0436\u0438\u0442 catalog.json.tmp.20872.14844 (\u0438\u043c\u044f \u0441\u043e\u0431\u0440\u0430\u043d\u043e \u0438\u0437 PID \u0438 thread id) \u0438 catalog.json.lock \u0441 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c 20872. \u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0443\u043c\u0435\u0440, \u0430 lock \u043e\u0441\u0442\u0430\u043b\u0441\u044f. \u0420\u043e\u0432\u043d\u043e \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 acquirefile_lock \u043f\u043e\u0442\u043e\u043c \u043f\u043e\u044f\u0432\u0438\u043b\u043e\u0441\u044c stale_after = 30 \u0441\u0435\u043a\u0443\u043d\u0434: lock \u0441\u0442\u0430\u0440\u0448\u0435 30 \u0441\u0435\u043a\u0443\u043d\u0434 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0442\u0443\u0445\u0448\u0438\u043c \u0438 \u0443\u0434\u0430\u043b\u044f\u0435\u0442\u0441\u044f.\u0422\u0435\u043a\u0443\u0449\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044fdef _save(self):    payload = json.dumps(self._data, ensure_ascii=False, indent=2, default=str).encode(&#171;utf-8&#187;)    with open(target, &#171;a+b&#187;) as file_obj:          # a+b: \u043d\u0435 \u043e\u0431\u043d\u0443\u043b\u044f\u0435\u0442 \u0444\u0430\u0439\u043b \u043f\u0440\u0438 \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0438        file_obj.seek(0)        if os.name == &#171;nt&#187;:            msvcrt.locking(file_obj.fileno(),&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-501926","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/501926","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=501926"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/501926\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=501926"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=501926"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=501926"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}