{"id":323040,"date":"2021-05-13T09:01:48","date_gmt":"2021-05-13T09:01:48","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=323040"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=323040","title":{"rendered":"\u0417\u0430\u043f\u0443\u0441\u043a \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u0433\u043e \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0431\u0435\u0437 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e IP \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Python"},"content":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\">\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/wk\/mt\/wc\/wkmtwc-p-oaltwox6zahqwicnmw.jpeg\"><\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u0425\u0430\u0431\u0440\u0430! <\/p>\n<p>  <\/p>\n<p>\u0417\u0430\u0434\u0430\u043b\u0441\u044f \u0442\u0443\u0442 \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u043c, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c \u0431\u0435\u0437 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e IP \u0434\u043b\u044f \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u043e\u0432 \u0432 \u0434\u043e\u043c\u0430\u0448\u043d\u0438\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445. \u041d\u0430\u0442\u043a\u043d\u0443\u043b\u0441\u044f \u043d\u0430 \u0432\u043e\u0442 \u044d\u0442\u0443 \u0441\u0442\u0430\u0442\u044c\u044e. <\/p>\n<p>  <\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0441\u0432\u043e\u0439 \u0432\u0435\u0431\u0441\u0435\u0440\u0432\u0435\u0440 \u0441 \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c \u0438\u0437\u0432\u043d\u0435, \u0430 \u043f\u043b\u0430\u0442\u0438\u0442\u044c \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u0443 \u0437\u0430 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 IP \u043d\u0435 \u0445\u043e\u0442\u0438\u0442\u0435, \u0442\u043e \u0434\u0430\u043d\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0432\u043f\u043e\u043b\u043d\u0435 \u0441\u0435\u0431\u0435 \u0432\u044b\u0445\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u043e\u0436\u043d\u043e \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u043f\u043e\u0434\u043e\u0433\u043d\u0430\u0442\u044c \u043f\u043e\u0434 \u0441\u0432\u043e\u0438 \u043d\u0443\u0436\u0434\u044b.<\/p>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<hr>\n<p>  <\/p>\n<p>\u041d\u0435\u0434\u0430\u0432\u043d\u043e \u044f \u0440\u0435\u0448\u0438\u043b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0430 Rasberry Pi, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u0437\u0430 \u043c\u043e\u0438\u043c \u0434\u043e\u043c\u0430\u0448\u043d\u0438\u043c \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0442\u043e\u0440\u043e\u043c. \u0423 \u043c\u0435\u043d\u044f \u0435\u0441\u0442\u044c \u043e\u043f\u044b\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u043d\u0430 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0445 \u043c\u0430\u0448\u0438\u043d\u0430\u0445 Linux \u0441\u043e \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u043c\u0438 IP-\u0430\u0434\u0440\u0435\u0441\u0430\u043c\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 apache2 \u043d\u0430 Pi \u043d\u0435\u0442 \u043d\u0438\u0447\u0435\u0433\u043e \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0433\u043e, \u0438 \u0432 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435 \u0435\u0441\u0442\u044c \u0441\u043e\u0442\u043d\u0438 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432. \u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e IP \u0432\u0430\u0448\u0435\u0433\u043e \u0440\u043e\u0443\u0442\u0435\u0440\u0430 \u0441\u0430\u0439\u0442 \u0441\u043b\u043e\u043c\u0430\u0435\u0442\u0441\u044f! \u041e\u0434\u0438\u043d \u0438\u0437 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u0440\u0435\u0448\u0438\u0442\u044c \u044d\u0442\u0443 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u2014 \u0437\u0430\u043f\u043b\u0430\u0442\u0438\u0442\u044c \u0441\u0432\u043e\u0435\u043c\u0443 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u0443 \u0437\u0430 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 IP-\u0430\u0434\u0440\u0435\u0441\u2026 \u043d\u043e \u0442\u043e\u0433\u0434\u0430 \u0432 \u0447\u0451\u043c \u0432\u0435\u0441\u0435\u043b\u044c\u0435?!<\/p>\n<p>  <\/p>\n<p>\u0412\u043e \u043c\u043d\u043e\u0433\u0438\u0445 \u0441\u0432\u043e\u0438\u0445 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b Google Domains \u0434\u043b\u044f \u043f\u043e\u043a\u0443\u043f\u043a\u0438 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u0438\u043c\u0435\u043d\u0438 \u0438 \u043e\u0431\u044b\u0447\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b \u0441\u0430\u0439\u0442\u044b \u0431\u0435\u0437 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0433\u0443\u0433\u043b\u043e\u0432\u0441\u043a\u0438\u0445 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0438\u043c\u0435\u043d \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c VPS\/\u00ab\u043e\u0431\u043b\u0430\u0447\u043d\u043e\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0435\u00bb. \u041d\u043e \u0434\u043b\u044f \u043c\u043e\u0435\u0433\u043e \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u044f \u0440\u0435\u0448\u0438\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0443\u044e \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043f\u0435\u0440\u0435\u0430\u0434\u0440\u0435\u0441\u0430\u0446\u0438\u0438 IP-\u0430\u0434\u0440\u0435\u0441\u043e\u0432 \u043f\u043e\u0434\u0434\u043e\u043c\u0435\u043d\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0434\u043e\u043c\u0435\u043d (@.example.com) \u043d\u0430 IP-\u0430\u0434\u0440\u0435\u0441 \u043c\u043e\u0435\u0433\u043e \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0442\u043e\u0440\u0430 (\u0430 \u0437\u0430\u0442\u0435\u043c \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043c\u043e\u0439 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0442\u043e\u0440 \u043d\u0430 \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441 http \u043f\u043e\u0440\u0442\u043e\u0432 \u043d\u0430 https \u043f\u043e\u0440\u0442\u044b \u043d\u0430 Pi). \u0422\u043e\u0433\u0434\u0430 \u043c\u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0431\u044b \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c, \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043b\u0438 \u0441\u0430\u0439\u0442, \u0438 \u043c\u0435\u043d\u044f\u0442\u044c IP \u043f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438. \u041e\u0447\u0435\u0432\u0438\u0434\u043d\u043e, \u044d\u0442\u043e \u043d\u0435 \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u043b\u0430\u043d, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442 \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430.<\/p>\n<p>  <\/p>\n<blockquote><p>\u041d\u0430 \u0437\u0430\u043c\u0435\u0442\u043a\u0443, \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 \u043f\u043e\u043b\u043d\u044b\u0439 \u0441\u043a\u0440\u0438\u043f\u0442 <a href=\"https:\/\/github.com\/nihilok\/domains-api\" rel=\"nofollow noopener noreferrer\">\u043d\u0430 \u0433\u0438\u0442\u0445\u0430\u0431\u0435<\/a> \u0438\u043b\u0438 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c <a href=\"http:\/\/pypi.org\/project\/domains-api\" rel=\"nofollow noopener noreferrer\">\u043f\u0430\u043a\u0435\u0442 Python<\/a> \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>pip install domains-api<\/code><\/p><\/blockquote>\n<p>\u0415\u0441\u0442\u044c \u043c\u043d\u043e\u0433\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0432\u0430\u0448 \u0432\u043d\u0435\u0448\u043d\u0438\u0439 IP-\u0430\u0434\u0440\u0435\u0441, \u0438 \u043e\u0434\u0438\u043d \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u043f\u0440\u043e\u0441\u0442\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044f \u043d\u0430\u0448\u0435\u043b, \u0431\u044b\u043b \u0447\u0435\u0440\u0435\u0437 <a href=\"http:\/\/ipify.org\/\" rel=\"nofollow noopener noreferrer\">ipify<\/a> API (api.ipify.org), \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0432\u0430\u0448 \u043e\u0431\u0449\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0439 IP-\u0430\u0434\u0440\u0435\u0441. \u041f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 Python \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 requests \u0437\u0430\u043f\u0440\u043e\u0441 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<p>  <\/p>\n<pre><code class=\"python\">IP = requests.get('https:\/\/api.ipify.org').text<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412\u043e\u0442 \u0438 \u0432\u0441\u0435, \u044d\u0442\u043e \u0432\u0430\u0448 \u0432\u043d\u0435\u0448\u043d\u0438\u0439 IP. \u041b\u0435\u0433\u043a\u043e, \u043f\u0440\u0430\u0432\u0434\u0430? \u0415\u0441\u0442\u044c \u043c\u043d\u043e\u0433\u043e \u0434\u0440\u0443\u0433\u0438\u0445 \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0445 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0432\u043d\u0435\u0448\u043d\u0438\u0439 IP-\u0430\u0434\u0440\u0435\u0441, \u043d\u043e \u044f \u0441\u0447\u0438\u0442\u0430\u044e, \u0447\u0442\u043e \u044d\u0442\u043e \u0441\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439.<\/p>\n<p>  <\/p>\n<p>\u0418\u0442\u0430\u043a, \u0447\u0442\u043e \u0435\u0449\u0435 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u0441\u043a\u0440\u0438\u043f\u0442\u0430? \u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0433\u0434\u0435-\u0442\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c IP-\u0430\u0434\u0440\u0435\u0441, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0431\u0443\u0434\u0443\u0449\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b. \u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u044f \u0440\u0435\u0448\u0438\u043b \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0435\u0433\u043e \u0432 \u043f\u0440\u043e\u0441\u0442\u043e\u043c \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u043c \u0444\u0430\u0439\u043b\u0435. \u041d\u0430\u043c \u0442\u0430\u043a\u0436\u0435 \u043d\u0443\u0436\u0435\u043d \u0441\u043f\u043e\u0441\u043e\u0431 \u043b\u0438\u0431\u043e \u0443\u0432\u0435\u0434\u043e\u043c\u0438\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u043b\u0438\u0431\u043e \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c domain.google.com, \u043b\u0438\u0431\u043e \u0438 \u0442\u043e, \u0438 \u0434\u0440\u0443\u0433\u043e\u0435. \u041f\u0435\u0440\u0432\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u044b \u0434\u043b\u044f Python, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043b \u0435\u0451 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043c\u043e\u0435\u0439 \u0443\u0447\u0435\u0442\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u044c\u044e Gmail \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c (\u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u043c\u0435\u043d\u0435\u0435 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f (<a href=\"https:\/\/support.google.com\/accounts\/answer\/6010255?hl=en\" rel=\"nofollow noopener noreferrer\">less secure apps<\/a>) \u0432 \u0441\u0432\u043e\u0435\u0439 \u0443\u0447\u0435\u0442\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 Google):<\/p>\n<p>  <\/p>\n<pre><code class=\"python\">from email.message import EmailMessage  def send_notification(new_ip):      msg = EmailMessage()     msg.set_content(f'IP has changed!\\nNew IP: {new_ip}')     msg['Subject'] = 'IP CHANGED!'     msg['From'] = GMAIL_USER     msg['To'] = GMAIL_USER      try:         server = smtplib.SMTP_SSL('smtp.gmail.com', 465)         server.ehlo()         server.login(GMAIL_USER, GMAIL_PASSWORD)         server.send_message(msg)         server.close()         log_msg = 'Email notification sent to %s' % GMAIL_USER)         logging.info(log_msg)      except (MessageError, ConnectionError) as e:         log_msg = 'Something went wrong: %s' % e         logging.warning(log_msg)<\/code><\/pre>\n<p>  <\/p>\n<p>\u041e\u0434\u043d\u0430 \u0432\u0435\u0449\u044c, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0431\u0435\u0441\u043f\u043e\u043a\u043e\u0438\u0442 \u0437\u0434\u0435\u0441\u044c, \u2014 \u044d\u0442\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0430\u0440\u043e\u043b\u044f \u043e\u0442 \u0443\u0447\u0435\u0442\u043a\u0438 Gmail \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b \u043d\u0430 \u044d\u0442\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u0445\u043e\u0442\u044f \u0431\u044b \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0437\u0430\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e, \u0434\u043e\u0431\u0430\u0432\u0438\u0432 \u043e\u0434\u0438\u043d \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u043f\u0430\u0440\u043e\u043b\u044e \u043f\u0435\u0440\u0435\u0434 \u0435\u0433\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435\u043c. \u041e\u043f\u044f\u0442\u044c \u0436\u0435, \u0435\u0441\u0442\u044c \u043c\u043d\u043e\u0433\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0438\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0438\u043b\u0438 \u043c\u0435\u043d\u0435\u0435 \u0441\u043d\u043e\u0441\u043d\u0443\u044e \u0437\u0430\u0449\u0438\u0442\u0443, \u043d\u043e \u044f \u0440\u0435\u0448\u0438\u043b, \u0447\u0442\u043e \u0434\u043b\u044f \u043c\u043e\u0438\u0445 \u0446\u0435\u043b\u0435\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e\u0439 \u043c\u0435\u0440\u0435 \u043d\u0430\u0434\u0435\u0436\u043d\u043e, \u0435\u0441\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d \u0432 base64 \u043f\u0440\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0438 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0439: \u043e\u0434\u043d\u0430 \u0434\u043b\u044f \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f\/\u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043f\u0430\u0440\u043e\u043b\u044f \u0438 \u043e\u0434\u043d\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f\/\u0434\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u0430\u0440\u043e\u043b\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"python\">def enc_pwd():     pwd = base64.b64encode(getpass(&quot;What's your email password?: &quot;).encode(&quot;utf-8&quot;))     with open('cred.txt', 'wb') as f:         f.write(pwd)  def read_pwd():     if os.path.isfile(f&quot;{CWD}\/cred.txt&quot;):         with open(f'{CWD}\/cred.txt', 'r') as f:              if f.read():                 password = base64.b64decode(pwd).decode('utf-8')                 logging.info('Password read successfully')                 return password             else:                     enc_pwd()                 read_pwd()     else:         enc_pwd()         read_pwd()<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u044f \u043c\u043e\u0433 \u0431\u044b \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u0443 GMAIL_PASSWORD \u0438\u0437 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043d\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044e read_pwd() (\u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0434\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043f\u0430\u0440\u043e\u043b\u044c), \u0447\u0442\u043e \u0432\u0441\u044f\u043a\u043e \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u0435\u0435.<\/p>\n<p>  <\/p>\n<p>\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435, \u0447\u0442\u043e \u043c\u043d\u0435 \u043d\u0443\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u0441\u0442\u0430\u043b\u0430 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0439, \u2014 \u044d\u0442\u043e \u0434\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u0432\u044f\u0436\u0435\u0442 \u0432\u0441\u0451 \u0432\u043c\u0435\u0441\u0442\u0435 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\/\u0441\u0440\u0430\u0432\u043d\u0438\u0442 IP-\u0430\u0434\u0440\u0435\u0441\u0430:<\/p>\n<p>  <\/p>\n<pre><code class=\"python\">def check_ip():      if os.path.isfile('ip.txt'):         # \u0421\u043d\u043e\u0432\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0439 IP         with open('ip.txt', 'r') as rf:             line = rf.readlines()             if not line:                 first_run = True             elif line[0] == IP:                 first_run = False                 change = False             else:                 first_run = False                 change = True     else:         first_run = True if first_run or change:         # \u0417\u0430\u043f\u0438\u0448\u0435\u043c \u043d\u043e\u0432\u044b\u0439 IP \u0432 \u0444\u0430\u0439\u043b         with open('ip.txt', 'w') as wf:             if first_run:                 wf.write(IP)             elif change:                 wf.write(IP)                 # \u0423\u0432\u0435\u0434\u043e\u043c\u0438\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f:                 send_notification(IP)      time.sleep(21600)       # \u0432 \u043e\u043a\u043e\u043d\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043d\u0430 \u043c\u043e\u0435\u043c \u0431\u043e\u0435\u0432\u043e\u043c \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u044f \u0443\u0434\u0430\u043b\u0438\u043b \u044d\u0442\u043e 6-\u0447\u0430\u0441\u043e\u0432\u043e\u0435 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0435 \u0438 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u044b\u0439 \u0432\u044b\u0437\u043e\u0432 \u0432 \u043a\u043e\u043d\u0446\u0435 \u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u0441\u043a\u0440\u0438\u043f\u0442 \u0432 crontab \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u0432 \u0447\u0430\u0441. \u041c\u043d\u0435 \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432\u0441\u0435 \u043f\u0443\u0442\u0438 \u043a \u0444\u0430\u0439\u043b\u0430\u043c \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u044b\u043c\u0438, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0434\u043b\u044f crontab \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u043a\u0430\u0442\u0430\u043b\u043e\u0433 - '\/'.     check_ip()<\/code><\/pre>\n<p>  <\/p>\n<p>\u0411\u0443\u043c! \u042d\u0442\u043e \u0431\u044b\u043b\u0430 \u043f\u0435\u0440\u0432\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043c\u043e\u0435\u0439 \u0438\u0434\u0435\u0438. \u041a\u043e\u0433\u0434\u0430 \u044f \u043f\u043e\u043b\u0443\u0447\u0430\u044e \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u043f\u043e \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u0435, \u044f \u043c\u043e\u0433\u0443 \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u043f\u0435\u0440\u0435\u0430\u0434\u0440\u0435\u0441\u0430\u0446\u0438\u0438 \u043d\u0430 \u0441\u0430\u0439\u0442\u0435 domains.google.com\u2026<\/p>\n<p>  <\/p>\n<p><em>\u0421\u0442\u043e\u043f, \u0447\u0442\u043e? \u041c\u043d\u0435 \u0432\u0441\u0435 \u0435\u0449\u0435 \u043d\u0443\u0436\u043d\u043e \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0430\u043c\u043e\u043c\u0443? \u041a\u043e\u043d\u0435\u0447\u043d\u043e \u043d\u0435\u0442, \u0435\u0441\u0442\u044c \u0441\u043f\u043e\u0441\u043e\u0431 \u043f\u0440\u043e\u0449\u0435!<\/em><\/p>\n<p>  <\/p>\n<p>\u0427\u0442\u043e \u0436, \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u0435\u0441\u0442\u044c \u0434\u0432\u0430 \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e \u2014 \u043e\u0434\u0438\u043d \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043c\u0435\u043d\u0435\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u044b\u0439, \u043d\u043e \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0431\u043e\u043b\u0435\u0435 \u0437\u0430\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u044e\u0449\u0438\u0439, \u0430 \u0434\u0440\u0443\u0433\u043e\u0439 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0441\u043a\u0443\u0447\u043d\u044b\u0439, \u043d\u043e \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0431\u043e\u043b\u0435\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u044b\u0439! \u042f \u043d\u0430\u0447\u043d\u0443, \u043a\u0430\u043a \u0438 \u0441\u0434\u0435\u043b\u0430\u043b, \u0441 \u0437\u0430\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u044e\u0449\u0435\u0433\u043e \u0438 \u0441\u043b\u043e\u0436\u043d\u043e\u0433\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0430: \u0441\u043b\u044b\u0448\u0430\u043b\u0438 \u043a\u043e\u0433\u0434\u0430-\u043d\u0438\u0431\u0443\u0434\u044c \u043e Selenium \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u0435\u0431-\u0441\u0430\u0439\u0442\u043e\u0432? \u042f \u0440\u0435\u0448\u0438\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0445\u043e\u0434\u0438\u0442\u044c \u0432 \u0434\u043e\u043c\u0435\u043d\u044b Google \u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0442\u044c\u0441\u044f \u043f\u043e \u0441\u0430\u0439\u0442\u0443, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0434\u043b\u044f \u043c\u0435\u043d\u044f, \u0435\u0441\u043b\u0438 \u0438 \u043a\u043e\u0433\u0434\u0430 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u0441\u044f IP. \u041e\u0434\u043d\u0430\u043a\u043e \u044d\u0442\u043e \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u043b\u043e \u043a \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u043c:<\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e, Google Domains (\u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u044b Google, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a Gmail) \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0445\u043e\u0440\u043e\u0448\u043e \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0432\u0430\u044e\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044e \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0432\u0430\u043c \u0432\u043e\u0439\u0442\u0438 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0447\u0435\u0440\u0435\u0437 \u0432\u0435\u0431-\u0434\u0440\u0430\u0439\u0432\u0435\u0440 Selenium. \u041c\u043d\u0435 \u043f\u043e\u0441\u0447\u0430\u0441\u0442\u043b\u0438\u0432\u0438\u043b\u043e\u0441\u044c \u043d\u0430\u0439\u0442\u0438 <a href=\"https:\/\/stackoverflow.com\/questions\/59514049\/unable-to-sign-into-google-with-selenium-automation-because-of-this-browser-or\" rel=\"nofollow noopener noreferrer\">\u044d\u0442\u043e\u0442 \u043e\u0442\u0432\u0435\u0442<\/a> (\u0435\u0441\u0442\u044c \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f) \u0432 Stack Overflow, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u043b \u0432\u043e\u0439\u0442\u0438 \u0432 \u0441\u0430\u043c Stack Overflow \u0441 \u0432\u0430\u0448\u0435\u0439 \u0443\u0447\u0435\u0442\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u044c\u044e Google, \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0436\u0435\u043b\u0430\u0435\u043c\u0443\u044e \u0441\u043b\u0443\u0436\u0431\u0443 Google, \u0447\u0442\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e, \u043f\u043e\u043a\u0430 \u044f \u043d\u0435 \u0431\u0440\u0430\u043b \u043f\u043e\u0434 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0438 \u043f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043d\u0435 \u0432\u0432\u043e\u0434\u0438\u043b \u043a\u0430\u043f\u0447\u0443. \u0421\u043e \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u043c, \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u044b\u043c \u043d\u0430 \u043c\u043e\u0435\u043c \u043d\u043e\u0443\u0442\u0431\u0443\u043a\u0435 \u0438\u043b\u0438 \u0434\u0435\u0441\u043a\u0442\u043e\u043f\u0435, \u044d\u0442\u043e \u0437\u0430\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u2014 \u0442\u0435\u043c \u0431\u043e\u043b\u0435\u0435, \u0447\u0442\u043e \u043f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 Captcha StackOverflow, \u043f\u043e\u0445\u043e\u0436\u0435, \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u043b \u0442\u043e\u0442 \u0436\u0435 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0432\u0435\u0431-\u0434\u0440\u0430\u0439\u0432\u0435\u0440 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0432 \u0430\u0432\u0442\u043e\u043d\u043e\u043c\u043d\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435, \u043d\u043e \u044d\u0442\u043e \u043d\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0430! \u0425\u043e\u0442\u044f \u044f \u043c\u043e\u0433 \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u0435\u0431-\u0434\u0440\u0430\u0439\u0432\u0435\u0440 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e PyVirtualDisplay \u0438 Geckodriver (\u0432\u0435\u0431-\u0434\u0440\u0430\u0439\u0432\u0435\u0440 \u0434\u043b\u044f Firefox), \u0435\u043c\u0443 \u0443\u0434\u0430\u0432\u0430\u043b\u043e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u043f\u043e\u043f\u0430\u0441\u0442\u044c \u043d\u0430 \u0436\u0435\u043b\u0430\u0435\u043c\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u00ab\u041c\u043e\u0438 \u0434\u043e\u043c\u0435\u043d\u044b\u00bb, \u0430 \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u043c\u043e\u0433 \u0432\u043e\u0439\u0442\u0438 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0438\u0437-\u0437\u0430 Captcha.<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/g6\/ta\/b_\/g6tab_jwhp3gslgnvfcq_kmcuca.png\"><\/p>\n<p>  <\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u044f \u043f\u0440\u043e\u0432\u043e\u0437\u0438\u043b\u0441\u044f \u0441 \u044d\u0442\u0438\u043c \u0438 \u043f\u044b\u0442\u0430\u043b\u0441\u044f \u0434\u0435\u0431\u0435\u0436\u0438\u0442\u044c\/\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0430\u0434 \u044d\u0442\u0438\u043c \u043f\u043e\u043b\u0434\u043d\u044f, \u044f \u0440\u0435\u0448\u0438\u043b, \u0447\u0442\u043e \u044d\u0442\u043e \u0431\u0435\u0437\u043d\u0430\u0434\u0435\u0436\u043d\u043e\u0435 \u0434\u0435\u043b\u043e, \u0442\u0430\u043a \u043a\u0430\u043a \u0432 \u043b\u044e\u0431\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u0441\u0451, \u0447\u0442\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f, \u2014 \u044d\u0442\u043e \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043e\u0434\u043d\u0443 \u0438\u0437 \u0441\u0442\u0440\u0430\u043d\u0438\u0446, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u044f \u043f\u0440\u043e\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u043b \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e, \u0438 \u0432\u0441\u044f \u0440\u0430\u0431\u043e\u0442\u0430 \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0440\u0443\u0448\u0435\u043d\u0430. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b \u043f\u0440\u0438\u0431\u0435\u0433\u043d\u0443\u0442\u044c \u043a \u0441\u043a\u0443\u0447\u043d\u043e\u043c\u0443 \u043c\u0435\u0442\u043e\u0434\u0443, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e \u0441\u0438\u0445 \u043f\u043e\u0440 \u044f \u043f\u043e \u0433\u043b\u0443\u043f\u043e\u0441\u0442\u0438 \u043d\u0435 \u0438\u0437\u0443\u0447\u0430\u043b \u043e\u0447\u0435\u043d\u044c \u0433\u043b\u0443\u0431\u043e\u043a\u043e.<\/p>\n<p>  <\/p>\n<p>\u0422\u0430\u043a \u0443\u0436 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c, \u0447\u0442\u043e \u0443 Google Domains \u0435\u0441\u0442\u044c API \u0438\u043c\u0435\u043d\u043d\u043e \u0434\u043b\u044f \u0442\u043e\u0439 \u0446\u0435\u043b\u0438, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043c\u043d\u0435 \u043d\u0443\u0436\u043d\u0430. \u042f \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u043e\u0442\u043a\u043b\u043e\u043d\u0438\u043b APi, \u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0441\u043c\u043e\u0433 \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0435\u0433\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043f\u0440\u0430\u0432\u0438\u043b\u0430\u043c\u0438 \u043f\u0435\u0440\u0435\u0430\u0434\u0440\u0435\u0441\u0430\u0446\u0438\u0438 \u043f\u043e\u0434\u0434\u043e\u043c\u0435\u043d\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b, \u043d\u0435 \u043f\u043e\u043d\u0438\u043c\u0430\u044f, \u0447\u0442\u043e API \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u0440\u0430\u0432\u0438\u043b <strong>\u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e DNS<\/strong> \u2014 <strong><a href=\"https:\/\/support.google.com\/domains\/answer\/6147083?hl=en-CA\" rel=\"nofollow noopener noreferrer\">\u044d\u0442\u0430 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f<\/a><\/strong> \u0441\u0442\u0430\u043b\u0430 \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043d\u044f\u0442\u043d\u043e\u0439 \u043f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043b \u0437\u0430\u043f\u0438\u0441\u044c \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e DNS \u0432\u043c\u0435\u0441\u0442\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0433\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u00ab\u041f\u0435\u0440\u0435\u0430\u0434\u0440\u0435\u0441\u0430\u0446\u0438\u044f \u043f\u043e\u0434\u0434\u043e\u043c\u0435\u043d\u043e\u0432\u00bb (\u0441\u043f\u0430\u0441\u0438\u0431\u043e <a href=\"https:\/\/medium.com\/u\/57d467229a39?source=post_page-----246570b26d88--------------------------------\" rel=\"nofollow noopener noreferrer\">\u0414\u0436\u0435\u0440\u0435\u043c\u0438 \u0413\u0435\u0439\u043b\u0443<\/a> \u0437\u0430 \u0435\u0433\u043e <strong><a href=\"https:\/\/medium.com\/@jeremygale\/how-to-set-up-a-free-dynamic-hostname-with-ssl-cert-using-google-domains-58929fdfbb7a\" rel=\"nofollow noopener noreferrer\">\u043e\u0442\u043b\u0438\u0447\u043d\u044b\u0439 \u0443\u0440\u043e\u043a<\/a><\/strong> \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f bash, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u043c\u043e\u0433 \u043c\u043d\u0435 \u043f\u043e\u0431\u0435\u0434\u0438\u0442\u044c \u044d\u0442\u0443 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443!)<\/p>\n<p>  <\/p>\n<p>\u0420\u0430\u0437\u0434\u0435\u043b \u00abSynthetic records\u00bb \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 DNS Google Domains \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/aw\/hd\/wk\/awhdwk-aufdedy9-4e7cofi4h1a.png\" alt=\"\u0412\u043e\u0442 \u043a\u0430\u043a \u0434\u043e\u043b\u0436\u043d\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0432\u0430\u0448\u0430 \u0437\u0430\u043f\u0438\u0441\u044c\"><\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/yr\/ga\/pr\/yrgapruvk6kghbkqxtlxagd0me8.png\" alt=\"\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u00abDynamic DNS\u00bb \u0432\u043c\u0435\u0441\u0442\u043e \u00abSubdomain forward\u00bb.\"><\/p>\n<p>  <\/p>\n<p>\u0417\u0430\u0442\u0435\u043c \u0432\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0443\u0447\u0435\u0442\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e API:<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/zk\/dw\/yn\/zkdwynofai0kgdzsty_cby15vyi.png\" alt=\"\u041f\u0440\u043e\u0441\u0442\u043e \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u00ab\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0443\u0447\u0435\u0442\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435\u00bb, \u0441\u043a\u043e\u043f\u0438\u0440\u0443\u0439\u0442\u0435 \u0438 \u0432\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u0438\u0445 \u0432 \u0441\u0432\u043e\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 API.\"><\/p>\n<p>  <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c, \u0437\u043d\u0430\u044f \u044d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434, \u044f \u0441\u043c\u043e\u0433 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c \u0434\u043b\u0438\u043d\u0443 \u0438 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u043d\u0430 \u0441\u043a\u0440\u0438\u043f\u0442! TTL \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e DNS \u0442\u0430\u043a\u0436\u0435 \u043e\u0447\u0435\u043d\u044c \u043d\u0438\u0437\u043e\u043a, \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e: 1 \u043c\u0438\u043d, \u0447\u0442\u043e \u0441\u043e\u043a\u0440\u0430\u0449\u0430\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u044f \u2014 \u0435\u0449\u0451 \u043e\u0434\u0438\u043d \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0431\u043e\u043d\u0443\u0441. \u0412\u0441\u0451, \u0447\u0442\u043e \u043c\u043d\u0435 \u0431\u044b\u043b\u043e \u043d\u0443\u0436\u043d\u043e, \u044d\u0442\u043e \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0432\u044b\u0437\u043e\u0432 API \u0432 \u043c\u043e\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e check_ip(), \u0438 \u043e\u043d \u0441\u0434\u0435\u043b\u0430\u0435\u0442 \u0432\u0441\u0435 \u0437\u0430 \u043c\u0435\u043d\u044f! \u0418 \u044d\u0442\u0430 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \u043a\u043e\u0434\u0430 (2 \u0441 \u0432\u044b\u0437\u043e\u0432\u043e\u043c \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f) \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<p>  <\/p>\n<pre><code class=\"python\">req = requests.post(f'https:\/\/&lt;auto_generated_username&gt;:&lt;auto_generated_password&gt;@domains.google.com\/nic\/update?hostname=@.example.com&amp;myip={IP}')  logging.info(req.content)<\/code><\/pre>\n<p>  <\/p>\n<p>\u042f \u0437\u0430\u043a\u043b\u044e\u0447\u0438\u043b \u0432\u0441\u0451 \u0432 \u0431\u043b\u043e\u043a try \/ except, \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0438\u0442\u044c \u043b\u044e\u0431\u044b\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f, \u0438 \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u044d\u0442\u043e\u0442 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0439, \u043d\u043e \u0443\u0434\u0438\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0439 \u0441\u043a\u0440\u0438\u043f\u0442 \u0431\u044b\u043b \u043f\u043e\u0447\u0442\u0438 \u0433\u043e\u0442\u043e\u0432. \u0422\u0435\u043f\u0435\u0440\u044c \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0435\u0433\u043e \u0432 crontab \u043d\u0430 \u043c\u043e\u0435\u043c \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0438 \u0434\u0430\u0442\u044c \u0435\u043c\u0443 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c, \u0438 (\u0442\u0435\u043e\u0440\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u0438) \u043c\u043d\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0431\u0435\u0441\u043f\u043e\u043a\u043e\u0438\u0442\u044c\u0441\u044f \u043e \u0441\u043c\u0435\u043d\u0435 IP!<\/p>\n<p>  <\/p>\n<h2 id=\"stop--vremya-refaktoringa\">\u0421\u0442\u043e\u043f! \u2026 \u0412\u0440\u0435\u043c\u044f \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433\u0430<\/h2>\n<p>  <\/p>\n<p>\u0422\u0430\u043a, \u0432\u043e\u0442, \u043e \u0447\u0435\u043c \u044f \u043f\u043e\u0437\u0430\u0431\u043e\u0442\u0438\u043b\u0441\u044f! \u0427\u0442\u043e\u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u0441\u043a\u0440\u0438\u043f\u0442 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c, \u044f \u0440\u0435\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u043b \u0432\u0441\u0451, \u0447\u0442\u043e\u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u043d\u043e-\u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434, \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043d\u0430 \u043a\u043b\u0430\u0441\u0441\u0430\u0445, \u0441 \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438 <code>User<\/code> \u0438 <code>IpChanger<\/code>. \u041a\u043b\u0430\u0441\u0441 <code>User<\/code> \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0432\u0441\u0435 \u0443\u0447\u0435\u0442\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0432\u0445\u043e\u0434\u0430 \u0432 smtp \u0438 \u0432\u044b\u0437\u043e\u0432\u0430 API domains.google, \u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u043c <code>previous_ip<\/code>, \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438, \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0432 \u043e\u0434\u043d\u043e\u043c pickle \u0444\u0430\u0439\u043b\u0435 (\u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432 JavaScript); \u0432 \u0431\u0443\u0434\u0443\u0449\u0438\u0445 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430\u0445 \u043a\u043b\u0430\u0441\u0441\u0430 <code>User()<\/code> \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0438\u0437 pickle, \u0435\u0441\u043b\u0438 \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043e \u0438\u043d\u043e\u0435. \u041a\u043b\u0430\u0441\u0441 <code>User<\/code> \u0442\u0430\u043a\u0436\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043c\u0435\u0442\u043e\u0434 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043f\u043e \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0443\u0441\u043b\u043e\u0432\u0438\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u043d\u0430 \u0441\u043b\u0443\u0447\u0430\u0439 \u0441\u0431\u043e\u044f \u0432\u044b\u0437\u043e\u0432\u0430 API. \u0417\u0430\u0442\u0435\u043c \u043a\u043b\u0430\u0441\u0441 <code>IpChanger<\/code> \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u043a\u043b\u0430\u0441\u0441 <code>User()<\/code> \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u043e\u043d \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0432\u0441\u0435 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0435 \u043a\u043b\u0430\u0441\u0441 <code>IpChanger()<\/code> \u0438 \u0432\u0441\u0451; \u043e\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442! \u042f \u0442\u0430\u043a\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u043f\u043e \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u0435, \u0431\u043e\u043b\u0435\u0435 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0443\u044e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043e\u0448\u0438\u0431\u043e\u043a\/\u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b\/\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0444\u0438\u043b\u0435\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u043c\u043e\u0433 \u0438\u0437\u0431\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u043e\u0442 \u043d\u0435\u0443\u043a\u043b\u044e\u0436\u0435\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0444\u0430\u0439\u043b\u0430 <code>ip.txt<\/code>, \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0432 \u0432\u0441\u0451 \u0432 \u043e\u0434\u043d\u043e\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u043c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0435.<\/p>\n<p>  <\/p>\n<p>\u0413\u043e\u0442\u043e\u0432\u044b\u0439, \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 (!) \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u043d\u0438\u0436\u0435 \u0432\u043e \u0432\u0441\u0435\u0439 \u0435\u0433\u043e \u043f\u043e\u043b\u043d\u043e\u0442\u0435, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0444\u043e\u0440\u043a\u043d\u0443\u0442\u044c\/\u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441 <a href=\"https:\/\/github.com\/nihilok\/ipChecker\" rel=\"nofollow noopener noreferrer\">\u043c\u043e\u0435\u0433\u043e GitHub<\/a> (\u0432\u043a\u043b\u044e\u0447\u0430\u044f README.md \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438 \u043f\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435). \u042f \u0442\u0430\u043a\u0436\u0435 \u0432\u044b\u043f\u0443\u0441\u0442\u0438\u043b \u0435\u0433\u043e \u043a\u0430\u043a \u043f\u0430\u043a\u0435\u0442 Python \u043d\u0430 pypi.org, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c <a href=\"http:\/\/pypi.org\/project\/domains-api\" rel=\"nofollow noopener noreferrer\">\u0437\u0434\u0435\u0441\u044c<\/a> \u0438\u043b\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043e\u0431\u044b\u0447\u043d\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e: <code>pip install domains-api<\/code><\/p>\n<p>  <\/p>\n<p>\u041b\u044e\u0431\u044b\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b, \u043e\u0442\u0437\u044b\u0432\u044b \u0438\u043b\u0438 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u2014 \u043f\u0438\u0448\u0438\u0442\u0435!<\/p>\n<p>  <\/p>\n<hr>\n<p>  <\/p>\n<p>\u041a\u0430\u043a\u0438\u0435 \u0435\u0449\u0451 \u043c\u0435\u0442\u043e\u0434\u044b \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0431\u0435\u0437 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0430\u0434\u0440\u0435\u0441\u0430 \u0432\u044b \u0437\u043d\u0430\u0435\u0442\u0435? \u0418 \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u044d\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435?<\/p>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041f\u043e\u043b\u043d\u044b\u0439 \u0441\u043a\u0440\u0438\u043f\u0442 (\u0431\u0435\u0437 file_handlers.py):<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">import os import sys import getopt import base64 import smtplib from email.message import EmailMessage from getpass import getpass from itertools import cycle  from requests import get, post from requests.exceptions import ConnectionError as ReqConError  from domains_api.file_handlers import FileHandlers  fh = FileHandlers()  def get_ip_only():     &quot;&quot;&quot;Gets current external IP from ipify.org&quot;&quot;&quot;     current_ip = get('https:\/\/api.ipify.org').text     return current_ip  class User:      BASE_URL = '@domains.google.com\/nic\/update?hostname='      def __init__(self):          &quot;&quot;&quot;Create user instance and save it for future changes to API and for email notifications.&quot;&quot;&quot;          self.domain, self.dns_username, self.dns_password, self.req_url = self.set_credentials()         self.notifications, self.gmail_address, self.gmail_password = self.set_email()         self.outbox = []      def set_credentials(self):          &quot;&quot;&quot;Set\/return attributes for Google Domains credentials&quot;&quot;&quot;          self.domain = input(&quot;What's your domain? (example.com \/ subdomain.example.com): &quot;)         self.dns_username = input(&quot;What's your autogenerated dns username?: &quot;)         self.dns_password = getpass(&quot;What's your autogenerated dns password?: &quot;)         self.req_url = f'https:\/\/{self.dns_username}:{self.dns_password}{self.BASE_URL}{self.domain}'         return self.domain, self.dns_username, self.dns_password, self.req_url      def set_email(self):          &quot;&quot;&quot;Set\/return attributes for Gmail credentials if user enables notifications&quot;&quot;&quot;          self.notifications = input(&quot;Enable email notifications? [Y]all(default); [e]errors only; [n]no: &quot;).lower()         if self.notifications != 'n':             self.gmail_address = input(&quot;What's your email address?: &quot;)             self.gmail_password = base64.b64encode(getpass(&quot;What's your email password?: &quot;).encode(&quot;utf-8&quot;))             if self.notifications != 'e':                 self.notifications = 'Y'             return self.notifications, self.gmail_address, self.gmail_password         else:             return 'n', None, None      def send_notification(self, ip=None, msg_type='success', error=None, outbox_msg=None):          &quot;&quot;&quot;Notify user via email if IP change is made successfully or if API call fails.&quot;&quot;&quot;          if self.notifications != 'n':             msg = EmailMessage()             msg['From'] = self.gmail_address             msg['To'] = self.gmail_address             if ip and msg_type == 'success' and self.notifications not in {'n', 'e'}:                 msg.set_content(f'IP for {self.domain} has changed! New IP: {ip}')                 msg['Subject'] = 'IP CHANGED!'             elif msg_type == 'error' and self.notifications != 'n':                 msg.set_content(f&quot;Error with {self.domain}'s IPChanger: ({error})!&quot;)                 msg['Subject'] = 'IPCHANGER ERROR!'             elif outbox_msg:                 msg = outbox_msg              try:                 server = smtplib.SMTP_SSL('smtp.gmail.com', 465)                 server.ehlo()                 server.login(self.gmail_address, base64.b64decode(self.gmail_password).decode('utf-8'))                 server.send_message(msg)                 server.close()                 return True             except Exception as e:                 log_msg = 'Email notification not sent: %s' % e                 fh.log(log_msg, 'warning')                 self.outbox.append(msg)                 fh.save_user(self)                 sys.exit(1)  class IPChanger:      ARG_STRING = 'cdehinu:'     ARG_LIST = ['credentials',                 'delete_user',                 'email',                 'help',                 'ip',                 'notifications',                 'user_load=']      def __init__(self, argv=None):          &quot;&quot;&quot;Check for command line arguments, load\/create User instance,         check previous IP address against current external IP, and change via the API if different.&quot;&quot;&quot;          # Load old user, or create new one:         if os.path.isfile(fh.user_file):             self.user = fh.load_user(fh.user_file)             fh.log('User loaded from pickle', 'debug')         else:             self.user = User()             fh.log('New user created.\\n(See `python -m domains_api --help` for help changing\/removing the user)', 'info')         self.current_ip = self.get_set_ip()          # Parse command line options:         try:             opts, _args = getopt.getopt(argv, self.ARG_STRING, self.ARG_LIST)         except getopt.GetoptError:             print('''Usage: python\/python3 -m domains_api --help''')             sys.exit(2)         if opts:             self.arg_parse(opts)          # Check IPs:         try:             if self.user.previous_ip == self.current_ip:                 log_msg = 'Current IP: %s (no change)' % self.user.previous_ip             else:                 self.user.previous_ip = self.current_ip                 fh.save_user(self.user)                 self.domains_api_call()                 log_msg = 'Newly recorded IP: %s' % self.user.previous_ip             fh.log(log_msg, 'info')         except AttributeError:             setattr(self.user, 'previous_ip', self.current_ip)             fh.save_user(self.user)             self.domains_api_call()         finally:             if fh.op_sys == 'pos' and os.geteuid() == 0:                 fh.set_permissions(fh.user_file)              # Send outbox emails:             if self.user.outbox:                 for i in range(len(self.user.outbox)):                     self.user.send_notification(outbox_msg=self.user.outbox.pop(i))                     fh.log('Outbox message sent', 'info')                 fh.save_user(self.user)             fh.clear_logs()      def get_set_ip(self):          &quot;&quot;&quot;Gets current external IP from api.ipify.org and sets self.current_ip&quot;&quot;&quot;          try:             return get_ip_only()         except (ReqConError, ConnectionError) as e:             fh.log('Connection Error. Could not reach api.ipify.org', 'warning')             self.user.send_notification(msg_type='error', error=e)      def domains_api_call(self):          &quot;&quot;&quot;Attempt to change the Dynamic DNS rules via the Google Domains API and handle response codes&quot;&quot;&quot;          try:             req = post(f'{self.user.req_url}&amp;myip={self.current_ip}')             response = req.text             log_msg = 'Google Domains API response: %s' % response             fh.log(log_msg, 'info')              # Successful request:             _response = response.split(' ')             if 'good' in _response or 'nochg' in _response:                 self.user.send_notification(self.current_ip)              # Unsuccessful requests:             elif response in {'nohost', 'notfqdn'}:                 msg = &quot;The hostname does not exist, is not a fully qualified domain&quot; \\                       &quot; or does not have Dynamic DNS enabled. The script will not be &quot; \\                       &quot;able to run until you fix this. See https:\/\/support.google.com\/domains\/answer\/6147083?hl=en-CA&quot; \\                       &quot; for API documentation&quot;                 fh.log(msg, 'warning')                 if input(&quot;Recreate the API profile? (Y\/n):&quot;).lower() != 'n':                     self.user.set_credentials()                     self.domains_api_call()                 else:                     self.user.send_notification(self.current_ip, 'error', msg)             else:                 fh.log(&quot;Could not authenticate with these credentials&quot;, 'warning')                 if input(&quot;Recreate the API profile? (Y\/n):&quot;).lower() != 'n':                     self.user.set_credentials()                     self.domains_api_call()                 else:                     fh.delete_user()                     fh.log('API authentication failed, user profile deleted', 'warning')                     sys.exit(1)         # Local connection related errors         except (ConnectionError, ReqConError) as e:             log_msg = 'Connection Error: %s' % e             fh.log(log_msg, 'warning')             self.user.send_notification(msg_type='error', error=e)      def arg_parse(self, opts):          &quot;&quot;&quot;Parses command line options: e.g. &quot;python -m domains_api --help&quot; &quot;&quot;&quot;          for opt, arg in opts:             if opt in {'-i', '--ip'}:                 print('''             [Domains API] Current external IP: %s                 ''' % get_ip_only())             elif opt in {'-h', '--help'}:                 print(                     &quot;&quot;&quot;         domains-api help manual (command line options):<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"plaintext\">    You will need your autogenerated Dynamic DNS keys from     https:\/\/domains.google.com\/registrar\/example.com\/dns     to create a user profile.     python -m domains_api                    || -run the script normally without arguments     python -m domains_api -h --help          || -show this help manual     python -m domains_api -i --ip            || -show current external IP address     python -m domains_api -c --credentials   || -change API credentials     python -m domains_api -e --email         || -email set up wizard &gt; use to delete email credentials (choose 'n')     python -m domains_api -n --notifications || -toggle email notification settings &gt; will not delete email address     python -m domains_api -u user.file       || (or &quot;--user_load path\/to\/user.file&quot;) -load user from pickle file     python -m domains_api -d --delete_user   || -delete current user profile                                              || User files are stored in &quot;\/var\/www\/domains_api\/domains.user&quot; &quot;&quot;&quot;             )         elif opt in {'-c', '--credentials'}:             self.user.set_credentials(update=True)             self.domains_api_call()             fh.save_user(self.user)             fh.log('API credentials changed', 'info')         elif opt in {'-d', '--delete'}:             fh.delete_user()             fh.log('User deleted', 'info')             print('&gt;&gt;&gt;Run the script without options to create a new user, or '                   '&quot;python3 -m domains_api -u path\/to\/pickle&quot; to load one from file')         elif opt in {'-e', '--email'}:             self.user.set_email()             fh.save_user(self.user)             fh.log('Notification settings changed', 'info')         elif opt in {'-n', '--notifications'}:             n_options = {'Y': '[all changes]', 'e': '[errors only]', 'n': '[none]'}             options_iter = cycle(n_options.keys())             for option in options_iter:                 if self.user.notifications == option:                     break             self.user.notifications = next(options_iter)             fh.save_user(self.user)             log_msg = 'Notification settings changed to %s' % n_options[self.user.notifications]             fh.log(log_msg, 'info')             if self.user.notifications in {'Y', 'e'} and not self.user.gmail_address:                 fh.log('No email user set, running email set up wizard...', 'info')                 self.user.set_email()                 fh.save_user(self.user)         elif opt in {'-u', '--user_load'}:             try:                 self.user = fh.load_user(arg)                 fh.save_user(self.user)                 fh.log('User loaded', 'info')             except FileNotFoundError as e:                 fh.log(e, 'warning')                 sys.exit(2)         sys.exit()<\/code><\/pre>\n<p>  <\/p>\n<p>if <strong>name<\/strong> == &quot;<strong>main<\/strong>&quot;:<br \/>  IPChanger(sys.argv[1:])<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">&lt;!--&lt;\/spoiler&gt;--&gt;<\/code><\/pre>\n<\/div><\/div>\n<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/557126\/\"> https:\/\/habr.com\/ru\/post\/557126\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\">\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/wk\/mt\/wc\/wkmtwc-p-oaltwox6zahqwicnmw.jpeg\"><\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u0425\u0430\u0431\u0440\u0430! <\/p>\n<p>  <\/p>\n<p>\u0417\u0430\u0434\u0430\u043b\u0441\u044f \u0442\u0443\u0442 \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u043c, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c \u0431\u0435\u0437 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e IP \u0434\u043b\u044f \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u043e\u0432 \u0432 \u0434\u043e\u043c\u0430\u0448\u043d\u0438\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445. \u041d\u0430\u0442\u043a\u043d\u0443\u043b\u0441\u044f \u043d\u0430 \u0432\u043e\u0442 \u044d\u0442\u0443 \u0441\u0442\u0430\u0442\u044c\u044e. <\/p>\n<p>  <\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0441\u0432\u043e\u0439 \u0432\u0435\u0431\u0441\u0435\u0440\u0432\u0435\u0440 \u0441 \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c \u0438\u0437\u0432\u043d\u0435, \u0430 \u043f\u043b\u0430\u0442\u0438\u0442\u044c \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u0443 \u0437\u0430 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 IP \u043d\u0435 \u0445\u043e\u0442\u0438\u0442\u0435, \u0442\u043e \u0434\u0430\u043d\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0432\u043f\u043e\u043b\u043d\u0435 \u0441\u0435\u0431\u0435 \u0432\u044b\u0445\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u043e\u0436\u043d\u043e \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u043f\u043e\u0434\u043e\u0433\u043d\u0430\u0442\u044c \u043f\u043e\u0434 \u0441\u0432\u043e\u0438 \u043d\u0443\u0436\u0434\u044b.<\/p>\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-323040","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/323040","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=323040"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/323040\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=323040"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=323040"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=323040"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}