{"id":462222,"date":"2025-06-06T09:00:25","date_gmt":"2025-06-06T09:00:25","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=462222"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=462222","title":{"rendered":"<span>\u041f\u0430\u0440\u0441\u0438\u043c YouTube \u043d\u0430 Python \u043a\u0430\u043a \u0434\u043b\u044f \u0432\u0437\u0440\u043e\u0441\u043b\u044b\u0445: \u043e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u044b\u0439 \u0441\u043a\u0440\u0438\u043f\u0442 \u0441 \u0440\u043e\u0442\u0430\u0446\u0438\u0435\u0439 \u043a\u043b\u044e\u0447\u0435\u0439<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041f\u0443\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043f\u0430\u0440\u0441\u0435\u0440\u043e\u0432 \u0442\u0435\u0440\u043d\u0438\u0441\u0442 \u0438 \u0441\u043b\u043e\u0436\u0435\u043d, \u0441\u043f\u0435\u0440\u0432\u0430 \u0442\u044b \u043f\u044b\u0442\u0430\u0435\u0448\u044c\u0441\u044f \u043e\u0431\u043e\u0439\u0442\u0438 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0442\u0430\u043a \u043f\u0440\u043e\u0449\u0435, \u0442\u0430\u043a \u043d\u0435\u0442\u0443 \u043a\u0432\u043e\u0442 \u0438 \u0440\u0430\u0437\u043d\u044b\u0445 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439. \u041f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u043c\u0443\u0447\u0430\u044f\u0441\u044c \u0441 Selenium, \u0432 \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u0443\u0433\u043d\u0430\u0442\u044c\u0441\u044f \u0437\u0430 \u043c\u0435\u043d\u044f\u044e\u0449\u0435\u0439\u0441\u044f \u0432\u0435\u0440\u0441\u0442\u043a\u043e\u0439 YouTube. \u041a\u0442\u043e-\u0442\u043e \u043f\u0438\u0448\u0435\u0442 \u043f\u0440\u043e\u0441\u0442\u044b\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u044b \u043d\u0430 requests, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0430\u0434\u0430\u044e\u0442 \u043f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u0439 \u0436\u0435 \u043e\u0448\u0438\u0431\u043a\u0435. \u0418 \u043a\u0443\u0434\u0430 \u0432\u0430\u0441 \u0432\u0441\u0435 \u044d\u0442\u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043f\u0440\u0438\u0432\u043e\u0434\u044f\u0442? <\/p>\n<p>\u0421\u043d\u043e\u0432\u0430 \u043a\u043e \u043c\u043d\u0435 &#8212; \u043a \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u043c\u0443 <strong>YouTube Data API v3<\/strong>. <\/p>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/68429ea880f398ebcd350292\" data-style=\"\" id=\"68429ea880f398ebcd350292\" width=\"\"><\/div>\n<blockquote>\n<p>\u0412\u0435\u0440\u043e\u044f\u0442\u043d\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0447\u0442\u043e \u0442\u043e \u0431\u043e\u043b\u0435\u0435 \u0438\u0437\u044f\u0449\u043d\u043e\u0435, \u043d\u043e \u043c\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0438 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0438 \u0443 \u0432\u0430\u0441.<\/p>\n<\/blockquote>\n<p>\u041d\u043e \u0441 \u044d\u0442\u0438\u043c \u0410\u041f\u0418 \u0432\u0441\u0435 \u0441\u043e\u0432\u0441\u0435\u043c \u043d\u0435 \u0442\u0430\u043a \u043f\u0440\u043e\u0441\u0442\u043e, \u043a\u0430\u043a \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434. \u0425\u043e\u0440\u043e\u0448\u043e, \u0432\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c \u0441 Cloud Console (\u0411\u0440\u0430\u0432\u043e!), \u0434\u0430\u0436\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 API-\u043a\u043b\u044e\u0447 \u0438 \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u0410\u041f\u0418, \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438 \u043f\u0430\u0440\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432&#8230; \u0438 \u0447\u0435\u0440\u0435\u0437 15 \u043c\u0438\u043d\u0443\u0442 (\u0430 \u043c\u043e\u0436\u0435\u0442 \u0434\u0430\u0436\u0435 \u0440\u0430\u043d\u044c\u0448\u0435) \u0443\u043f\u0435\u0440\u043b\u0438\u0441\u044c \u0432 quotaExceeded. \u0417\u043d\u0430\u043a\u043e\u043c\u043e? \u041c\u043d\u0435 \u0434\u0430! \u042f \u0432\u043e\u043e\u0431\u0449\u0435 \u043a\u043e\u0433\u0434\u0430 \u0432\u043e\u0440\u0432\u0430\u043b\u0441\u044f \u0441 \u043d\u043e\u0433\u0438 \u0432 \u044d\u0442\u043e\u0442 \u043c\u0438\u0440 \u0410\u041f\u0418, \u043d\u0435 \u0434\u0443\u043c\u0430\u043b \u043f\u0440\u043e \u043a\u0432\u043e\u0442\u0443 &#8212; \u043f\u0440\u043e\u0441\u0442\u043e \u0443 \u043c\u0435\u043d\u044f \u0431\u044b\u043b \u043a\u0430\u043a\u043e\u0439 \u0442\u043e \u043f\u043b\u0430\u043d \u0438 \u044f \u0435\u0433\u043e \u043f\u0440\u0438\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u043b\u0441\u044f. \u0418 \u0442\u043e, \u043e \u0447\u0435\u043c \u044f \u0432\u0430\u043c \u0445\u043e\u0447\u0443 \u043f\u043e\u0432\u0435\u0434\u0430\u0442\u044c &#8212; \u0438\u0441\u0442\u043e\u0440\u0438\u044f, \u0432\u044b\u0441\u0442\u0440\u0430\u0434\u0430\u043d\u043d\u0430\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0434\u043d\u044f\u043c\u0438. \u041f\u0430\u0434\u0435\u043d\u0438\u044f \u043d\u0430 \u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0435 \u0441\u0431\u043e\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u043f\u043e\u0442\u0435\u0440\u044f \u0441\u043f\u0430\u0440\u0448\u0435\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445. <strong>\u041a\u043e\u0440\u043e\u0447\u0435 &#8212; \u044d\u0442\u043e\u0442 \u0441\u043a\u0440\u0438\u043f\u0442, (\u043f\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0438 \u0441 \u0423\u0413\u0438\u041a\u0421 &#8212; \u043a\u0442\u043e \u043f\u043e\u0439\u043c\u0435\u0442, \u0442\u043e\u0442 \u043f\u043e\u0439\u043c\u0435\u0442) &#8212; \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u0445\u043e\u0442\u044c \u0438 \u043d\u0435 \u043a\u0440\u043e\u0432\u044c\u044e, \u043d\u043e \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0441\u043e\u043b\u0438 \u0442\u043e \u0442\u0430\u043c \u0435\u0441\u0442\u044c, \u0442\u0430\u043a \u043a\u0430\u043a \u0441\u043b\u0435\u0437\u044b \u0442\u043e\u0436\u0435 \u0441\u043e\u043b\u0435\u043d\u044b\u0435. <\/strong><\/p>\n<p>\u0412 \u043e\u0431\u0449\u0435\u043c &#8212; \u043a\u0430\u0436\u0434\u044b\u0439 \u0445\u043e\u0434 \u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0432 \u044d\u0442\u043e\u043c \u0441\u043a\u0440\u0438\u043f\u0442\u0435 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u043b\u043e\u0441\u044c \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u043b\u043e\u0441\u044c \u043f\u043e \u043c\u0435\u0440\u0435 \u0432\u044b\u043b\u0435\u0437\u0430\u043d\u0438\u044f \u0442\u043e\u0439 \u0438\u043b\u0438 \u0438\u043d\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b &#8212; \u0443\u043f\u0438\u0440\u0430\u043d\u0438\u0435 \u0432 \u043a\u0432\u043e\u0442\u044b, \u043e\u0431\u0440\u044b\u0432 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0439 \u0438 \u0442\u043f. \u0414\u043b\u044f \u043c\u0435\u043d\u044f \u0441\u043a\u0440\u0438\u043f\u0442 \u0441\u0432\u043e\u044e \u0437\u0430\u0434\u0430\u0447\u0443 \u0441\u0434\u0435\u043b\u0430\u043b, \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0438 \u0432\u0430\u043c. <\/p>\n<p>\u0411\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0433\u0430\u0439\u0434\u043e\u0432 \u0432 \u0441\u0435\u0442\u0438 (\u0438\u0437 \u0442\u0435\u0445, \u0447\u0442\u043e \u0432\u0441\u0442\u0440\u0435\u0442\u0438\u043b\u0438\u0441\u044c \u043d\u0430 \u043c\u043e\u0435\u043c \u043f\u0443\u0442\u0438) \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442, \u043a\u0430\u043a \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043e\u0434\u0438\u043d-\u0434\u0432\u0430 \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u041d\u043e \u043c\u044b \u043f\u043e\u0439\u0434\u0435\u043c \u0434\u0430\u043b\u044c\u0448\u0435. \u042f \u043f\u043e\u043a\u0430\u0436\u0443 \u0432\u0430\u043c \u0441\u043a\u0440\u0438\u043f\u0442 \u043d\u0430 Python, \u043a\u043e\u0442\u043e\u0440\u044b\u0439:<\/p>\n<ul>\n<li>\n<p><strong>\u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u043f\u0443\u043b\u043e\u043c API-\u043a\u043b\u044e\u0447\u0435\u0439<\/strong>, \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u044f\u0441\u044c \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439, \u043a\u043e\u0433\u0434\u0430 \u0443 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u0432\u043e\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p><strong>\u0423\u043c\u0435\u0435\u0442 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443<\/strong> \u0441 \u0442\u043e\u0433\u043e \u043c\u0435\u0441\u0442\u0430, \u0433\u0434\u0435 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0441\u044f, \u0434\u0430\u0436\u0435 \u043f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p><strong>\u041a\u044d\u0448\u0438\u0440\u0443\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u044b<\/strong>, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0442\u0440\u0430\u0442\u0438\u0442\u044c \u0434\u0440\u0430\u0433\u043e\u0446\u0435\u043d\u043d\u044b\u0435 \u0435\u0434\u0438\u043d\u0438\u0446\u044b \u043a\u0432\u043e\u0442\u044b \u043d\u0430 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0435 \u0432\u044b\u0437\u043e\u0432\u044b.<\/p>\n<\/li>\n<li>\n<p><strong>\u0423\u0441\u0442\u043e\u0439\u0447\u0438\u0432 \u043a \u043e\u0448\u0438\u0431\u043a\u0430\u043c \u0441\u0435\u0442\u0438<\/strong> \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0443 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 (retry).<\/p>\n<\/li>\n<li>\n<p><strong>\u0418\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043d \u0441 Google Sheets<\/strong>: \u0447\u0438\u0442\u0430\u0435\u0442 \u0438\u0437 \u043e\u0434\u043d\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b, \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0432 \u0434\u0440\u0443\u0433\u0443\u044e.<\/p>\n<\/li>\n<li>\n<p><strong>\u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u0440\u0446\u0438\u044f\u043c\u0438 (\u0431\u0430\u0442\u0447\u0430\u043c\u0438)<\/strong>, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u043e\u0442\u0435\u0440\u044f\u0442\u044c \u0432\u0441\u0451 \u043f\u0440\u0438 \u0441\u0431\u043e\u0435.<\/p>\n<\/li>\n<li>\n<p><strong>\u041e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0438 \u043e\u0431\u043e\u0433\u0430\u0449\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435<\/strong> \u043d\u0430 \u043b\u0435\u0442\u0443: \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u044f\u0437\u044b\u043a, \u0434\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c, \u0432\u043e\u0437\u0440\u0430\u0441\u0442 \u0432\u0438\u0434\u0435\u043e \u0438 \u043c\u043d\u043e\u0433\u043e\u0435 \u0434\u0440\u0443\u0433\u043e\u0435.<\/p>\n<\/li>\n<\/ul>\n<p>\u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u2014 \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0442\u0435\u043e\u0440\u0438\u044f \u0438 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u0430. \u042d\u0442\u043e \u043f\u043e\u0448\u0430\u0433\u043e\u0432\u044b\u0439 \u0440\u0430\u0437\u0431\u043e\u0440 \u0433\u043e\u0442\u043e\u0432\u043e\u0433\u043e, \u0440\u0430\u0431\u043e\u0447\u0435\u0433\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434 \u0441\u0432\u043e\u0438 \u0437\u0430\u0434\u0430\u0447\u0438. \u041f\u043e\u043b\u043d\u044b\u0439 \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u043a\u043e\u0434 \u044f \u0437\u0430\u043b\u044c\u044e \u043d\u0430 \u0441\u0432\u043e\u0439 (\u043d\u0435 \u0411\u043e\u0433 \u0432\u0435\u0441\u044c \u043a\u0430\u043a\u043e\u0439, \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e) <a href=\"https:\/\/github.com\/kentavr009\/Youtube-Parser\" rel=\"noopener noreferrer nofollow\">GitHub<\/a>, \u0438 \u0442\u0430\u043a\u0436\u0435 \u0441\u0434\u0435\u043b\u0430\u044e \u0447\u0443\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u044b\u0439 \u0440\u0430\u0437\u0431\u043e\u0440 <a href=\"https:\/\/autoparse.tech\/kejsy\/parsing-youtube\/\" rel=\"noopener noreferrer nofollow\">\u0432 \u0441\u0432\u043e\u0435\u043c \u0431\u043b\u043e\u0433\u0435<\/a> &#8212; \u043d\u0443 \u044d\u0442\u043e \u0443\u0436\u0435 \u0441\u043a\u043e\u0440\u0435\u0435 \u0434\u043b\u044f \u0442\u0435\u0445, \u043a\u0442\u043e \u0445\u043e\u0447\u0435\u0442 \u043f\u0440\u044f\u043c \u043f\u043e\u0433\u0440\u0443\u0437\u0438\u0442\u044c\u0441\u044f \u0432 \u043d\u0435\u0433\u043e \u0441 \u0433\u043e\u043b\u043e\u0432\u043e\u0439, \u043a\u0430\u043a \u0432 \u0442\u043e\u043c \u0430\u043d\u0435\u043a\u0434\u043e\u0442\u0435 &#8212; \u201c\u043a\u0443\u0440\u0438\u0442\u044c \u043b\u044e\u0431\u043b\u044e, \u043a\u0430\u043f\u0435\u0446\u2026\u201d. \u041f\u043e\u0435\u0445\u0430\u043b\u0438!<\/p>\n<h3>\u0427\u0430\u0441\u0442\u044c 1. \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430<\/h3>\n<h4>\u041f\u0440\u0438\u043a\u0432\u0435\u043b<\/h4>\n<p>\u041f\u0435\u0440\u0435\u0434\u043e \u043c\u043d\u043e\u0439 \u0432\u0441\u0442\u0430\u043b\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 &#8212; \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0432\u0438\u0434\u0435\u043e \u0434\u043b\u044f 40+ \u0442\u044b\u0441\u044f\u0447 \u0441\u0442\u0440\u0430\u043d\u0438\u0446 \u0441\u0430\u0439\u0442\u0430, \u043a\u0430\u0436\u0434\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0438\u043c\u0435\u0435\u0442 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u043a\u043b\u044e\u0447. \u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043f\u043e \u044d\u0442\u043e\u043c\u0443 \u043a\u043b\u044e\u0447\u0443 \u0438 \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u042e\u0442\u0443\u0431\u0430. \u0417\u0430\u0434\u0430\u0447\u0430 &#8212; \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0436\u0435 \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u044b\u0435 \u0432\u0438\u0434\u0435\u043e, \u043d\u043e \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u0441\u0431\u043e\u0440\u0430 \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u043e (\u0442\u0435\u043c \u0431\u043e\u043b\u0435\u0435 \u0447\u0442\u043e \u044d\u0442\u043e \u043d\u0435 \u043a\u043e\u043c\u0431\u0430\u0439\u043d, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0437\u0430\u0434\u0430\u0447\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u043d\u043e \u0441\u043c\u0435\u043b\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0432 \u043a\u043e\u0441\u043c\u043e\u0441) &#8212; \u0443 \u043c\u0435\u043d\u044f \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0430\u0440\u0441\u0435\u0440.<\/p>\n<p>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u044f \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043b \u0434\u0432\u0430 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u043f\u0430\u0440\u0441\u0435\u0440\u043e\u0432 &#8212; \u043e\u0434\u0438\u043d \u0447\u0443\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0437\u0430\u043c\u043e\u0440\u043e\u0447\u0435\u043d\u044b\u0439, \u0433\u0434\u0435 \u043a\u0430\u0436\u0434\u044b\u0439 \u0410\u041f\u0418 \u043a\u043b\u044e\u0447 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d \u043a \u0441\u0432\u043e\u0435\u043c\u0443 \u0441\u0435\u0440\u0432\u0438\u0441\u043d\u043e\u043c\u0443 \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0443, \u0438 \u0432\u0442\u043e\u0440\u043e\u0439 (\u043e\u043d \u043a\u0430\u043a \u0440\u0430\u0437 \u043d\u0438\u0436\u0435) &#8212; \u0433\u0434\u0435 \u0435\u0441\u0442\u044c \u043e\u0434\u0438\u043d \u0441\u0435\u0440\u0432\u0438\u0441\u043d\u044b\u0439 \u0430\u043a\u043a\u0430\u0443\u043d\u0442 \u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043a\u043b\u044e\u0447\u0435\u0439 \u0410\u041f\u0418.<\/p>\n<p>\u0412 \u043e\u0431\u043e\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u0432\u0440\u0435\u043c\u044f \u0436\u0438\u0437\u043d\u0438 \u043a\u043b\u044e\u0447\u0435\u0439 \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u043b\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e 3 \u0434\u043d\u044f, \u043f\u043e\u0442\u043e\u043c \u044e\u0442\u0443\u0431 \u043d\u0430\u0447\u0438\u043d\u0430\u043b \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043a\u0430\u043a\u0430\u044f \u0442\u043e \u043d\u0435\u043f\u043e\u043d\u044f\u0442\u043d\u0430\u044f \u0447\u0435\u043f\u0443\u0445\u0430 \u0438 \u0441\u043d\u0438\u0436\u0430\u043b \u043a\u0432\u043e\u0442\u0443 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0430 \u0434\u043e 1 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (\u0441 10000 \u0432 \u0441\u0443\u0442\u043a\u0438) \u0438\u00a0 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430\u043b \u0441\u0435\u0440\u0432\u0438\u0441\u043d\u044b\u0439 \u0430\u043a\u043a\u0430\u0443\u043d\u0442 &#8212; \u043a\u043e\u0440\u043e\u0447\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u044b\u0440\u0443\u0431\u0430\u043b \u043f\u0430\u0440\u0441\u0435\u0440 \u0441\u0432\u043e\u0438\u043c\u0438 \u0441\u0438\u043b\u0430\u043c\u0438.<\/p>\n<p>\u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0432\u0435\u043d\u043d\u043e &#8212; \u0435\u0441\u043b\u0438 \u043d\u0435\u0442 \u0440\u0430\u0437\u043d\u0438\u0446\u044b, \u0437\u0430\u0447\u0435\u043c <s>\u043f\u043b\u0430\u0442\u0438\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435<\/s> \u0434\u0435\u043b\u0430\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u0440\u0430\u0431\u043e\u0442\u044b?<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/70d\/3b8\/9b5\/70d3b89b5a829365c10b523c32f8298a.jpg\" width=\"469\" height=\"621\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/70d\/3b8\/9b5\/70d3b89b5a829365c10b523c32f8298a.jpg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/70d\/3b8\/9b5\/70d3b89b5a829365c10b523c32f8298a.jpg 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u0422\u0430\u043a \u0438 \u0440\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u044d\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435<\/p>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043f\u043e\u0433\u0440\u0443\u0436\u0430\u0442\u044c\u0441\u044f \u0432 \u043f\u0430\u0440\u0441\u0435\u0440, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c\u0441\u044f \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u0438 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043c \u0432\u0441\u0451 \u0447\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043b\u044f \u0435\u0433\u043e \u0440\u0430\u0431\u043e\u0442\u044b. \u0422\u0430\u043a \u043a\u0430\u043a \u044d\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0434\u043d\u043e\u0444\u0430\u0439\u043b\u043e\u0432\u044b\u0439 \u0441\u043a\u0440\u0438\u043f\u0442\u0438\u043a, \u0430 \u0441\u0432\u043e\u0435\u0433\u043e \u0440\u043e\u0434\u0430 \u043c\u0438\u043d\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0430.<\/p>\n<h4>1.1. \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0447\u0435\u0440\u0435\u0437 .env<\/h4>\n<p>\u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u044f \u043b\u044e\u0431\u0438\u0442\u0435\u043b\u044c \u0432\u0441\u0435 \u0443\u043f\u0440\u043e\u0449\u0430\u0442\u044c, \u0442\u0430\u043a \u043a\u0430\u043a \u043f\u0430\u0440\u0441\u0435\u0440 \u0438\u0434\u0435\u0442 \u0432 \u043f\u0430\u0431\u043b\u0438\u043a \u044f \u043d\u0435 \u0431\u0443\u0434\u0443 \u0445\u0430\u0440\u0434\u043a\u043e\u0434\u0438\u0442\u044c \u043a\u043b\u044e\u0447\u0438 \u0438 ID \u0442\u0430\u0431\u043b\u0438\u0446 \u0432 \u043a\u043e\u0434\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u0430. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c .env \u0444\u0430\u0439\u043b \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u043d\u0443\u0436\u043d\u044b\u0445 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a. \u042d\u0442\u043e \u0432 \u0446\u0435\u043b\u043e\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e \u0438 \u0443\u0434\u043e\u0431\u043d\u043e.\u00a0<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0432 \u0442\u043e\u0439 \u0436\u0435 \u043f\u0430\u043f\u043a\u0435 \u0433\u0434\u0435 \u043b\u0435\u0436\u0438\u0442 \u043f\u0430\u0440\u0441\u0435\u0440 \u0444\u0430\u0439\u043b .env \u0442\u0430\u043a\u043e\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f:<\/p>\n<pre><code class=\"python\">     # ID \u0432\u0430\u0448\u0435\u0439 Google \u0422\u0430\u0431\u043b\u0438\u0446\u044b SHEET_ID=\"ID \u0422\u0410\u0411\u041b\u0418\u0426\u042b \u0412\u0410\u0428\u0415\u0419 \u0422\u0410\u0411\u041b\u0418\u0426\u042b\" # \u0418\u043c\u044f \u043b\u0438\u0441\u0442\u0430 \u0441 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438 KEYWORDS_SHEET=\"Keywords\" # \u0418\u043c\u044f \u043b\u0438\u0441\u0442\u0430 \u0434\u043b\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 RESULTS_SHEET=\"Results\" # \u041f\u0443\u0442\u044c \u043a JSON-\u0444\u0430\u0439\u043b\u0443 \u0441\u0435\u0440\u0432\u0438\u0441\u043d\u043e\u0433\u043e \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0430 Google SERVICE_ACCOUNT_JSON=\"credentials.json\" # \u0412\u0430\u0448\u0438 API \u043a\u043b\u044e\u0447\u0438 \u043e\u0442 YouTube, \u0447\u0435\u0440\u0435\u0437 \u0437\u0430\u043f\u044f\u0442\u0443\u044e YT_API_KEYS=\"\u0412\u0410\u0428_\u041a\u041b\u042e\u0427_1,\u0412\u0410\u0428_\u041a\u041b\u042e\u0427_2,\u0412\u0410\u0428_\u041a\u041b\u042e\u0427_3\"  # \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0430\u0440\u0441\u0435\u0440\u0430 NUM_RESULTS=10      # \u0421\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u043d\u0430 \u043e\u0434\u0438\u043d \u043a\u043b\u044e\u0447\u0435\u0432\u0438\u043a REGION=\"US\"         # \u0420\u0435\u0433\u0438\u043e\u043d \u043f\u043e\u0438\u0441\u043a\u0430 MAX_PAGES=1         # \u0421\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0442\u0440\u0430\u043d\u0438\u0446 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c BATCH_SIZE=50       # \u0427\u0435\u0440\u0435\u0437 \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043a\u043b\u044e\u0447\u0435\u0432\u0438\u043a\u043e\u0432 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0431\u0430\u0442\u0447 OUTPUT_CSV=\"yt_results.csv\" # \u0418\u043c\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e CSV \u0444\u0430\u0439\u043b\u0430<\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u0432\u044b \u0443\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442\u0435 \u043f\u043e\u0434 \u0441\u0435\u0431\u044f \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e, \u0432\u0430\u0436\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c, \u0447\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u043d\u0430 \u043e\u0434\u0438\u043d \u043a\u043b\u044e\u0447 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c, \u0442\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0441\u0445\u043e\u0434\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u0432\u043e\u0442\u0430.\u00a0\u00a0\u00a0<\/p>\n<h4>1.2. \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043a\u043b\u044e\u0447\u0435\u0439 \u0410\u041f\u0418 \u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u043d\u043e\u0433\u043e \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0430<\/h4>\n<p>\u041d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0434\u0432\u0430 \u0442\u0438\u043f\u0430 \u0443\u0447\u0435\u0442\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445:<\/p>\n<ol>\n<li>\n<p><strong>YouTube Data API Keys (\u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0448\u0442\u0443\u043a!):<\/strong> \u0417\u0430\u0439\u0434\u0438\u0442\u0435 \u0432<a href=\"https:\/\/console.cloud.google.com\/\" rel=\"noopener noreferrer nofollow\"> Google Cloud Console<\/a>, \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u043d\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442, \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u0435 YouTube Data API v3 \u0438 \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 API-\u043a\u043b\u044e\u0447. \u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437\u2026 \u0417\u0430\u0447\u0435\u043c?\u00a0 \u0414\u043d\u0435\u0432\u043d\u0430\u044f \u043a\u0432\u043e\u0442\u0430 \u043d\u0430 \u043e\u0434\u0438\u043d \u043a\u043b\u044e\u0447 \u2014 10 000 &#171;\u0435\u0434\u0438\u043d\u0438\u0446&#187;. \u042d\u0442\u043e\u0433\u043e \u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043c\u0430\u043b\u043e \u0434\u043b\u044f \u0441\u0435\u0440\u044c\u0435\u0437\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447. \u041f\u0443\u043b \u0438\u0437 3-5 \u043a\u043b\u044e\u0447\u0435\u0439 \u0434\u0430\u0441\u0442 \u043d\u0430\u043c 30-50 \u0442\u044b\u0441\u044f\u0447 \u0435\u0434\u0438\u043d\u0438\u0446 \u0432 \u0434\u0435\u043d\u044c, \u0447\u0442\u043e \u0443\u0436\u0435 \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0435\u0435 (\u044f \u0434\u0435\u043b\u0430\u043b 8 \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u043e\u0432 \u043f\u043e 12 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u0432 \u043a\u0430\u0436\u0434\u043e\u043c, \u0447\u0442\u043e \u0434\u0430\u043b\u043e \u043c\u043d\u0435 \u0432 \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0441\u0435 960\u043a \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0432 \u0434\u0435\u043d\u044c).<\/p>\n<\/li>\n<\/ol>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c53\/292\/ea3\/c53292ea3f94d90989e0bc7c944cdb5c.jpg\" width=\"1901\" height=\"544\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/c53\/292\/ea3\/c53292ea3f94d90989e0bc7c944cdb5c.jpg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c53\/292\/ea3\/c53292ea3f94d90989e0bc7c944cdb5c.jpg 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<ol>\n<li>\n<p><strong>Google Sheets API Service Account:<\/strong> \u0427\u0442\u043e\u0431\u044b \u0441\u043a\u0440\u0438\u043f\u0442 \u043c\u043e\u0433 \u0441\u0430\u043c \u0447\u0438\u0442\u0430\u0442\u044c \u0438 \u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u0432\u0430\u0448\u0443 \u0442\u0430\u0431\u043b\u0438\u0446\u0443, \u043d\u0443\u0436\u0435\u043d \u0441\u0435\u0440\u0432\u0438\u0441\u043d\u044b\u0439 \u0430\u043a\u043a\u0430\u0443\u043d\u0442. \u0412 \u0442\u043e\u0439 \u0436\u0435 Cloud Console \u043f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u0432 IAM &amp; Admin -&gt; Service Accounts, \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u043d\u043e\u0432\u044b\u0439, \u0434\u0430\u0439\u0442\u0435 \u0435\u043c\u0443 \u0440\u043e\u043b\u044c &#171;Editor&#187;, \u0438 \u0441\u043a\u0430\u0447\u0430\u0439\u0442\u0435 JSON-\u043a\u043b\u044e\u0447. \u041f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u0443\u0439\u0442\u0435 \u0435\u0433\u043e \u0432 credentials.json \u0438 \u043f\u043e\u043b\u043e\u0436\u0438\u0442\u0435 \u0440\u044f\u0434\u043e\u043c \u0441\u043e \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u043c. <strong>\u0412\u0430\u0436\u043d\u043e:<\/strong> \u043d\u0435 \u0437\u0430\u0431\u0443\u0434\u044c\u0442\u0435 &#171;\u0440\u0430\u0441\u0448\u0430\u0440\u0438\u0442\u044c&#187; \u0432\u0430\u0448\u0443 Google \u0422\u0430\u0431\u043b\u0438\u0446\u0443 \u0434\u043b\u044f email&#8217;\u0430 \u044d\u0442\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u043d\u043e\u0433\u043e \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0430 (\u043e\u043d \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043a\u0430\u043a &#8230;<a href=\"http:\/\/gserviceaccount.com\" rel=\"noopener noreferrer nofollow\">gserviceaccount.com<\/a>).<\/p>\n<\/li>\n<\/ol>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/bdd\/898\/698\/bdd8986985a1c5ba63dd42d3301db5a0.jpg\" width=\"1894\" height=\"588\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/bdd\/898\/698\/bdd8986985a1c5ba63dd42d3301db5a0.jpg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/bdd\/898\/698\/bdd8986985a1c5ba63dd42d3301db5a0.jpg 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u041e\u0434\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u043d\u043e\u0433\u043e \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0430 \u043f\u043e \u043c\u043e\u0435\u043c\u0443 \u043e\u043f\u044b\u0442\u0443 \u0436\u0435\u0441\u0442\u043a\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043f\u0430\u0440\u0441\u0435\u0440\u0430 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u043d\u0430 3 \u0434\u043d\u044f, \u043d\u043e \u044f \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u043d\u0430 \u0432\u0441\u044f\u043a\u0438\u0439 \u0441\u043b\u0443\u0447\u0430\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 40-50 \u043a\u043b\u044e\u0447\u0435\u0439 \u043d\u0430 \u043e\u0434\u0438\u043d \u0441\u0435\u0440\u0432\u0438\u0441\u043d\u044b\u0439 \u0430\u043a\u043a\u0430\u0443\u043d\u0442, \u0447\u0438\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0441\u0442\u0440\u0430\u0445\u043e\u0432\u043a\u0430, \u043c\u0430\u043b\u043e \u043b\u0438 \u0413\u0443\u0433\u043b \u043d\u0430\u0447\u043d\u0435\u0442 \u0447\u0442\u043e \u0442\u043e \u043f\u043e\u0434\u043e\u0437\u0440\u0435\u0432\u0430\u0442\u044c \u0440\u0430\u043d\u044c\u0448\u0435.<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/2eb\/809\/ea9\/2eb809ea9b18c119d76d0ade20ad4b21.jpeg\" width=\"960\" height=\"465\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/2eb\/809\/ea9\/2eb809ea9b18c119d76d0ade20ad4b21.jpeg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/2eb\/809\/ea9\/2eb809ea9b18c119d76d0ade20ad4b21.jpeg 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u044d\u0442\u043e \u0438 \u0435\u0441\u0442\u044c \u0441\u0430\u043c\u0430\u044f \u0441\u043b\u043e\u0436\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 &#8212; \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0410\u041f\u0418 \u043a\u043b\u044e\u0447\u0435\u0439. \u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0437\u0430\u0433\u043b\u044f\u043d\u0435\u043c \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442 \u043f\u0430\u0440\u0441\u0435\u0440\u0430.<\/p>\n<h3>\u0427\u0430\u0441\u0442\u044c 2. KeyManager \u0434\u043b\u044f \u0440\u043e\u0442\u0430\u0446\u0438\u0438 API-\u043a\u043b\u044e\u0447\u0435\u0439<\/h3>\n<p>\u0412\u043e\u0442 \u043a\u0430\u043a \u043f\u0430\u0440\u0441\u0435\u0440 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u0443\u043b\u043e\u043c \u043a\u043b\u044e\u0447\u0435\u0439 \u0438 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043f\u0440\u0435\u0432\u044b\u0448\u0435\u043d\u0438\u0435 \u043a\u0432\u043e\u0442\u044b &#8212; \u0447\u0435\u0440\u0435\u0437 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441-\u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440.<\/p>\n<pre><code class=\"python\">     class APIKey:     \"\"\"\u041e\u0431\u0435\u0440\u0442\u043a\u0430 \u0434\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e API \u043a\u043b\u044e\u0447\u0430\"\"\"     def __init__(self, key: str):         self.key = key         self.service = build(\"youtube\", \"v3\", developerKey=key, cache_discovery=False)         self.used_units = 0         self.active = True  class KeyManager:     \"\"\"\u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u0443\u043b\u043e\u043c \u043a\u043b\u044e\u0447\u0435\u0439, \u0440\u043e\u0442\u0438\u0440\u0443\u0435\u0442 \u0438\u0445 \u0438 \u043e\u0442\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u043f\u0440\u0438 \u0438\u0441\u0447\u0435\u0440\u043f\u0430\u043d\u0438\u0438 \u043a\u0432\u043e\u0442\u044b\"\"\"     def __init__(self, keys: list[str]):         self.keys = [APIKey(k) for k in keys]         self.index = 0      def get_key(self) -&gt; APIKey:         # \u0418\u0449\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u043f\u043e \u043a\u0440\u0443\u0433\u0443         for _ in range(len(self.keys)):             api = self.keys[self.index]             self.index = (self.index + 1) % len(self.keys) # \u0426\u0438\u043a\u043b\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0441\u0434\u0432\u0438\u0433             if api.active:                 return api         # \u0415\u0441\u043b\u0438 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u043a\u043b\u044e\u0447\u0435\u0439 \u043d\u0435 \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c         raise QuotaExceededAllKeys()      def deactivate(self, api: APIKey):         api.active = False         logger.warning(f\"\u0414\u0435\u0430\u043a\u0442\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u043d \u043a\u043b\u044e\u0447: {api.key}\")      def execute(self, fn, units=0, backoff_max=3):         # \u042d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 - \"\u043e\u0431\u0435\u0440\u0442\u043a\u0430\" \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0432\u044b\u0437\u043e\u0432\u043e\u0432 API         attempt = 0         while True:             api = self.get_key() # \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u043a\u043b\u044e\u0447             try:                 resp = fn(api.service).execute()                 # ... \u043b\u043e\u0433\u0438\u043a\u0430 \u043f\u043e\u0434\u0441\u0447\u0435\u0442\u0430 \u0440\u0430\u0441\u0445\u043e\u0434\u0430 ...                 return resp             except HttpError as e:                 err_str = str(e)                 if 'quotaExceeded' in err_str:                     self.deactivate(api) # \u041a\u043b\u044e\u0447 \"\u0441\u0433\u043e\u0440\u0435\u043b\", \u0434\u0435\u0430\u043a\u0442\u0438\u0432\u0438\u0440\u0443\u0435\u043c \u0438 \u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439                     continue                 if 'rateLimitExceeded' in err_str and attempt &lt; backoff_max:                     # \u0421\u043b\u0438\u0448\u043a\u043e\u043c \u0447\u0430\u0441\u0442\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u0436\u0434\u0435\u043c \u0438 \u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0441\u043d\u043e\u0432\u0430 (Exponential Backoff)                     delay = 2 ** attempt                     logger.warning(f\"Rate limit, \u0436\u0434\u0443 {delay}s...\")                     time.sleep(delay)                     attempt += 1                     continue                 # \u0414\u0440\u0443\u0433\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430, \u043f\u0440\u043e\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u043c \u043d\u0430\u0432\u0435\u0440\u0445                 raise     IGNORE_WHEN_COPYING_START content_copy download Use code with caution. Python IGNORE_WHEN_COPYING_END <\/code><\/pre>\n<p><strong>\u0427\u0442\u043e \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442?<\/strong><\/p>\n<ul>\n<li>\n<p>APIKey \u2014 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043a\u043b\u0430\u0441\u0441-\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0434\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0430, \u0435\u0433\u043e \u0441\u0442\u0430\u0442\u0443\u0441\u0430 \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0434\u043b\u044f \u043d\u0435\u0433\u043e service \u043e\u0431\u044a\u0435\u043a\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>KeyManager \u2014 \u043c\u043e\u0437\u0433 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438. \u041c\u0435\u0442\u043e\u0434 <code>get_key() <\/code>\u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0442\u0434\u0430\u0435\u0442 \u043a\u043b\u044e\u0447, \u0430 \u0438\u0449\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 <em>\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0439<\/em> \u043a\u043b\u044e\u0447 \u0432 \u0441\u043f\u0438\u0441\u043a\u0435. \u0415\u0441\u043b\u0438 \u043a\u043b\u044e\u0447 \u0438\u0441\u0447\u0435\u0440\u043f\u0430\u043b \u043a\u0432\u043e\u0442\u0443, \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043c\u0435\u0447\u0435\u043d \u043a\u0430\u043a <code>active = False<\/code> \u0438 \u043f\u0440\u043e\u043f\u0443\u0449\u0435\u043d.<\/p>\n<\/li>\n<li>\n<p><strong>execute() &#8212; <\/strong>\u00a0\u0412\u043c\u0435\u0441\u0442\u043e \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u0432 \u043a\u043e\u0434\u0435 \u043f\u0438\u0441\u0430\u0442\u044c <a href=\"http:\/\/youtube.search\" rel=\"noopener noreferrer nofollow\"><code>youtube.search<\/code><\/a><code>().list(...).execute()<\/code>, \u043f\u0438\u0448\u0435\u043c <code>key_manager.execute(lambda svc: <\/code><a href=\"http:\/\/svc.search\" rel=\"noopener noreferrer nofollow\"><code>svc.search<\/code><\/a><code>().list(...)<\/code>). \u042d\u0442\u0430 \u043e\u0431\u0435\u0440\u0442\u043a\u0430 \u0441\u0430\u043c\u0430:<\/p>\n<ol>\n<li>\n<p>\u0412\u043e\u0437\u044c\u043c\u0435\u0442 \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u043a\u043b\u044e\u0447 \u0438\u0437 \u043f\u0443\u043b\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u0438\u0442 \u0437\u0430\u043f\u0440\u043e\u0441.<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u043f\u043e\u0439\u043c\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0443 <code>quotaExceeded<\/code>, \u0434\u0435\u0430\u043a\u0442\u0438\u0432\u0438\u0440\u0443\u0435\u0442 \u043a\u043b\u044e\u0447 \u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043a\u043b\u044e\u0447\u043e\u043c.<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u043f\u043e\u0439\u043c\u0430\u0435\u0442 <code>rateLimitExceeded <\/code>(\u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0443), \u043f\u043e\u0434\u043e\u0436\u0434\u0435\u0442 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0438 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u0442 \u0441\u043d\u043e\u0432\u0430.<\/p>\n<\/li>\n<\/ol>\n<\/li>\n<li>\n<p>\u042d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043a\u043e\u0434 \u0447\u0443\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0441\u0442\u044b\u043c \u0438 \u0438\u0437\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u043d\u0430\u0441 \u043e\u0442 \u0434\u0435\u0441\u044f\u0442\u043a\u043e\u0432 <code>try-except<\/code> \u0431\u043b\u043e\u043a\u043e\u0432.<\/p>\n<h3>\u0427\u0430\u0441\u0442\u044c 3. \u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438 \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/h3>\n<p>\u0421\u043a\u0440\u0438\u043f\u0442, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0442\u044b\u0441\u044f\u0447\u0438 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0445 \u0441\u043b\u043e\u0432, \u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0447\u0430\u0441\u0430\u043c\u0438. \u041d\u043e \u0435\u0441\u043b\u0438 \u043e\u0431\u043e\u0440\u0432\u0435\u0442\u0441\u044f \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u0438\u043b\u0438 \u0432\u044b\u043a\u043b\u044e\u0447\u0438\u0442\u0441\u044f \u0441\u0432\u0435\u0442? \u0423 \u043c\u0435\u043d\u044f \u0442\u0430\u043a\u043e\u0435 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e, \u0447\u0435\u0440\u0435\u0437 2 \u0447\u0430\u0441\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u0438 \u043c\u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u043d\u0430\u0447\u0430\u0442\u044c \u0437\u0430\u043d\u043e\u0432\u043e, \u043d\u043e \u044d\u0442\u043e \u043f\u043e\u043c\u043e\u0433\u043b\u043e \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442 \u043d\u043e\u0432\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u043e\u0439\u2026 \u041f\u0435\u0440\u0441\u0438\u0441\u0442\u0435\u043d\u0442\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <code>shelve<\/code>.<\/p>\n<p>shelve \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043a\u0430\u043a \u0441\u043b\u043e\u0432\u0430\u0440\u044c (<code>dict<\/code>), \u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442 \u0441\u0432\u043e\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u0444\u0430\u0439\u043b\u0435 \u043d\u0430 \u0434\u0438\u0441\u043a\u0435.<\/p>\n<p><strong>\u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441\u0430 (progress.db):<br \/><\/strong>\u041c\u044b \u0441\u043e\u0437\u0434\u0430\u0435\u043c shelve-\u0444\u0430\u0439\u043b \u0434\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441\u0430. \u041f\u0435\u0440\u0435\u0434 \u043d\u0430\u0447\u0430\u043b\u043e\u043c \u0446\u0438\u043a\u043b\u0430 \u043c\u044b \u0447\u0438\u0442\u0430\u0435\u043c \u0438\u0437 \u043d\u0435\u0433\u043e <code>last_index<\/code>, \u0430 \u043f\u043e\u0441\u043b\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0433\u043e \u0441\u043b\u043e\u0432\u0430 \u2014 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u043d\u043e\u0432\u044b\u0439 \u0438\u043d\u0434\u0435\u043a\u0441.<\/p>\n<pre><code class=\"python\">      # \u0412 \u043d\u0430\u0447\u0430\u043b\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u0430 prog = shelve.open('progress.db') start_index = prog.get('last_index', 0) # \u0415\u0441\u043b\u0438 \u0444\u0430\u0439\u043b\u0430 \u043d\u0435\u0442, \u043d\u0430\u0447\u043d\u0435\u043c \u0441 0  # \u0412\u043d\u0443\u0442\u0440\u0438 \u0446\u0438\u043a\u043b\u0430 for idx in range(start_index, len(keywords)):     # ... \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 ...     prog['last_index'] = idx + 1 # \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0438\u043d\u0434\u0435\u043a\u0441 \u0421\u041b\u0415\u0414\u0423\u042e\u0429\u0415\u0413\u041e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430  # \u0412 \u043a\u043e\u043d\u0446\u0435 prog.close()      IGNORE_WHEN_COPYING_START  content_copy download  Use code with caution. Python IGNORE_WHEN_COPYING_END<\/code><\/pre>\n<p>\u041f\u0440\u0438 \u0442\u0430\u043a\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0435, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0441\u043a\u0440\u0438\u043f\u0442 \u0443\u043f\u0430\u0434\u0435\u0442 \u043d\u0430 5437-\u043c \u043a\u043b\u044e\u0447\u0435\u0432\u0438\u043a\u0435, \u043f\u0440\u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043e\u043d \u043d\u0430\u0447\u043d\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0443 \u0438\u043c\u0435\u043d\u043d\u043e \u0441 \u043d\u0435\u0433\u043e! \u0410 \u043d\u0435 \u0441 \u0441\u0430\u043c\u043e\u0433\u043e \u043d\u0430\u0447\u0430\u043b\u0430, \u043a\u0430\u043a \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u0432 \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u0430.<\/p>\n<h4>\u041a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 (yt_cache.db):<\/h4>\n<p>\u0412\u044b\u0437\u043e\u0432 search.list \u0441\u0442\u043e\u0438\u0442 \u0446\u0435\u043b\u044b\u0445 <strong>100 \u0435\u0434\u0438\u043d\u0438\u0446 \u043a\u0432\u043e\u0442\u044b<\/strong>. \u0415\u0441\u043b\u0438 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442 \u0434\u043b\u044f \u0442\u043e\u0433\u043e \u0436\u0435 \u043a\u043b\u044e\u0447\u0435\u0432\u0438\u043a\u0430 \u0435\u0449\u0435 \u0440\u0430\u0437, \u0431\u044b\u043b\u043e \u0431\u044b \u0433\u043b\u0443\u043f\u043e \u0442\u0440\u0430\u0442\u0438\u0442\u044c \u043a\u0432\u043e\u0442\u0443 \u0441\u043d\u043e\u0432\u0430. \u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u2014 \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0442\u0432\u0435\u0442\u043e\u0432 API.<\/p>\n<pre><code class=\"python\">      CACHE = shelve.open(\"yt_cache.db\")  def search_once(keyword: str, ...):     # ...     # \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430     cache_key = f\"S:{keyword}:{REGION}:{pageToken or ''}\"      if cache_key in CACHE:         # \u0415\u0441\u043b\u0438 \u043e\u0442\u0432\u0435\u0442 \u0435\u0441\u0442\u044c \u0432 \u043a\u044d\u0448\u0435 - \u0431\u0435\u0440\u0435\u043c \u0435\u0433\u043e \u043e\u0442\u0442\u0443\u0434\u0430         search_response = CACHE[cache_key]     else:         # \u0415\u0441\u043b\u0438 \u043d\u0435\u0442 - \u0434\u0435\u043b\u0430\u0435\u043c \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u043a API         search_response = key_manager.execute(...)         # \u0418 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u043e\u0442\u0432\u0435\u0442 \u0432 \u043a\u044d\u0448 \u0434\u043b\u044f \u0431\u0443\u0434\u0443\u0449\u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f         CACHE[cache_key] = search_response     # ...      IGNORE_WHEN_COPYING_START  content_copy download  Use code with caution. Python IGNORE_WHEN_COPYING_END<\/code><\/pre>\n<p>\u041c\u044b \u0434\u0435\u043b\u0430\u0435\u043c \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435 \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 <code>videos.list<\/code> \u0438 <code>channels.list<\/code>. \u042d\u0442\u043e \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442 \u043a\u0432\u043e\u0442\u0443 \u043f\u0440\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0445 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0445, \u043d\u043e \u0438 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u0441\u043a\u043e\u0440\u044f\u0435\u0442 \u0438\u0445.  <\/p>\n<h3>\u0427\u0430\u0441\u0442\u044c 4. \u0421\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0432\u0441\u0451 \u0432\u043c\u0435\u0441\u0442\u0435: \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0432\u043e\u0440\u043a\u0444\u043b\u043e\u0443<\/h3>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u0432\u0441\u0435 \u044d\u0442\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0432\u043c\u0435\u0441\u0442\u0435 \u0432 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 search_once.<\/p>\n<p><strong>\u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0434\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0433\u043e \u0441\u043b\u043e\u0432\u0430:<\/strong><\/p>\n<ol>\n<li>\n<p><strong>\u041f\u0430\u0433\u0438\u043d\u0430\u0446\u0438\u044f:<\/strong> YouTube \u043e\u0442\u0434\u0430\u0435\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u043c\u0438 (\u043e\u0431\u044b\u0447\u043d\u043e \u043f\u043e 50 \u0448\u0442\u0443\u043a). \u041d\u0430\u0448 \u0441\u043a\u0440\u0438\u043f\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0446\u0438\u043a\u043b while, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u0435\u043b\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0434\u043e \u0442\u0435\u0445 \u043f\u043e\u0440, \u043f\u043e\u043a\u0430 \u043d\u0435 \u043d\u0430\u0431\u0435\u0440\u0435\u0442 \u043d\u0443\u0436\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0432\u0438\u0434\u0435\u043e (<code>NUM_RESULTS<\/code>) \u0438\u043b\u0438 \u043f\u043e\u043a\u0430 \u043d\u0435 \u0437\u0430\u043a\u043e\u043d\u0447\u0430\u0442\u0441\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b (<code>nextPageToken<\/code> \u0441\u0442\u0430\u043d\u0435\u0442 <code>None<\/code>).<\/p>\n<\/li>\n<li>\n<p><strong>\u042d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u044b\u0439 \u0441\u0431\u043e\u0440 \u0434\u0430\u043d\u043d\u044b\u0445:<\/strong> \u042d\u0442\u043e \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0438 \u0441\u0430\u043c\u0430\u044f \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u044f:<\/p>\n<ul>\n<li>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u0435\u043b\u0430\u0435\u043c <strong>\u043e\u0434\u0438\u043d<\/strong> <code>search.list<\/code> \u0437\u0430\u043f\u0440\u043e\u0441 (\u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c 100 \u0435\u0434\u0438\u043d\u0438\u0446), \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c N \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432 \u0432\u0438\u0434\u0435\u043e (<code>videoId<\/code>).<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u0442\u0435\u043c \u0434\u0435\u043b\u0430\u0435\u043c <strong>\u043e\u0434\u0438\u043d<\/strong> <code>videos.list<\/code> \u0437\u0430\u043f\u0440\u043e\u0441, \u043f\u0435\u0440\u0435\u0434\u0430\u0432 \u0435\u043c\u0443 \u0432\u0441\u0435 N \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432 \u0447\u0435\u0440\u0435\u0437 \u0437\u0430\u043f\u044f\u0442\u0443\u044e (\u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c N * 1 = N \u0435\u0434\u0438\u043d\u0438\u0446).<br \/>\u042d\u0442\u043e \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0434\u0435\u0448\u0435\u0432\u043b\u0435, \u0447\u0435\u043c \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043a\u0430\u0436\u0434\u043e\u043c \u0432\u0438\u0434\u0435\u043e \u0432 search.list.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>\u041e\u0431\u043e\u0433\u0430\u0449\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445:<\/strong> \u041f\u043e\u043b\u0443\u0447\u0438\u0432 \u0441\u044b\u0440\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 API, \u043c\u044b \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u0445 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c, \u0430 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u043c \u0432 \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u0432\u0438\u0434:<\/p>\n<ul>\n<li>\n<p><code>iso2hms<\/code>: \u041f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442 PT1M35S \u0432 \u0447\u0438\u0442\u0430\u0435\u043c\u043e\u0435 00:01:35 \u0438 \u0441\u0435\u043a\u0443\u043d\u0434\u044b.<\/p>\n<\/li>\n<li>\n<p><code>fmt_age<\/code>: \u0412\u044b\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442 \u0432\u043e\u0437\u0440\u0430\u0441\u0442 \u0432\u0438\u0434\u0435\u043e \u0432 \u0433\u043e\u0434\u0430\u0445 \u0438 \u043c\u0435\u0441\u044f\u0446\u0430\u0445.<\/p>\n<\/li>\n<li>\n<p><code>safe_detect<\/code>: \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u044f\u0437\u044b\u043a \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0438 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e langdetect.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0431\u043e\u0440 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e \u043a\u0430\u043d\u0430\u043b\u0435 (\u0430\u0432\u0430\u0442\u0430\u0440\u043a\u0430) \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u0438\u043c \u0431\u0430\u0442\u0447\u0435\u0432\u044b\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c <code>channels.list<\/code> \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u043a\u0430\u043d\u0430\u043b\u043e\u0432 \u0432 \u0432\u044b\u0434\u0430\u0447\u0435.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<h3>\u0427\u0430\u0441\u0442\u044c 5. \u041e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432<\/h3>\n<p>\u0421\u043e\u0431\u0440\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u2014 \u044d\u0442\u043e \u043f\u043e\u043b\u0434\u0435\u043b\u0430. \u0418\u0445 \u043d\u0443\u0436\u043d\u043e \u043d\u0430\u0434\u0435\u0436\u043d\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c. \u0421\u043a\u0440\u0438\u043f\u0442 \u0434\u0435\u043b\u0430\u0435\u0442 \u044d\u0442\u043e \u0434\u0432\u0443\u043c\u044f \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u043c\u0438, \u0438 \u043e\u0431\u0430 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 \u0441\u0431\u043e\u0435\u0432.\u00a0<\/p>\n<p>\u041a\u0441\u0442\u0430\u0442\u0438, \u044d\u0442\u0430 \u0447\u0430\u0441\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u0440\u043e\u0434\u0438\u043b\u0430\u0441\u044c \u0437\u0430\u043a\u043e\u043d\u043e\u043c\u0435\u0440\u043d\u043e \u0438\u0437 \u0442\u0440\u0435\u0442\u044c\u0435\u0439 (\u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432), \u0442\u0430\u043a \u043a\u0430\u043a \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u044f \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043b \u0437\u0430\u043f\u0438\u0441\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u043f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430, \u043d\u043e \u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u043c \u043f\u0440\u043e\u0433\u043e\u043d\u0435 \u0432\u0441\u0435 \u0431\u044b\u043b\u043e \u0445\u043e\u0440\u043e\u0448\u043e, \u0430 \u043d\u0430 \u0431\u043e\u0435\u0432\u043e\u043c &#8212; \u043a\u043e\u0433\u0434\u0430 \u043e\u043d \u0443\u043f\u0430\u043b \u0447\u0435\u0440\u0435\u0437 2 \u0447\u0430\u0441\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0431\u044b\u043b\u043e \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u0441\u043c\u0435\u0448\u043d\u043e.<\/p>\n<p><strong>\u0417\u0430\u043f\u0438\u0441\u044c \u0432 Google Sheets:<\/strong> \u041c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043c\u0435\u0442\u043e\u0434 <code>append<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0441\u0442\u0440\u043e\u043a\u0438 \u0432 \u043a\u043e\u043d\u0435\u0446 \u0442\u0430\u0431\u043b\u0438\u0446\u044b. \u041d\u043e \u0435\u0441\u043b\u0438 API Google Sheets \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u044f \u043e\u0431\u0435\u0440\u043d\u0443\u043b \u0432\u044b\u0437\u043e\u0432 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0441 <strong>retry-\u043b\u043e\u0433\u0438\u043a\u043e\u0439<\/strong>:<\/p>\n<pre><code class=\"python\">      def append_to_sheets_with_retry(...):     for attempt in range(1, max_retries+1):         try:             # \u041f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435             service.spreadsheets().values().append(...).execute()             return True # \u0423\u0441\u043f\u0435\u0445!         except (HttpError, ConnectionResetError, socket.error) as e:             # \u0415\u0441\u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0430 \u0441\u0435\u0442\u0438, \u0436\u0434\u0435\u043c \u0438 \u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0441\u043d\u043e\u0432\u0430 \u0441 \u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d\u043d\u043e\u0439 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u043e\u0439             delay = base_delay * 2**(attempt-1)             time.sleep(delay)     return False # \u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0441\u043b\u0435 \u0432\u0441\u0435\u0445 \u043f\u043e\u043f\u044b\u0442\u043e\u043a      IGNORE_WHEN_COPYING_START  content_copy download  Use code with caution. Python IGNORE_WHEN_COPYING_END<\/code><\/pre>\n<p><strong>\u041f\u0430\u043a\u0435\u0442\u043d\u043e\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 (Batching):<\/strong> \u0414\u0435\u043b\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441 \u043a Google Sheets \u043f\u043e\u0441\u043b\u0435 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0433\u043e \u0441\u043b\u043e\u0432\u0430 \u2014 \u043d\u0435\u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u0438 \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u043e. \u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u043d\u0430\u043a\u0430\u043f\u043b\u0438\u0432\u0430\u0435\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 <code>batch_res<\/code> \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0438\u0445 \u0432\u0441\u0435 \u0432\u043c\u0435\u0441\u0442\u0435, \u043a\u043e\u0433\u0434\u0430 \u0438\u0445 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0434\u043e\u0441\u0442\u0438\u0433\u043d\u0435\u0442 <code>BATCH_SIZE<\/code>. \u042d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u043d\u0438\u0436\u0430\u0435\u0442 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e API-\u0432\u044b\u0437\u043e\u0432\u043e\u0432 \u0438 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443. \u0422\u043e\u0447\u043d\u043e \u0442\u0430\u043a\u0430\u044f \u0436\u0435 \u043b\u043e\u0433\u0438\u043a\u0430 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0438 \u0434\u043b\u044f \u0434\u043e\u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 CSV-\u0444\u0430\u0439\u043b.<\/p>\n<pre><code class=\"python\">     # \u0412 \u0433\u043b\u0430\u0432\u043d\u043e\u043c \u0446\u0438\u043a\u043b\u0435 batch_res.extend(res)  if (idx + 1 - start) % BATCH_SIZE == 0:     # \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u043d\u0430\u043a\u043e\u043f\u043b\u0435\u043d\u043d\u044b\u0439 \u0431\u0430\u0442\u0447     append_csv_batch(df_batch, OUTPUT_CSV)     append_to_sheets_with_retry(...)     batch_res = [] # \u041e\u0447\u0438\u0449\u0430\u0435\u043c \u0431\u0430\u0442\u0447 \u0434\u043b\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u043f\u043e\u0440\u0446\u0438\u0438  # ... \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0446\u0438\u043a\u043b\u0430 \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0435\u043c \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043e\u0441\u0442\u0430\u0442\u043e\u043a if batch_res:     # ... \u043b\u043e\u0433\u0438\u043a\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0431\u0430\u0442\u0447\u0430     IGNORE_WHEN_COPYING_START content_copy download Use code with caution. Python IGNORE_WHEN_COPYING_END<\/code><\/pre>\n<h3>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h3>\n<p>\u042f \u0431\u044b \u043d\u0430\u0432\u0435\u0440\u043d\u043e\u0435 \u043d\u0430\u0437\u0432\u0430\u043b \u044d\u0442\u043e\u0442 \u0441\u043a\u0440\u0438\u043f\u0442 &#8212; \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u043c \u0434\u043b\u044f \u043d\u0430\u0434\u0435\u0436\u043d\u043e\u0439 \u0438 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 YouTube API, \u0435\u0441\u043b\u0438 \u0431\u044b \u0431\u044b\u043b \u0447\u0443\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0430\u043c\u0431\u0438\u0446\u0438\u043e\u0437\u043d\u044b\u043c. \u0418 \u0432\u0441\u0435 \u0436\u0435 &#8212; \u0441\u043a\u0440\u0438\u043f\u0442 \u0443\u043c\u0435\u0435\u0442 \u0440\u043e\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043b\u044e\u0447\u0438, \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f, \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0438 \u0438 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0442\u044c \u043f\u0430\u043a\u0435\u0442\u043d\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c.<\/p>\n<p>\u0422\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043e\u0431\u044a\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0445, \u0431\u0435\u0437 \u043f\u043e\u0442\u0435\u0440\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438.<\/p>\n<p><strong>\u0427\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c, \u043d\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0435 \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u044e.<\/strong><\/p>\n<ul>\n<li>\n<p><strong>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0441\u0442\u044c:<\/strong> \u0414\u043b\u044f \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0435\u0442\u0435\u0432\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c asyncio \u0438 aiohttp, \u0447\u0442\u043e\u0431\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e API-\u0432\u044b\u0437\u043e\u0432\u043e\u0432 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e.<\/p>\n<\/li>\n<li>\n<p><strong>\u041f\u0440\u043e\u043a\u0441\u0438:<\/strong> \u0414\u043b\u044f \u043e\u0447\u0435\u043d\u044c \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043e\u0431\u044a\u0435\u043c\u043e\u0432 \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0440\u043e\u0442\u0430\u0446\u0438\u044e \u043f\u0440\u043e\u043a\u0441\u0438 \u0432 KeyManager.<\/p>\n<\/li>\n<li>\n<p><strong>\u0411\u043e\u043b\u0435\u0435 \u0433\u0440\u0430\u043d\u0443\u043b\u044f\u0440\u043d\u044b\u0439 part:<\/strong> \u0412 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445 videos.list \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c \u043d\u0435 \u0432\u0441\u0435 \u0447\u0430\u0441\u0442\u0438 (snippet,contentDetails,&#8230;), \u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435, \u0447\u0442\u043e \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u043d\u0443\u0436\u043d\u044b, \u0435\u0449\u0435 \u0441\u0438\u043b\u044c\u043d\u0435\u0435 \u044d\u043a\u043e\u043d\u043e\u043c\u044f \u043a\u0432\u043e\u0442\u0443.<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043d\u0430<\/strong><a href=\"https:\/\/github.com\/kentavr009\/Youtube-Parser\" rel=\"noopener noreferrer nofollow\"><strong> GitHub<\/strong><\/a><strong>.<\/strong><\/p>\n<p><strong>\u041d\u043e, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0440\u0430\u0437\u0434\u0440\u0430\u0436\u0430\u0442\u044c \u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0432\u043e\u0442 \u043f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u043d\u0438\u0436\u0435:<\/strong><\/p>\n<pre><code class=\"python\">#!\/usr\/bin\/env python3 # -*- coding: utf-8 -*- \"\"\" YouTube-\u043f\u0430\u0440\u0441\u0435\u0440: Shorts + \u043e\u0431\u044b\u0447\u043d\u044b\u0435 \u0440\u043e\u043b\u0438\u043a\u0438, \u0431\u0435\u0437 live\/upcoming. \u0421\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0441\u043b\u043e\u0432\u0430 (col A) \u0438 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0435 URL (col J) \u0438\u0437 Google Sheets \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u0432 \u043b\u0438\u0441\u0442 \"Results\". \u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u0442 \u0441 \u043c\u0435\u0441\u0442\u0430 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0447\u0435\u0440\u0435\u0437 shelve. \u041f\u0440\u0438 \u0438\u0441\u0447\u0435\u0440\u043f\u0430\u043d\u0438\u0438 \u043a\u0432\u043e\u0442\u044b \u0432\u0441\u0435\u0445 \u043a\u043b\u044e\u0447\u0435\u0439 \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0443\u0436\u0435 \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435. \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441 \u043a\u0430\u0436\u0434\u044b\u0435 BATCH_SIZE \u043a\u043b\u044e\u0447\u0435\u0439. \"\"\" import os import sys import shelve import time import logging import socket from pathlib import Path from datetime import datetime, timezone  import pandas as pd import isodate from langdetect import detect, LangDetectException from dotenv import load_dotenv, dotenv_values from googleapiclient.discovery import build from googleapiclient.errors import HttpError from google.oauth2 import service_account  # \u2500\u2500\u2500 Logging \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 logging.basicConfig(     level=logging.INFO,     format='%(asctime)s %(levelname)s %(message)s',     datefmt='%Y-%m-%d %H:%M:%S' ) logger = logging.getLogger(__name__)  # \u2500\u2500\u2500 \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f (\u0438\u0437 .env) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 # \u042f\u0432\u043d\u043e \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043f\u0443\u0442\u044c \u043a .env \u0440\u044f\u0434\u043e\u043c \u0441\u043e \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u043c \u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 env_path = Path(__file__).parent \/ \".env\" if not env_path.exists():     logger.error(f\"\u274c .env \u0444\u0430\u0439\u043b \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d \u043f\u043e \u043f\u0443\u0442\u0438 {env_path}\")     sys.exit(1)  load_dotenv(dotenv_path=env_path, override=True) SHEET_ID = os.getenv(\"SHEET_ID\") logger.info(f\"\ud83d\udea9 Loaded SHEET_ID from {env_path}: {SHEET_ID}\")  KEYWORDS_SHEET       = os.getenv(\"KEYWORDS_SHEET\", \"Keywords\") RESULTS_SHEET        = os.getenv(\"RESULTS_SHEET\", \"Results\") SERVICE_ACCOUNT_JSON = os.getenv(\"SERVICE_ACCOUNT_JSON\") NUM_RESULTS          = int(os.getenv(\"NUM_RESULTS\", 10)) REGION               = os.getenv(\"REGION\", \"US\") MAX_PAGES            = int(os.getenv(\"MAX_PAGES\", 1)) OUTPUT_CSV           = os.getenv(\"OUTPUT_CSV\", \"yt_results.csv\") BATCH_SIZE           = int(os.getenv(\"BATCH_SIZE\", 50))  if MAX_PAGES &lt; 1:     sys.exit(\"\u274c MAX_PAGES \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u2265 1\")  # \u2500\u2500\u2500 Google Sheets API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 SCOPES = ['https:\/\/www.googleapis.com\/auth\/spreadsheets'] creds_sheets = service_account.Credentials.from_service_account_file(     SERVICE_ACCOUNT_JSON, scopes=SCOPES ) sheets_service = build(     'sheets', 'v4',     credentials=creds_sheets,     cache_discovery=False )  # \u2500\u2500\u2500 \u0425\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u043a\u0435\u0448\u0430 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 CACHE = shelve.open(\"yt_cache.db\")  # \u2500\u2500\u2500 \u041e\u0448\u0438\u0431\u043a\u0430 \u0438\u0441\u0447\u0435\u0440\u043f\u0430\u043d\u0438\u044f \u043a\u0432\u043e\u0442\u044b \u0432\u0441\u0435\u0445 \u043a\u043b\u044e\u0447\u0435\u0439 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 class QuotaExceededAllKeys(Exception):     \"\"\"\u0412\u0441\u0435 \u043a\u043b\u044e\u0447\u0438 YouTube API \u0438\u0441\u0447\u0435\u0440\u043f\u0430\u043b\u0438 \u043a\u0432\u043e\u0442\u0443\"\"\"     pass  # \u2500\u2500\u2500 \u041a\u043b\u0430\u0441\u0441\u044b \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f API-\u043a\u043b\u044e\u0447\u0430\u043c\u0438 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 class APIKey:     def __init__(self, key: str):         self.key = key         self.service = build(             \"youtube\", \"v3\",             developerKey=key,             cache_discovery=False         )         self.used_units = 0         self.active = True  class KeyManager:     def __init__(self, keys: list[str]):         self.keys = [APIKey(k) for k in keys]         self.index = 0      def get_key(self) -&gt; APIKey:         n = len(self.keys)         for _ in range(n):             api = self.keys[self.index]             self.index = (self.index + 1) % n             if api.active:                 return api         raise QuotaExceededAllKeys()      def deactivate(self, api: APIKey):         api.active = False         logger.warning(f\"\u0414\u0435\u0430\u043a\u0442\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u043d \u043a\u043b\u044e\u0447: {api.key}\")      def record(self, api: APIKey, units: int):         api.used_units += units         logger.info(f\"\u041a\u043b\u044e\u0447 {api.key}: \u0440\u0430\u0441\u0445\u043e\u0434 {units} units (\u0438\u0442\u043e\u0433\u043e {api.used_units})\")      def execute(self, fn, units=0, backoff_max=3):         attempt = 0         while True:             api = self.get_key()             try:                 resp = fn(api.service).execute()                 used = units(resp) if callable(units) else units                 self.record(api, used)                 return resp             except HttpError as e:                 err_str = str(e)                 if 'quotaExceeded' in err_str or 'dailyLimitExceeded' in err_str:                     self.deactivate(api)                     continue                 if 'rateLimitExceeded' in err_str:                     if attempt &lt; backoff_max:                         delay = 2 ** attempt                         logger.warning(                             f\"Rate limitExceeded \u043d\u0430 \u043a\u043b\u044e\u0447\u0435 {api.key}, \u0436\u0434\u0443 {delay}s (\u043f\u043e\u043f\u044b\u0442\u043a\u0430 {attempt+1})\"                         )                         time.sleep(delay)                         attempt += 1                         continue                     else:                         self.deactivate(api)                         continue                 logger.error(f\"Unexpected HttpError \u043d\u0430 \u043a\u043b\u044e\u0447\u0435 {api.key}: {e}\")                 raise             except (ConnectionResetError, socket.error) as e:                 if attempt &lt; backoff_max:                     delay = 2 ** attempt                     logger.warning(                         f\"Connection error \u043d\u0430 \u043a\u043b\u044e\u0447\u0435 {api.key}: {e}, \u0436\u0434\u0443 {delay}s (\u043f\u043e\u043f\u044b\u0442\u043a\u0430 {attempt+1})\"                     )                     time.sleep(delay)                     attempt += 1                     continue                 else:                     self.deactivate(api)                     continue  # \u2500\u2500\u2500 \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043b\u044e\u0447\u0435\u0439 YouTube API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 raw_keys = os.getenv(\"YT_API_KEYS\") or dotenv_values(env_path).get(\"YT_API_KEYS\", \"\") KEYS = [k.strip() for k in raw_keys.split(\",\") if k.strip()] if not KEYS:     sys.exit(\"\u274c \u041d\u0435\u0442 API-\u043a\u043b\u044e\u0447\u0435\u0439 (YT_API_KEYS).\") logger.info(f\"\ud83d\udd11 \u041d\u0430\u0439\u0434\u0435\u043d\u043e {len(KEYS)} \u043a\u043b\u044e\u0447\u0435\u0439\") key_manager = KeyManager(KEYS)  VIDEO_PARTS = \"snippet,contentDetails,status,player,statistics\"  # \u2500\u2500\u2500 \u0423\u0442\u0438\u043b\u0438\u0442\u044b \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 def iso2hms(iso: str):     if not iso:         return \"\", 0     td = isodate.parse_duration(iso)     s = int(td.total_seconds())     h, r = divmod(s, 3600)     m, sec = divmod(r, 60)     return f\"{h:02d}:{m:02d}:{sec:02d}\", s  def fmt_age(pub: str):     if not pub:         return \"\"     dt = datetime.fromisoformat(pub.replace('Z', '+00:00'))     d = (datetime.now(timezone.utc) - dt).days     y, rem = divmod(d, 365)     mo = rem \/\/ 30     return f\"{y} years {mo} months\" if y else f\"{mo} months\"  def safe_detect(txt: str):     try:         return detect(txt) if txt.strip() else \"\"     except LangDetectException:         return \"\"  # \u2500\u2500\u2500 \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 Google Sheets \u0438 CSV \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 def append_to_sheets_with_retry(service, spreadsheet_id, sheet_range, values,                                 max_retries=5, base_delay=1):     for attempt in range(1, max_retries+1):         try:             service.spreadsheets().values().append(                 spreadsheetId=spreadsheet_id,                 range=sheet_range,                 valueInputOption='RAW',                 body={'values': values}             ).execute()             logger.info(\"\u2705 \u0423\u0441\u043f\u0435\u0448\u043d\u043e \u0437\u0430\u043f\u0438\u0441\u0430\u043b\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0432 Google Sheets\")             return True         except (HttpError, ConnectionResetError, socket.error) as e:             delay = base_delay * 2**(attempt-1)             logger.warning(                 f\"\u26a0\ufe0f \u041f\u043e\u043f\u044b\u0442\u043a\u0430 {attempt}\/{max_retries} \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 Sheets \u0443\u043f\u0430\u043b\u0430: {e}. \u0416\u0434\u0451\u043c {delay}s.\"             )             time.sleep(delay)     logger.error(\"\u274c \u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0432 Google Sheets \u043f\u043e\u0441\u043b\u0435 \u0432\u0441\u0435\u0445 \u043f\u043e\u043f\u044b\u0442\u043e\u043a\")     return False  def save_csv_with_retry(df: pd.DataFrame, path: str, max_retries=3, base_delay=1):     for attempt in range(1, max_retries+1):         try:             df.to_csv(path, index=False)             logger.info(f\"\u2705 CSV \u0441\u043e\u0445\u0440\u0430\u043d\u0451\u043d: {path}\")             return True         except Exception as e:             delay = base_delay * 2**(attempt-1)             logger.warning(                 f\"\u26a0\ufe0f \u041f\u043e\u043f\u044b\u0442\u043a\u0430 {attempt}\/{max_retries} \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f CSV \u0443\u043f\u0430\u043b\u0430: {e}. \u0416\u0434\u0451\u043c {delay}s.\"             )             time.sleep(delay)     logger.error(\"\u274c \u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c CSV \u043f\u043e\u0441\u043b\u0435 \u0432\u0441\u0435\u0445 \u043f\u043e\u043f\u044b\u0442\u043e\u043a\")     return False  def append_csv_batch(df: pd.DataFrame, path: str, max_retries=3, base_delay=1) -&gt; bool:     \"\"\"\u0414\u043e\u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 DataFrame \u0432 CSV, \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u044f \u0444\u0430\u0439\u043b \u0441 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u043c, \u0435\u0441\u043b\u0438 \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442.\"\"\"     p = Path(path)     header = not p.exists()     for attempt in range(1, max_retries+1):         try:             df.to_csv(path, index=False, header=header, mode='a')             logger.info(f\"\u2705 CSV \u0431\u0430\u0442\u0447 \u0441\u043e\u0445\u0440\u0430\u043d\u0451\u043d ({len(df)} \u0441\u0442\u0440\u043e\u043a): {path}\")             return True         except Exception as e:             delay = base_delay * 2**(attempt-1)             logger.warning(f\"\u26a0\ufe0f \u041f\u043e\u043f\u044b\u0442\u043a\u0430 {attempt}\/{max_retries} \u0434\u043e\u0437\u0430\u043f\u0438\u0441\u0438 CSV \u0443\u043f\u0430\u043b\u0430: {e}. \u0416\u0434\u0451\u043c {delay}s.\")             time.sleep(delay)     logger.error(\"\u274c \u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0434\u043e\u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c CSV \u043f\u043e\u0441\u043b\u0435 \u0432\u0441\u0435\u0445 \u043f\u043e\u043f\u044b\u0442\u043e\u043a\")     return False  # \u2500\u2500\u2500 \u041f\u043e\u0438\u0441\u043a YouTube \u0432\u0438\u0434\u0435\u043e \u043f\u043e \u043a\u043b\u044e\u0447\u0443 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 def search_once(keyword: str, input_url: str) -&gt; list:     rows, token, page = [], None, 0     while len(rows) &lt; NUM_RESULTS and page &lt; MAX_PAGES:         page += 1         sk = f\"S:{keyword}:{REGION}:{token or ''}\"         if sk in CACHE:             sr = CACHE[sk]         else:             sr = key_manager.execute(                 lambda svc: svc.search().list(                     q=keyword,                     part=\"id\",                     type=\"video\",                     order=\"relevance\",                     regionCode=REGION,                     maxResults=min(50, NUM_RESULTS - len(rows)),                     pageToken=token or \"\",                     safeSearch=\"none\"                 ),                 units=100             )             CACHE[sk] = sr         vids = [it.get('id', {}).get('videoId') for it in sr.get('items', []) if it.get('id', {}).get('videoId')]         if not vids:             break         vk = f\"V:{','.join(vids)}\"         if vk in CACHE:             vr = CACHE[vk]         else:             vr = key_manager.execute(                 lambda svc: svc.videos().list(                     id=\",\".join(vids),                     part=VIDEO_PARTS                 ),                 units=lambda resp: len(resp.get('items', []))             )             CACHE[vk] = vr         cids = list({it['snippet']['channelId'] for it in vr.get('items', [])})         amap = {}         if cids:             ck = f\"C:{','.join(cids)}\"             if ck in CACHE:                 ch = CACHE[ck]             else:                 ch = key_manager.execute(                     lambda svc: svc.channels().list(                         part=\"snippet\",                         id=\",\".join(cids)                     ),                     units=1                 )                 CACHE[ck] = ch             amap = {c['id']: c['snippet']['thumbnails']['default']['url'] for c in ch.get('items', [])}         for it in vr.get('items', []):             sn = it.get('snippet', {})             if sn.get('liveBroadcastContent') in {'live', 'upcoming'}:                 continue             det = it.get('contentDetails', {})             dur_str, dur_s = iso2hms(det.get('duration', ''))             st = it.get('status', {})             stats = it.get('statistics', {})             author = sn.get('channelTitle', '')             avatar = amap.get(sn.get('channelId', ''), '')             if sn.get('defaultAudioLanguage'):                 ls, lang = 'audio', sn['defaultAudioLanguage']             elif sn.get('defaultLanguage'):                 ls, lang = 'default', sn['defaultLanguage']             else:                 ls, lang = 'detect', safe_detect(sn.get('title', '') + ' ' + sn.get('description', '')) or 'unknown'             lic = st.get('license', '')             emb = st.get('embeddable', False)             allowed = emb and lic == 'creativeCommon'             rows.append([                 keyword, input_url, it['id'], sn.get('title', ''), sn.get('description', ''),                 lang, ls, 'short' if dur_s &lt; 60 else 'video',                 dur_str, dur_s, fmt_age(sn.get('publishedAt', '')), author, avatar,                 stats.get('viewCount', ''), stats.get('likeCount', ''), stats.get('dislikeCount', ''),                 emb, lic, allowed,                 it.get('player', {}).get('embedHtml', f\"&lt;iframe src=\\\"https:\/\/www.youtube.com\/embed\/{it['id']}\\\" allowfullscreen&gt;&lt;\/iframe&gt;\")             ])         token = sr.get('nextPageToken') or None     return rows  # \u2500\u2500\u2500 \u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 r1 = sheets_service.spreadsheets().values().get(     spreadsheetId=SHEET_ID,     range=f\"{KEYWORDS_SHEET}!A2:A\" ).execute() r2 = sheets_service.spreadsheets().values().get(     spreadsheetId=SHEET_ID,     range=f\"{KEYWORDS_SHEET}!J2:J\" ).execute() keywords = [r[0] for r in r1.get('values', [])] input_urls = [r[0] for r in r2.get('values', [])]  prog = shelve.open('progress.db') start = prog.get('last_index', 0) all_res = [] batch_res = []  try:     for idx in range(start, len(keywords)):         kw = keywords[idx]         input_url = input_urls[idx] if idx &lt; len(input_urls) else ''         logger.info(f\"\ud83d\udd0d [{idx}] {kw}\")         res = search_once(kw, input_url)          all_res.extend(res)         batch_res.extend(res)         prog['last_index'] = idx + 1          # \u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0431\u0430\u0442\u0447\u0430 \u043a\u0430\u0436\u0434\u044b\u0435 BATCH_SIZE \u043a\u043b\u044e\u0447\u0435\u0439         if (idx + 1 - start) % BATCH_SIZE == 0:             df_batch = pd.DataFrame(batch_res, columns=[                 'keyword','input_url','videoId','title','description','language','language_source',                 'video_type','duration','duration_seconds','age','author','author_avatar',                 'view_count','like_count','dislike_count','embeddable','license',                 'allowed_on_third_party','iframe'             ])             append_csv_batch(df_batch, OUTPUT_CSV)             append_to_sheets_with_retry(                 sheets_service,                 SHEET_ID,                 f\"{RESULTS_SHEET}!A2\",                 batch_res             )             logger.info(f\"\ud83d\udd04 \u0411\u0430\u0442\u0447 \u0438\u0437 {len(batch_res)} \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u0441\u043e\u0445\u0440\u0430\u043d\u0451\u043d \u043f\u043e\u0441\u043b\u0435 {(idx+1-start)} \u043a\u043b\u044e\u0447\u0435\u0439\")             batch_res = []  except QuotaExceededAllKeys:     logger.warning(\"\u26a0\ufe0f \u0412\u0441\u0435 \u043a\u043b\u044e\u0447\u0438 \u0438\u0441\u0447\u0435\u0440\u043f\u0430\u043b\u0438 \u043a\u0432\u043e\u0442\u0443, \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0443\") finally:     prog.close()     CACHE.close()  # \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u043e\u0441\u0442\u0430\u0442\u043e\u043a \u0431\u0430\u0442\u0447\u0430 \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f if batch_res:     df_batch = pd.DataFrame(batch_res, columns=[         'keyword','input_url','videoId','title','description','language','language_source',         'video_type','duration','duration_seconds','age','author','author_avatar',         'view_count','like_count','dislike_count','embeddable','license',         'allowed_on_third_party','iframe'     ])     append_csv_batch(df_batch, OUTPUT_CSV)     append_to_sheets_with_retry(         sheets_service,         SHEET_ID,         f\"{RESULTS_SHEET}!A2\",         batch_res     )     logger.info(f\"\ud83d\udd04 \u0424\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0431\u0430\u0442\u0447 \u0438\u0437 {len(batch_res)} \u0441\u0442\u0440\u043e\u043a \u0441\u043e\u0445\u0440\u0430\u043d\u0451\u043d\")  # \u0418\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u0440\u0430\u0441\u0445\u043e\u0434 \u043a\u0432\u043e\u0442\u044b total_units = sum(api.used_units for api in key_manager.keys) logger.info(f\"\u2139\ufe0f \u0412\u0441\u0435\u0433\u043e \u0440\u0430\u0441\u0445\u043e\u0434: {total_units} units\") <\/code><\/pre>\n<p>\u0421\u043a\u0440\u0438\u043f\u0442 \u0432\u044b\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u043a \u0435\u0441\u0442\u044c, \u0441\u0432\u043e\u044e \u0440\u0430\u0431\u043e\u0442\u0443 \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u043e\u043d \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043b. \u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u044d\u0442\u0430\u043f &#8212; \u043e\u0447\u0438\u0441\u0442\u043a\u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u043e\u0442 \u043c\u0443\u0441\u043e\u0440\u0430, \u0435\u0435 \u044f \u0443\u0436\u0435 \u043f\u0440\u043e\u0432\u0435\u043b \u0438 \u0441\u043a\u043e\u0440\u043e \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043a\u0430\u043a \u0438 \u0433\u043b\u0430\u0432\u043d\u043e\u0435 \u0447\u0435\u043c.\u00a0<\/p>\n<\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/916114\/\"> https:\/\/habr.com\/ru\/articles\/916114\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041f\u0443\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043f\u0430\u0440\u0441\u0435\u0440\u043e\u0432 \u0442\u0435\u0440\u043d\u0438\u0441\u0442 \u0438 \u0441\u043b\u043e\u0436\u0435\u043d, \u0441\u043f\u0435\u0440\u0432\u0430 \u0442\u044b \u043f\u044b\u0442\u0430\u0435\u0448\u044c\u0441\u044f \u043e\u0431\u043e\u0439\u0442\u0438 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0442\u0430\u043a \u043f\u0440\u043e\u0449\u0435, \u0442\u0430\u043a \u043d\u0435\u0442\u0443 \u043a\u0432\u043e\u0442 \u0438 \u0440\u0430\u0437\u043d\u044b\u0445 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439. \u041f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u043c\u0443\u0447\u0430\u044f\u0441\u044c \u0441 Selenium, \u0432 \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u0443\u0433\u043d\u0430\u0442\u044c\u0441\u044f \u0437\u0430 \u043c\u0435\u043d\u044f\u044e\u0449\u0435\u0439\u0441\u044f \u0432\u0435\u0440\u0441\u0442\u043a\u043e\u0439 YouTube. \u041a\u0442\u043e-\u0442\u043e \u043f\u0438\u0448\u0435\u0442 \u043f\u0440\u043e\u0441\u0442\u044b\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u044b \u043d\u0430 requests, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0430\u0434\u0430\u044e\u0442 \u043f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u0439 \u0436\u0435 \u043e\u0448\u0438\u0431\u043a\u0435. \u0418 \u043a\u0443\u0434\u0430 \u0432\u0430\u0441 \u0432\u0441\u0435 \u044d\u0442\u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043f\u0440\u0438\u0432\u043e\u0434\u044f\u0442? <\/p>\n<p>\u0421\u043d\u043e\u0432\u0430 \u043a\u043e \u043c\u043d\u0435 &#8212; \u043a \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u043c\u0443 <strong>YouTube Data API v3<\/strong>. <\/p>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/68429ea880f398ebcd350292\" data-style=\"\" id=\"68429ea880f398ebcd350292\" width=\"\"><\/div>\n<blockquote>\n<p>\u0412\u0435\u0440\u043e\u044f\u0442\u043d\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0447\u0442\u043e \u0442\u043e \u0431\u043e\u043b\u0435\u0435 \u0438\u0437\u044f\u0449\u043d\u043e\u0435, \u043d\u043e \u043c\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0438 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0438 \u0443 \u0432\u0430\u0441.<\/p>\n<\/blockquote>\n<p>\u041d\u043e \u0441 \u044d\u0442\u0438\u043c \u0410\u041f\u0418 \u0432\u0441\u0435 \u0441\u043e\u0432\u0441\u0435\u043c \u043d\u0435 \u0442\u0430\u043a \u043f\u0440\u043e\u0441\u0442\u043e, \u043a\u0430\u043a \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434. \u0425\u043e\u0440\u043e\u0448\u043e, \u0432\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c \u0441 Cloud Console (\u0411\u0440\u0430\u0432\u043e!), \u0434\u0430\u0436\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 API-\u043a\u043b\u044e\u0447 \u0438 \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u0410\u041f\u0418, \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438 \u043f\u0430\u0440\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432&#8230; \u0438 \u0447\u0435\u0440\u0435\u0437 15 \u043c\u0438\u043d\u0443\u0442 (\u0430 \u043c\u043e\u0436\u0435\u0442 \u0434\u0430\u0436\u0435 \u0440\u0430\u043d\u044c\u0448\u0435) \u0443\u043f\u0435\u0440\u043b\u0438\u0441\u044c \u0432 quotaExceeded. \u0417\u043d\u0430\u043a\u043e\u043c\u043e? \u041c\u043d\u0435 \u0434\u0430! \u042f \u0432\u043e\u043e\u0431\u0449\u0435 \u043a\u043e\u0433\u0434\u0430 \u0432\u043e\u0440\u0432\u0430\u043b\u0441\u044f \u0441 \u043d\u043e\u0433\u0438 \u0432 \u044d\u0442\u043e\u0442 \u043c\u0438\u0440 \u0410\u041f\u0418, \u043d\u0435 \u0434\u0443\u043c\u0430\u043b \u043f\u0440\u043e \u043a\u0432\u043e\u0442\u0443 &#8212; \u043f\u0440\u043e\u0441\u0442\u043e \u0443 \u043c\u0435\u043d\u044f \u0431\u044b\u043b \u043a\u0430\u043a\u043e\u0439 \u0442\u043e \u043f\u043b\u0430\u043d \u0438 \u044f \u0435\u0433\u043e \u043f\u0440\u0438\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u043b\u0441\u044f. \u0418 \u0442\u043e, \u043e \u0447\u0435\u043c \u044f \u0432\u0430\u043c \u0445\u043e\u0447\u0443 \u043f\u043e\u0432\u0435\u0434\u0430\u0442\u044c &#8212; \u0438\u0441\u0442\u043e\u0440\u0438\u044f, \u0432\u044b\u0441\u0442\u0440\u0430\u0434\u0430\u043d\u043d\u0430\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0434\u043d\u044f\u043c\u0438. \u041f\u0430\u0434\u0435\u043d\u0438\u044f \u043d\u0430 \u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0435 \u0441\u0431\u043e\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u043f\u043e\u0442\u0435\u0440\u044f \u0441\u043f\u0430\u0440\u0448\u0435\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445. <strong>\u041a\u043e\u0440\u043e\u0447\u0435 &#8212; \u044d\u0442\u043e\u0442 \u0441\u043a\u0440\u0438\u043f\u0442, (\u043f\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0438 \u0441 \u0423\u0413\u0438\u041a\u0421 &#8212; \u043a\u0442\u043e \u043f\u043e\u0439\u043c\u0435\u0442, \u0442\u043e\u0442 \u043f\u043e\u0439\u043c\u0435\u0442) &#8212; \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u0445\u043e\u0442\u044c \u0438 \u043d\u0435 \u043a\u0440\u043e\u0432\u044c\u044e, \u043d\u043e \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0441\u043e\u043b\u0438 \u0442\u043e \u0442\u0430\u043c \u0435\u0441\u0442\u044c, \u0442\u0430\u043a \u043a\u0430\u043a \u0441\u043b\u0435\u0437\u044b \u0442\u043e\u0436\u0435 \u0441\u043e\u043b\u0435\u043d\u044b\u0435. <\/strong><\/p>\n<p>\u0412 \u043e\u0431\u0449\u0435\u043c &#8212; \u043a\u0430\u0436\u0434\u044b\u0439 \u0445\u043e\u0434 \u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0432 \u044d\u0442\u043e\u043c \u0441\u043a\u0440\u0438\u043f\u0442\u0435 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u043b\u043e\u0441\u044c \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u043b\u043e\u0441\u044c \u043f\u043e \u043c\u0435\u0440\u0435 \u0432\u044b\u043b\u0435\u0437\u0430\u043d\u0438\u044f \u0442\u043e\u0439 \u0438\u043b\u0438 \u0438\u043d\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b &#8212; \u0443\u043f\u0438\u0440\u0430\u043d\u0438\u0435 \u0432 \u043a\u0432\u043e\u0442\u044b, \u043e\u0431\u0440\u044b\u0432 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0439 \u0438 \u0442\u043f. \u0414\u043b\u044f \u043c\u0435\u043d\u044f \u0441\u043a\u0440\u0438\u043f\u0442 \u0441\u0432\u043e\u044e \u0437\u0430\u0434\u0430\u0447\u0443 \u0441\u0434\u0435\u043b\u0430\u043b, \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0438 \u0432\u0430\u043c. <\/p>\n<p>\u0411\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0433\u0430\u0439\u0434\u043e\u0432 \u0432 \u0441\u0435\u0442\u0438 (\u0438\u0437 \u0442\u0435\u0445, \u0447\u0442\u043e \u0432\u0441\u0442\u0440\u0435\u0442\u0438\u043b\u0438\u0441\u044c \u043d\u0430 \u043c\u043e\u0435\u043c \u043f\u0443\u0442\u0438) \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442, \u043a\u0430\u043a \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043e\u0434\u0438\u043d-\u0434\u0432\u0430 \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u041d\u043e \u043c\u044b \u043f\u043e\u0439\u0434\u0435\u043c \u0434\u0430\u043b\u044c\u0448\u0435. \u042f \u043f\u043e\u043a\u0430\u0436\u0443 \u0432\u0430\u043c \u0441\u043a\u0440\u0438\u043f\u0442 \u043d\u0430 Python, \u043a\u043e\u0442\u043e\u0440\u044b\u0439:<\/p>\n<ul>\n<li>\n<p><strong>\u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u043f\u0443\u043b\u043e\u043c API-\u043a\u043b\u044e\u0447\u0435\u0439<\/strong>, \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u044f\u0441\u044c \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439, \u043a\u043e\u0433\u0434\u0430 \u0443 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u0432\u043e\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p><strong>\u0423\u043c\u0435\u0435\u0442 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443<\/strong> \u0441 \u0442\u043e\u0433\u043e \u043c\u0435\u0441\u0442\u0430, \u0433\u0434\u0435 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0441\u044f, \u0434\u0430\u0436\u0435 \u043f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p><strong>\u041a\u044d\u0448\u0438\u0440\u0443\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u044b<\/strong>, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0442\u0440\u0430\u0442\u0438\u0442\u044c \u0434\u0440\u0430\u0433\u043e\u0446\u0435\u043d\u043d\u044b\u0435 \u0435\u0434\u0438\u043d\u0438\u0446\u044b \u043a\u0432\u043e\u0442\u044b \u043d\u0430 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0435 \u0432\u044b\u0437\u043e\u0432\u044b.<\/p>\n<\/li>\n<li>\n<p><strong>\u0423\u0441\u0442\u043e\u0439\u0447\u0438\u0432 \u043a \u043e\u0448\u0438\u0431\u043a\u0430\u043c \u0441\u0435\u0442\u0438<\/strong> \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0443 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 (retry).<\/p>\n<\/li>\n<li>\n<p><strong>\u0418\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043d \u0441 Google Sheets<\/strong>: \u0447\u0438\u0442\u0430\u0435\u0442 \u0438\u0437 \u043e\u0434\u043d\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b, \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0432 \u0434\u0440\u0443\u0433\u0443\u044e.<\/p>\n<\/li>\n<li>\n<p><strong>\u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u0440\u0446\u0438\u044f\u043c\u0438 (\u0431\u0430\u0442\u0447\u0430\u043c\u0438)<\/strong>, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u043e\u0442\u0435\u0440\u044f\u0442\u044c \u0432\u0441\u0451 \u043f\u0440\u0438 \u0441\u0431\u043e\u0435.<\/p>\n<\/li>\n<li>\n<p><strong>\u041e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0438 \u043e\u0431\u043e\u0433\u0430\u0449\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435<\/strong> \u043d\u0430 \u043b\u0435\u0442\u0443: \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u044f\u0437\u044b\u043a, \u0434\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c, \u0432\u043e\u0437\u0440\u0430\u0441\u0442 \u0432\u0438\u0434\u0435\u043e \u0438 \u043c\u043d\u043e\u0433\u043e\u0435 \u0434\u0440\u0443\u0433\u043e\u0435.<\/p>\n<\/li>\n<\/ul>\n<p>\u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u2014 \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0442\u0435\u043e\u0440\u0438\u044f \u0438 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u0430. \u042d\u0442\u043e \u043f\u043e\u0448\u0430\u0433\u043e\u0432\u044b\u0439 \u0440\u0430\u0437\u0431\u043e\u0440 \u0433\u043e\u0442\u043e\u0432\u043e\u0433\u043e, \u0440\u0430\u0431\u043e\u0447\u0435\u0433\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434 \u0441\u0432\u043e\u0438 \u0437\u0430\u0434\u0430\u0447\u0438. \u041f\u043e\u043b\u043d\u044b\u0439 \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u043a\u043e\u0434 \u044f \u0437\u0430\u043b\u044c\u044e \u043d\u0430 \u0441\u0432\u043e\u0439 (\u043d\u0435 \u0411\u043e\u0433 \u0432\u0435\u0441\u044c \u043a\u0430\u043a\u043e\u0439, \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e) <a href=\"https:\/\/github.com\/kentavr009\/Youtube-Parser\" rel=\"noopener noreferrer nofollow\">GitHub<\/a>, \u0438 \u0442\u0430\u043a\u0436\u0435 \u0441\u0434\u0435\u043b\u0430\u044e \u0447\u0443\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u044b\u0439 \u0440\u0430\u0437\u0431\u043e\u0440 <a href=\"https:\/\/autoparse.tech\/kejsy\/parsing-youtube\/\" rel=\"noopener noreferrer nofollow\">\u0432 \u0441\u0432\u043e\u0435\u043c \u0431\u043b\u043e\u0433\u0435<\/a> &#8212; \u043d\u0443 \u044d\u0442\u043e \u0443\u0436\u0435 \u0441\u043a\u043e\u0440\u0435\u0435 \u0434\u043b\u044f \u0442\u0435\u0445, \u043a\u0442\u043e \u0445\u043e\u0447\u0435\u0442 \u043f\u0440\u044f\u043c \u043f\u043e\u0433\u0440\u0443\u0437\u0438\u0442\u044c\u0441\u044f \u0432 \u043d\u0435\u0433\u043e \u0441 \u0433\u043e\u043b\u043e\u0432\u043e\u0439, \u043a\u0430\u043a \u0432 \u0442\u043e\u043c \u0430\u043d\u0435\u043a\u0434\u043e\u0442\u0435 &#8212; \u201c\u043a\u0443\u0440\u0438\u0442\u044c \u043b\u044e\u0431\u043b\u044e, \u043a\u0430\u043f\u0435\u0446\u2026\u201d. \u041f\u043e\u0435\u0445\u0430\u043b\u0438!<\/p>\n<h3>\u0427\u0430\u0441\u0442\u044c 1. \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430<\/h3>\n<h4>\u041f\u0440\u0438\u043a\u0432\u0435\u043b<\/h4>\n<p>\u041f\u0435\u0440\u0435\u0434\u043e \u043c\u043d\u043e\u0439 \u0432\u0441\u0442\u0430\u043b\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 &#8212; \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0432\u0438\u0434\u0435\u043e \u0434\u043b\u044f 40+ \u0442\u044b\u0441\u044f\u0447 \u0441\u0442\u0440\u0430\u043d\u0438\u0446 \u0441\u0430\u0439\u0442\u0430, \u043a\u0430\u0436\u0434\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0438\u043c\u0435\u0435\u0442 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u043a\u043b\u044e\u0447. \u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043f\u043e \u044d\u0442\u043e\u043c\u0443 \u043a\u043b\u044e\u0447\u0443 \u0438 \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u042e\u0442\u0443\u0431\u0430. \u0417\u0430\u0434\u0430\u0447\u0430 &#8212; \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0436\u0435 \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u044b\u0435 \u0432\u0438\u0434\u0435\u043e, \u043d\u043e \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u0441\u0431\u043e\u0440\u0430 \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u043e (\u0442\u0435\u043c \u0431\u043e\u043b\u0435\u0435 \u0447\u0442\u043e \u044d\u0442\u043e \u043d\u0435 \u043a\u043e\u043c\u0431\u0430\u0439\u043d, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0437\u0430\u0434\u0430\u0447\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u043d\u043e \u0441\u043c\u0435\u043b\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0432 \u043a\u043e\u0441\u043c\u043e\u0441) &#8212; \u0443 \u043c\u0435\u043d\u044f \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0430\u0440\u0441\u0435\u0440.<\/p>\n<p>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u044f \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043b \u0434\u0432\u0430 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u043f\u0430\u0440\u0441\u0435\u0440\u043e\u0432 &#8212; \u043e\u0434\u0438\u043d \u0447\u0443\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0437\u0430\u043c\u043e\u0440\u043e\u0447\u0435\u043d\u044b\u0439, \u0433\u0434\u0435 \u043a\u0430\u0436\u0434\u044b\u0439 \u0410\u041f\u0418 \u043a\u043b\u044e\u0447 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d \u043a \u0441\u0432\u043e\u0435\u043c\u0443 \u0441\u0435\u0440\u0432\u0438\u0441\u043d\u043e\u043c\u0443 \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0443, \u0438 \u0432\u0442\u043e\u0440\u043e\u0439 (\u043e\u043d \u043a\u0430\u043a \u0440\u0430\u0437 \u043d\u0438\u0436\u0435) &#8212; \u0433\u0434\u0435 \u0435\u0441\u0442\u044c \u043e\u0434\u0438\u043d \u0441\u0435\u0440\u0432\u0438\u0441\u043d\u044b\u0439 \u0430\u043a\u043a\u0430\u0443\u043d\u0442 \u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043a\u043b\u044e\u0447\u0435\u0439 \u0410\u041f\u0418.<\/p>\n<p>\u0412 \u043e\u0431\u043e\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u0432\u0440\u0435\u043c\u044f \u0436\u0438\u0437\u043d\u0438 \u043a\u043b\u044e\u0447\u0435\u0439 \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u043b\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e 3 \u0434\u043d\u044f, \u043f\u043e\u0442\u043e\u043c \u044e\u0442\u0443\u0431 \u043d\u0430\u0447\u0438\u043d\u0430\u043b \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043a\u0430\u043a\u0430\u044f \u0442\u043e \u043d\u0435\u043f\u043e\u043d\u044f\u0442\u043d\u0430\u044f \u0447\u0435\u043f\u0443\u0445\u0430 \u0438 \u0441\u043d\u0438\u0436\u0430\u043b \u043a\u0432\u043e\u0442\u0443 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0430 \u0434\u043e 1 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (\u0441 10000 \u0432 \u0441\u0443\u0442\u043a\u0438) \u0438\u00a0 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430\u043b \u0441\u0435\u0440\u0432\u0438\u0441\u043d\u044b\u0439 \u0430\u043a\u043a\u0430\u0443\u043d\u0442 &#8212; \u043a\u043e\u0440\u043e\u0447\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u044b\u0440\u0443\u0431\u0430\u043b \u043f\u0430\u0440\u0441\u0435\u0440 \u0441\u0432\u043e\u0438\u043c\u0438 \u0441\u0438\u043b\u0430\u043c\u0438.<\/p>\n<p>\u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0432\u0435\u043d\u043d\u043e &#8212; \u0435\u0441\u043b\u0438 \u043d\u0435\u0442 \u0440\u0430\u0437\u043d\u0438\u0446\u044b, \u0437\u0430\u0447\u0435\u043c <s>\u043f\u043b\u0430\u0442\u0438\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435<\/s> \u0434\u0435\u043b\u0430\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u0440\u0430\u0431\u043e\u0442\u044b?<\/p>\n<figure class=\"\"><\/figure>\n<p>\u0422\u0430\u043a \u0438 \u0440\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u044d\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435<\/p>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043f\u043e\u0433\u0440\u0443\u0436\u0430\u0442\u044c\u0441\u044f \u0432 \u043f\u0430\u0440\u0441\u0435\u0440, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c\u0441\u044f \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u0438 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043c \u0432\u0441\u0451 \u0447\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043b\u044f \u0435\u0433\u043e \u0440\u0430\u0431\u043e\u0442\u044b. \u0422\u0430\u043a \u043a\u0430\u043a \u044d\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0434\u043d\u043e\u0444\u0430\u0439\u043b\u043e\u0432\u044b\u0439 \u0441\u043a\u0440\u0438\u043f\u0442\u0438\u043a, \u0430 \u0441\u0432\u043e\u0435\u0433\u043e \u0440\u043e\u0434\u0430 \u043c\u0438\u043d\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0430.<\/p>\n<h4>1.1. \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0447\u0435\u0440\u0435\u0437 .env<\/h4>\n<p>\u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u044f \u043b\u044e\u0431\u0438\u0442\u0435\u043b\u044c \u0432\u0441\u0435 \u0443\u043f\u0440\u043e\u0449\u0430\u0442\u044c, \u0442\u0430\u043a \u043a\u0430\u043a \u043f\u0430\u0440\u0441\u0435\u0440 \u0438\u0434\u0435\u0442 \u0432 \u043f\u0430\u0431\u043b\u0438\u043a \u044f \u043d\u0435 \u0431\u0443\u0434\u0443 \u0445\u0430\u0440\u0434\u043a\u043e\u0434\u0438\u0442\u044c \u043a\u043b\u044e\u0447\u0438 \u0438 ID \u0442\u0430\u0431\u043b\u0438\u0446 \u0432 \u043a\u043e\u0434\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u0430. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c .env \u0444\u0430\u0439\u043b \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u043d\u0443\u0436\u043d\u044b\u0445 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a. \u042d\u0442\u043e \u0432 \u0446\u0435\u043b\u043e\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e \u0438 \u0443\u0434\u043e\u0431\u043d\u043e.\u00a0<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0432 \u0442\u043e\u0439 \u0436\u0435 \u043f\u0430\u043f\u043a\u0435 \u0433\u0434\u0435 \u043b\u0435\u0436\u0438\u0442 \u043f\u0430\u0440\u0441\u0435\u0440 \u0444\u0430\u0439\u043b .env \u0442\u0430\u043a\u043e\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f:<\/p>\n<pre><code class=\"python\">     # ID \u0432\u0430\u0448\u0435\u0439 Google \u0422\u0430\u0431\u043b\u0438\u0446\u044b SHEET_ID=\"ID \u0422\u0410\u0411\u041b\u0418\u0426\u042b \u0412\u0410\u0428\u0415\u0419 \u0422\u0410\u0411\u041b\u0418\u0426\u042b\" # \u0418\u043c\u044f \u043b\u0438\u0441\u0442\u0430 \u0441 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438 KEYWORDS_SHEET=\"Keywords\" # \u0418\u043c\u044f \u043b\u0438\u0441\u0442\u0430 \u0434\u043b\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 RESULTS_SHEET=\"Results\" # \u041f\u0443\u0442\u044c \u043a JSON-\u0444\u0430\u0439\u043b\u0443 \u0441\u0435\u0440\u0432\u0438\u0441\u043d\u043e\u0433\u043e \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0430 Google SERVICE_ACCOUNT_JSON=\"credentials.json\" # \u0412\u0430\u0448\u0438 API \u043a\u043b\u044e\u0447\u0438 \u043e\u0442 YouTube, \u0447\u0435\u0440\u0435\u0437 \u0437\u0430\u043f\u044f\u0442\u0443\u044e YT_API_KEYS=\"\u0412\u0410\u0428_\u041a\u041b\u042e\u0427_1,\u0412\u0410\u0428_\u041a\u041b\u042e\u0427_2,\u0412\u0410\u0428_\u041a\u041b\u042e\u0427_3\"  # \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0430\u0440\u0441\u0435\u0440\u0430 NUM_RESULTS=10      # \u0421\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u043d\u0430 \u043e\u0434\u0438\u043d \u043a\u043b\u044e\u0447\u0435\u0432\u0438\u043a REGION=\"US\"         # \u0420\u0435\u0433\u0438\u043e\u043d \u043f\u043e\u0438\u0441\u043a\u0430 MAX_PAGES=1         # \u0421\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0442\u0440\u0430\u043d\u0438\u0446 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c BATCH_SIZE=50       # \u0427\u0435\u0440\u0435\u0437 \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043a\u043b\u044e\u0447\u0435\u0432\u0438\u043a\u043e\u0432 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0431\u0430\u0442\u0447 OUTPUT_CSV=\"yt_results.csv\" # \u0418\u043c\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e CSV \u0444\u0430\u0439\u043b\u0430<\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u0432\u044b \u0443\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442\u0435 \u043f\u043e\u0434 \u0441\u0435\u0431\u044f \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e, \u0432\u0430\u0436\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c, \u0447\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u043d\u0430 \u043e\u0434\u0438\u043d \u043a\u043b\u044e\u0447 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c, \u0442\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0441\u0445\u043e\u0434\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u0432\u043e\u0442\u0430.\u00a0\u00a0\u00a0<\/p>\n<h4>1.2. \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043a\u043b\u044e\u0447\u0435\u0439 \u0410\u041f\u0418 \u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u043d\u043e\u0433\u043e \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0430<\/h4>\n<p>\u041d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0434\u0432\u0430 \u0442\u0438\u043f\u0430 \u0443\u0447\u0435\u0442\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445:<\/p>\n<ol>\n<li>\n<p><strong>YouTube Data API Keys (\u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0448\u0442\u0443\u043a!):<\/strong> \u0417\u0430\u0439\u0434\u0438\u0442\u0435 \u0432<a href=\"https:\/\/console.cloud.google.com\/\" rel=\"noopener noreferrer nofollow\"> Google Cloud Console<\/a>, \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u043d\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442, \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u0435 YouTube Data API v3 \u0438 \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 API-\u043a\u043b\u044e\u0447. \u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437\u2026 \u0417\u0430\u0447\u0435\u043c?\u00a0 \u0414\u043d\u0435\u0432\u043d\u0430\u044f \u043a\u0432\u043e\u0442\u0430 \u043d\u0430 \u043e\u0434\u0438\u043d \u043a\u043b\u044e\u0447 \u2014 10 000 &#171;\u0435\u0434\u0438\u043d\u0438\u0446&#187;. \u042d\u0442\u043e\u0433\u043e \u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043c\u0430\u043b\u043e \u0434\u043b\u044f \u0441\u0435\u0440\u044c\u0435\u0437\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447. \u041f\u0443\u043b \u0438\u0437 3-5 \u043a\u043b\u044e\u0447\u0435\u0439 \u0434\u0430\u0441\u0442 \u043d\u0430\u043c 30-50 \u0442\u044b\u0441\u044f\u0447 \u0435\u0434\u0438\u043d\u0438\u0446 \u0432 \u0434\u0435\u043d\u044c, \u0447\u0442\u043e \u0443\u0436\u0435 \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0435\u0435 (\u044f \u0434\u0435\u043b\u0430\u043b 8 \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u043e\u0432 \u043f\u043e 12 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u0432 \u043a\u0430\u0436\u0434\u043e\u043c, \u0447\u0442\u043e \u0434\u0430\u043b\u043e \u043c\u043d\u0435 \u0432 \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0441\u0435 960\u043a \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0432 \u0434\u0435\u043d\u044c).<\/p>\n<\/li>\n<\/ol>\n<figure class=\"full-width\"><\/figure>\n<ol>\n<li>\n<p><strong>Google Sheets API Service Account:<\/strong> \u0427\u0442\u043e\u0431\u044b \u0441\u043a\u0440\u0438\u043f\u0442 \u043c\u043e\u0433 \u0441\u0430\u043c \u0447\u0438\u0442\u0430\u0442\u044c \u0438 \u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u0432\u0430\u0448\u0443 \u0442\u0430\u0431\u043b\u0438\u0446\u0443, \u043d\u0443\u0436\u0435\u043d \u0441\u0435\u0440\u0432\u0438\u0441\u043d\u044b\u0439 \u0430\u043a\u043a\u0430\u0443\u043d\u0442. \u0412 \u0442\u043e\u0439 \u0436\u0435 Cloud Console \u043f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u0432 IAM &amp; Admin -&gt; Service Accounts, \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u043d\u043e\u0432\u044b\u0439, \u0434\u0430\u0439\u0442\u0435 \u0435\u043c\u0443 \u0440\u043e\u043b\u044c &#171;Editor&#187;, \u0438 \u0441\u043a\u0430\u0447\u0430\u0439\u0442\u0435 JSON-\u043a\u043b\u044e\u0447. \u041f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u0443\u0439\u0442\u0435 \u0435\u0433\u043e \u0432 credentials.json \u0438 \u043f\u043e\u043b\u043e\u0436\u0438\u0442\u0435 \u0440\u044f\u0434\u043e\u043c \u0441\u043e \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u043c. <strong>\u0412\u0430\u0436\u043d\u043e:<\/strong> \u043d\u0435 \u0437\u0430\u0431\u0443\u0434\u044c\u0442\u0435 &#171;\u0440\u0430\u0441\u0448\u0430\u0440\u0438\u0442\u044c&#187; \u0432\u0430\u0448\u0443 Google \u0422\u0430\u0431\u043b\u0438\u0446\u0443 \u0434\u043b\u044f email&#8217;\u0430 \u044d\u0442\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u043d\u043e\u0433\u043e \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0430 (\u043e\u043d \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043a\u0430\u043a &#8230;<a href=\"http:\/\/gserviceaccount.com\" rel=\"noopener noreferrer nofollow\">gserviceaccount.com<\/a>).<\/p>\n<\/li>\n<\/ol>\n<figure class=\"full-width\"><\/figure>\n<p>\u041e\u0434\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u043d\u043e\u0433\u043e \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0430 \u043f\u043e \u043c\u043e\u0435\u043c\u0443 \u043e\u043f\u044b\u0442\u0443 \u0436\u0435\u0441\u0442\u043a\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043f\u0430\u0440\u0441\u0435\u0440\u0430 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u043d\u0430 3 \u0434\u043d\u044f, \u043d\u043e \u044f \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u043d\u0430 \u0432\u0441\u044f\u043a\u0438\u0439 \u0441\u043b\u0443\u0447\u0430\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 40-50 \u043a\u043b\u044e\u0447\u0435\u0439 \u043d\u0430 \u043e\u0434\u0438\u043d \u0441\u0435\u0440\u0432\u0438\u0441\u043d\u044b\u0439 \u0430\u043a\u043a\u0430\u0443\u043d\u0442, \u0447\u0438\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0441\u0442\u0440\u0430\u0445\u043e\u0432\u043a\u0430, \u043c\u0430\u043b\u043e \u043b\u0438 \u0413\u0443\u0433\u043b \u043d\u0430\u0447\u043d\u0435\u0442 \u0447\u0442\u043e \u0442\u043e \u043f\u043e\u0434\u043e\u0437\u0440\u0435\u0432\u0430\u0442\u044c \u0440\u0430\u043d\u044c\u0448\u0435.<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u044d\u0442\u043e \u0438 \u0435\u0441\u0442\u044c \u0441\u0430\u043c\u0430\u044f \u0441\u043b\u043e\u0436\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 &#8212; \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0410\u041f\u0418 \u043a\u043b\u044e\u0447\u0435\u0439. \u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0437\u0430\u0433\u043b\u044f\u043d\u0435\u043c \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442 \u043f\u0430\u0440\u0441\u0435\u0440\u0430.<\/p>\n<h3>\u0427\u0430\u0441\u0442\u044c 2. KeyManager \u0434\u043b\u044f \u0440\u043e\u0442\u0430\u0446\u0438\u0438 API-\u043a\u043b\u044e\u0447\u0435\u0439<\/h3>\n<p>\u0412\u043e\u0442 \u043a\u0430\u043a \u043f\u0430\u0440\u0441\u0435\u0440 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u0443\u043b\u043e\u043c \u043a\u043b\u044e\u0447\u0435\u0439 \u0438 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043f\u0440\u0435\u0432\u044b\u0448\u0435\u043d\u0438\u0435 \u043a\u0432\u043e\u0442\u044b &#8212; \u0447\u0435\u0440\u0435\u0437 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441-\u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440.<\/p>\n<pre><code class=\"python\">     class APIKey:     \"\"\"\u041e\u0431\u0435\u0440\u0442\u043a\u0430 \u0434\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e API \u043a\u043b\u044e\u0447\u0430\"\"\"     def __init__(self, key: str):         self.key = key         self.service = build(\"youtube\", \"v3\", developerKey=key, cache_discovery=False)         self.used_units = 0         self.active = True  class KeyManager:     \"\"\"\u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u0443\u043b\u043e\u043c \u043a\u043b\u044e\u0447\u0435\u0439, \u0440\u043e\u0442\u0438\u0440\u0443\u0435\u0442 \u0438\u0445 \u0438 \u043e\u0442\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u043f\u0440\u0438 \u0438\u0441\u0447\u0435\u0440\u043f\u0430\u043d\u0438\u0438 \u043a\u0432\u043e\u0442\u044b\"\"\"     def __init__(self, keys: list[str]):         self.keys = [APIKey(k) for k in keys]         self.index = 0      def get_key(self) -&gt; APIKey:         # \u0418\u0449\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u043f\u043e \u043a\u0440\u0443\u0433\u0443         for _ in range(len(self.keys)):             api = self.keys[self.index]             self.index = (self.index + 1) % len(self.keys) # \u0426\u0438\u043a\u043b\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0441\u0434\u0432\u0438\u0433             if api.active:                 return api         # \u0415\u0441\u043b\u0438 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u043a\u043b\u044e\u0447\u0435\u0439 \u043d\u0435 \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c         raise QuotaExceededAllKeys()      def deactivate(self, api: APIKey):         api.active = False         logger.warning(f\"\u0414\u0435\u0430\u043a\u0442\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u043d \u043a\u043b\u044e\u0447: {api.key}\")      def execute(self, fn, units=0, backoff_max=3):         # \u042d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 - \"\u043e\u0431\u0435\u0440\u0442\u043a\u0430\" \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0432\u044b\u0437\u043e\u0432\u043e\u0432 API         attempt = 0         while True:             api = self.get_key() # \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u043a\u043b\u044e\u0447             try:                 resp = fn(api.service).execute()                 # ... \u043b\u043e\u0433\u0438\u043a\u0430 \u043f\u043e\u0434\u0441\u0447\u0435\u0442\u0430 \u0440\u0430\u0441\u0445\u043e\u0434\u0430 ...                 return resp             except HttpError as e:                 err_str = str(e)                 if 'quotaExceeded' in err_str:                     self.deactivate(api) # \u041a\u043b\u044e\u0447 \"\u0441\u0433\u043e\u0440\u0435\u043b\", \u0434\u0435\u0430\u043a\u0442\u0438\u0432\u0438\u0440\u0443\u0435\u043c \u0438 \u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439                     continue                 if 'rateLimitExceeded' in err_str and attempt &lt; backoff_max:                     # \u0421\u043b\u0438\u0448\u043a\u043e\u043c \u0447\u0430\u0441\u0442\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u0436\u0434\u0435\u043c \u0438 \u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0441\u043d\u043e\u0432\u0430 (Exponential Backoff)                     delay = 2 ** attempt                     logger.warning(f\"Rate limit, \u0436\u0434\u0443 {delay}s...\")                     time.sleep(delay)                     attempt += 1                     continue                 # \u0414\u0440\u0443\u0433\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430, \u043f\u0440\u043e\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u043c \u043d\u0430\u0432\u0435\u0440\u0445                 raise     IGNORE_WHEN_COPYING_START content_copy download Use code with caution. Python IGNORE_WHEN_COPYING_END <\/code><\/pre>\n<p><strong>\u0427\u0442\u043e \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442?<\/strong><\/p>\n<ul>\n<li>\n<p>APIKey \u2014 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043a\u043b\u0430\u0441\u0441-\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0434\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0430, \u0435\u0433\u043e \u0441\u0442\u0430\u0442\u0443\u0441\u0430 \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0434\u043b\u044f \u043d\u0435\u0433\u043e service \u043e\u0431\u044a\u0435\u043a\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>KeyManager \u2014 \u043c\u043e\u0437\u0433 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438. \u041c\u0435\u0442\u043e\u0434 <code>get_key() <\/code>\u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0442\u0434\u0430\u0435\u0442 \u043a\u043b\u044e\u0447, \u0430 \u0438\u0449\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 <em>\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0439<\/em> \u043a\u043b\u044e\u0447 \u0432 \u0441\u043f\u0438\u0441\u043a\u0435. \u0415\u0441\u043b\u0438 \u043a\u043b\u044e\u0447 \u0438\u0441\u0447\u0435\u0440\u043f\u0430\u043b \u043a\u0432\u043e\u0442\u0443, \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043c\u0435\u0447\u0435\u043d \u043a\u0430\u043a <code>active = False<\/code> \u0438 \u043f\u0440\u043e\u043f\u0443\u0449\u0435\u043d.<\/p>\n<\/li>\n<li>\n<p><strong>execute() &#8212; <\/strong>\u00a0\u0412\u043c\u0435\u0441\u0442\u043e \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u0432 \u043a\u043e\u0434\u0435 \u043f\u0438\u0441\u0430\u0442\u044c <a href=\"http:\/\/youtube.search\" rel=\"noopener noreferrer nofollow\"><code>youtube.search<\/code><\/a><code>().list(...).execute()<\/code>, \u043f\u0438\u0448\u0435\u043c <code>key_manager.execute(lambda svc: <\/code><a href=\"http:\/\/svc.search\" rel=\"noopener noreferrer nofollow\"><code>svc.search<\/code><\/a><code>().list(...)<\/code>). \u042d\u0442\u0430 \u043e\u0431\u0435\u0440\u0442\u043a\u0430 \u0441\u0430\u043c\u0430:<\/p>\n<ol>\n<li>\n<p>\u0412\u043e\u0437\u044c\u043c\u0435\u0442 \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u043a\u043b\u044e\u0447 \u0438\u0437 \u043f\u0443\u043b\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u0438\u0442 \u0437\u0430\u043f\u0440\u043e\u0441.<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u043f\u043e\u0439\u043c\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0443 <code>quotaExceeded<\/code>, \u0434\u0435\u0430\u043a\u0442\u0438\u0432\u0438\u0440\u0443\u0435\u0442 \u043a\u043b\u044e\u0447 \u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043a\u043b\u044e\u0447\u043e\u043c.<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u043f\u043e\u0439\u043c\u0430\u0435\u0442 <code>rateLimitExceeded <\/code>(\u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0443), \u043f\u043e\u0434\u043e\u0436\u0434\u0435\u0442 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0438 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u0442 \u0441\u043d\u043e\u0432\u0430.<\/p>\n<\/li>\n<\/ol>\n<\/li>\n<li>\n<p>\u042d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043a\u043e\u0434 \u0447\u0443\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0441\u0442\u044b\u043c \u0438 \u0438\u0437\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u043d\u0430\u0441 \u043e\u0442 \u0434\u0435\u0441\u044f\u0442\u043a\u043e\u0432 <code>try-except<\/code> \u0431\u043b\u043e\u043a\u043e\u0432.<\/p>\n<h3>\u0427\u0430\u0441\u0442\u044c 3. \u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438 \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/h3>\n<p>\u0421\u043a\u0440\u0438\u043f\u0442, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0442\u044b\u0441\u044f\u0447\u0438 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0445 \u0441\u043b\u043e\u0432, \u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0447\u0430\u0441\u0430\u043c\u0438. \u041d\u043e \u0435\u0441\u043b\u0438 \u043e\u0431\u043e\u0440\u0432\u0435\u0442\u0441\u044f \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u0438\u043b\u0438 \u0432\u044b\u043a\u043b\u044e\u0447\u0438\u0442\u0441\u044f \u0441\u0432\u0435\u0442? \u0423 \u043c\u0435\u043d\u044f \u0442\u0430\u043a\u043e\u0435 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e, \u0447\u0435\u0440\u0435\u0437 2 \u0447\u0430\u0441\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u0438 \u043c\u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u043d\u0430\u0447\u0430\u0442\u044c \u0437\u0430\u043d\u043e\u0432\u043e, \u043d\u043e \u044d\u0442\u043e \u043f\u043e\u043c\u043e\u0433\u043b\u043e \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442 \u043d\u043e\u0432\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u043e\u0439\u2026 \u041f\u0435\u0440\u0441\u0438\u0441\u0442\u0435\u043d\u0442\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <code>shelve<\/code>.<\/p>\n<p>shelve \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043a\u0430\u043a \u0441\u043b\u043e\u0432\u0430\u0440\u044c (<code>dict<\/code>), \u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442 \u0441\u0432\u043e\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u0444\u0430\u0439\u043b\u0435 \u043d\u0430 \u0434\u0438\u0441\u043a\u0435.<\/p>\n<p><strong>\u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441\u0430 (progress.db):<br \/><\/strong>\u041c\u044b \u0441\u043e\u0437\u0434\u0430\u0435\u043c shelve-\u0444\u0430\u0439\u043b \u0434\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441\u0430. \u041f\u0435\u0440\u0435\u0434 \u043d\u0430\u0447\u0430\u043b\u043e\u043c \u0446\u0438\u043a\u043b\u0430 \u043c\u044b \u0447\u0438\u0442\u0430\u0435\u043c \u0438\u0437 \u043d\u0435\u0433\u043e <code>last_index<\/code>, \u0430 \u043f\u043e\u0441\u043b\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0433\u043e \u0441\u043b\u043e\u0432\u0430 \u2014 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u043d\u043e\u0432\u044b\u0439 \u0438\u043d\u0434\u0435\u043a\u0441.<\/p>\n<pre><code class=\"python\">      # \u0412<\/code><\/pre>\n<\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-462222","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/462222","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=462222"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/462222\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=462222"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=462222"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=462222"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}