<?xml version="1.0" encoding="utf-8" ?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:tt="http://teletype.in/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"><title>AIO Study</title><subtitle>by hodlmod</subtitle><author><name>AIO Study</name></author><id>https://teletype.in/atom/aiostudy</id><link rel="self" type="application/atom+xml" href="https://teletype.in/atom/aiostudy?offset=0"></link><link rel="alternate" type="text/html" href="https://teletype.in/@aiostudy?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=aiostudy"></link><link rel="next" type="application/rss+xml" href="https://teletype.in/atom/aiostudy?offset=10"></link><link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></link><updated>2026-05-30T18:48:07.233Z</updated><entry><id>aiostudy:c9N7AdbxhYU</id><link rel="alternate" type="text/html" href="https://teletype.in/@aiostudy/c9N7AdbxhYU?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=aiostudy"></link><title>Гайд по нейросетям </title><published>2025-03-01T11:53:37.220Z</published><updated>2025-03-02T20:24:16.719Z</updated><summary type="html">Когда мы вступили в информационную эпоху любая информация начала продаваться. Челы быстро поняли, что любую инфу можно продать под обёрткой &quot;GEM&quot;. Например, нейросети только появились, а инфоцыгане сразу же нашли в этом выгоду. Они стали продавать информацию по использованию нового инструмента, который по своей сути не является чем-то мега сложным для потребителя.</summary><content type="html">
  &lt;p id=&quot;jEyK&quot;&gt;Сейчас продают любую информацию, даже самую базовую, выдавая её за &amp;quot;уникальные знания&amp;quot;. Мы с этим не согласны. Вот, например, чуваки, которые учат писать промпты. Серьёзно? Продавать умение формулировать запрос — это уже перебор.&lt;/p&gt;
  &lt;p id=&quot;SJo1&quot;&gt;Мы сделали этот гайд, чтобы показать на этом примере: &lt;strong&gt;работать с нейросетями вообще несложно&lt;/strong&gt;. Тут не нужно знать физику или секретные техники.&lt;/p&gt;
  &lt;p id=&quot;1tVi&quot;&gt;&lt;strong&gt;Главное — уметь чётко формулировать задачу.&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;Zo32&quot;&gt;Мы не против тех, кто реально делится опытом, например, учит строить проекты используя только нейронки. Это ценный контент, а вот продавать базовые вещи — scam.&lt;/p&gt;
  &lt;h2 id=&quot;BXDg&quot;&gt;Оглавление&lt;/h2&gt;
  &lt;p id=&quot;8kPe&quot;&gt;&lt;a href=&quot;#5e5Y&quot;&gt;Кастомные инстуркции&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;G3J8&quot;&gt;&lt;a href=&quot;#9n5P&quot;&gt;Как получить ответ, который тебе нужен&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;1rWm&quot;&gt;&lt;a href=&quot;#cc0t&quot;&gt;База данных ChatGPT&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;3itt&quot;&gt;&lt;a href=&quot;#81Xc&quot;&gt;Упрощение жизни&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;m5gq&quot;&gt;&lt;a href=&quot;#Z16M&quot;&gt;Какую нейронку и для чего юзать&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;SEXj&quot;&gt;&lt;a href=&quot;#9Zyq&quot;&gt;Заключение&lt;/a&gt;&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;pvvs&quot;&gt;&lt;strong&gt;Небольшой дисклеймер&lt;/strong&gt;&lt;/p&gt;
    &lt;p id=&quot;mZsJ&quot;&gt;Просим вас не воспринимать данный гайд как способ получить альфу. Мы лишь делимся своим опытом по качественному использованию нейронок. Так что выглядеть это будет скорее как шпаргалка по различным темам связанными с ними.&lt;/p&gt;
    &lt;p id=&quot;EeCw&quot;&gt;Все примеры будут показаны на ChatGPT, но некоторые из советов будут приминимы и с другими нейронками.&lt;/p&gt;
  &lt;/section&gt;
  &lt;h2 id=&quot;5e5Y&quot;&gt;Кастомные инструкции&lt;/h2&gt;
  &lt;p id=&quot;ZM3H&quot;&gt;Речь пойдёт о кнопке &lt;strong&gt;&amp;quot;Настроить ChatGPT&amp;quot;&lt;/strong&gt;. Если ты ни разу не замечал эту кнопку, то ты многое потерял.&lt;/p&gt;
  &lt;figure id=&quot;mQYl&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/fd/ba/fdbaacc6-73f0-4b95-b523-a78c2fcd55e3.png&quot; width=&quot;358&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;mJuT&quot;&gt;Погнали посмотрим, что там есть внутри:&lt;/p&gt;
  &lt;p id=&quot;SIFL&quot;&gt;&lt;strong&gt;1. Как должен ChatGPT обращаться к вам?&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;P5BS&quot;&gt;Тут понятно, назови себя &amp;quot;Boy Next Door&amp;quot; или &amp;quot;My Master&amp;quot; для антуража.&lt;/p&gt;
  &lt;p id=&quot;rgHi&quot;&gt;&lt;strong&gt;2. Кем вы работаете?&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;w0Rn&quot;&gt;Вот здесь уже интереснее. Укажи направление, в котором ChatGPT должен тебе помогать. Это не значит, что ему нужно знать, что ты каменщик и работаешь три дня без зарплаты. Просто напиши сферу, например, &amp;quot;Python Programmer&lt;em&gt;&amp;quot;&lt;/em&gt;, чтобы он лучше помогал тебе с запросами по этой теме.&lt;/p&gt;
  &lt;p id=&quot;t7I2&quot;&gt;&lt;strong&gt;3. Какими характеристиками должен обладать ChatGPT&lt;/strong&gt;&lt;/p&gt;
  &lt;figure id=&quot;KeyX&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/de/64/de6447a5-7f45-4cdb-a86f-d5a871d64702.png&quot; width=&quot;601&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;H2xK&quot;&gt;Тут ты можешь указать характеристики ассистента мечты. Скажи ему, что он должен писать как офисный клерк или наоборот, более заряженно и неформально. А еще можешь написать, чтобы он не выдумывал факты, писал только на русском и т.д.&lt;/p&gt;
  &lt;p id=&quot;2irJ&quot;&gt;&lt;strong&gt;Вот пример нашей инструкции (индивидуально):&lt;/strong&gt;&lt;/p&gt;
  &lt;blockquote id=&quot;XuAy&quot;&gt;Отвечай без воды, учитывай контекст.&lt;br /&gt;Если не знаешь ответ — говори об этом и предлагай альтернативы. &lt;br /&gt;В сложных процессах давай пошаговые инструкции, &lt;br /&gt;Если есть траты, то указывай их в рублях и круглых скобках.&lt;/blockquote&gt;
  &lt;blockquote id=&quot;ToXc&quot;&gt;Пиши в разговорном стиле, как с другом.  &lt;br /&gt;Отвечай кратко для простых вопросов, подробно для сложных.  &lt;br /&gt;Примеры обязательны, если задача сложная.  &lt;br /&gt;Предположения допустимы, но уточняй, что это предположение.  &lt;br /&gt;В бизнес-вопросах проверяй актуальность данных.&lt;/blockquote&gt;
  &lt;blockquote id=&quot;GDVx&quot;&gt;Если тема касается заработка, то уделяй ей особое внимание.&lt;/blockquote&gt;
  &lt;blockquote id=&quot;W2rq&quot;&gt;Если в конце сообщения будет написано &amp;quot;Вопросы.&amp;quot;, то задавай максимум уточняющих вопросов.&lt;/blockquote&gt;
  &lt;p id=&quot;X4PZ&quot;&gt;Можешь опираться на данную инструкцию и адаптировать под свои нужды. Если чего-то не хватает и хочешь чтобы чел отвечал тебе более кратко, например, то просто добавь это в промпт.&lt;/p&gt;
  &lt;p id=&quot;lZgH&quot;&gt;&lt;strong&gt;4. Что-нибудь еще, что ChatGPT должен знать о вас&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;nb3Q&quot;&gt;Если нужно, чтобы ChatGPT знал что-то конкретное о тебе, например, что ты нищий кодер и хочешь через 2 месяца стать крипто скамером, то можешь указать это. Тогда его ответы будут сформированы на основе твоих предпочтений и увлечений.&lt;/p&gt;
  &lt;p id=&quot;Qs01&quot;&gt;&lt;strong&gt;Например:&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;E6Y3&quot;&gt;Если ты указал, что владеешь ларьком с шаурмой, а в чате переживаешь, что новый проект может не выстрелить и что тогда делать, ChatGPT сможет проанализировать ситуацию и напомнит, что у тебя уже есть стабильный заработок, так что загоняться не стоит – всё будет нормально.&lt;/p&gt;
  &lt;h2 id=&quot;9n5P&quot;&gt;Как получить ответ, который тебе нужен&lt;/h2&gt;
  &lt;p id=&quot;OeXM&quot;&gt;Это самая важная часть. Возможно, ты слышал выражение: &lt;strong&gt;&lt;em&gt;«Как корабль назовёшь, так он и поплывёт»&lt;/em&gt;?&lt;/strong&gt; Здесь тот же принцип – чем чётче ты сформулируешь запрос, тем лучше будет ответ.&lt;/p&gt;
  &lt;h3 id=&quot;sb3A&quot;&gt;Разберём на примере: с чего ты можешь начать диалог?&lt;/h3&gt;
  &lt;p id=&quot;iqCa&quot;&gt;Пример качественного промпта:&lt;/p&gt;
  &lt;blockquote id=&quot;yTz3&quot;&gt;В этом чате ты копирайтер. Мне необходимо, чтобы ты писал статьи для моего ТГ-канала про самодисциплину. Сейчас хочу разобрать тему «Почему казик — зло». Я буду тебе кидать просто название темы либо её описание, а ты должен выдавать структурированную статью без делового стиля, внутри которой нужно делать нативные упоминания самодисциплины и добавить мотивацию в конце.&lt;/blockquote&gt;
  &lt;p id=&quot;QXej&quot;&gt;Из чего состоит этот промпт:&lt;/p&gt;
  &lt;p id=&quot;1AKH&quot;&gt;&lt;strong&gt;1. Использование правила &amp;quot;NoHello&amp;quot;&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;ILfM&quot;&gt;Ты, возможно, уже знаком с правилом &lt;strong&gt;&amp;quot;&lt;/strong&gt;NoHello&lt;strong&gt;&amp;quot;&lt;/strong&gt; – его суть в том, чтобы сразу писать свою проблему, не дожидаясь ответа на простое &amp;quot;Привет&amp;quot;. С ChatGPT это правило особенно актуально, поэтому переходим сразу к делу.&lt;/p&gt;
  &lt;p id=&quot;5XrV&quot;&gt;&lt;strong&gt;2. Постановка роли ChatGPT в этом чате&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;HHY3&quot;&gt;Если ты просто попросишь нейронку &amp;quot;напиши статью по теме ...&amp;quot;, он, возможно, поймёт, что от него требуется, но качество ответа будет не на высоте. Чтобы получить действительно экспертный разбор, нужно указать, что он должен писать статьи как профессионал в данной области.&lt;/p&gt;
  &lt;p id=&quot;GE9J&quot;&gt;&lt;strong&gt;3. Предупредить о том, что ты будешь скидывать в чат&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;wRMn&quot;&gt;Нейронка должна знать контекст будущих сообщений. Чётко опиши, что ты собираешься ей отправлять.&lt;/p&gt;
  &lt;p id=&quot;XkSH&quot;&gt;&lt;strong&gt;4. Описание формата ответа на твой запрос&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;Y4uy&quot;&gt;Если ты не напишешь, то как хочешь видеть ответ на твой запрос, то будь готов к проявлению &amp;quot;креативности&amp;quot;. Она может написать вместо объемного и детального разбора темы, краткий пересказ заезженных пунктов.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;8cMJ&quot;&gt;Если будешь следовать этим советам, получишь именно тот ответ, который ожидаешь.&lt;/p&gt;
  &lt;h2 id=&quot;cc0t&quot;&gt;База данных ChatGPT&lt;/h2&gt;
  &lt;p id=&quot;HLeB&quot;&gt;ChatGPT можно использовать как персональную базу данных, где сохраняется контекст всех разговоров, идей и проектов. Это позволяет не держать информацию в голове, а при необходимости обращаться к ней без необходимости запоминания деталей.&lt;/p&gt;
  &lt;h3 id=&quot;5Nfh&quot;&gt;Как эффективно использовать ChatGPT как базу данных&lt;/h3&gt;
  &lt;p id=&quot;gZiK&quot;&gt;Вы, скорее всего, уже пишете себе заметки в избранное в Telegram. Здесь то же самое — просто скармливаете GPT инфу и потом работаете с ней.&lt;/p&gt;
  &lt;p id=&quot;s5PZ&quot;&gt;&lt;strong&gt;Например:&lt;/strong&gt; у вас появилась идея создать свой проект по продаже ковриков для мышки. Кидаете все мысли об этом проекте в GPT, что полезно прямо на старте. Потому что нейросеть поможет реализовать его ещё лучше, чем вы могли бы придумать сами.&lt;/p&gt;
  &lt;p id=&quot;egLM&quot;&gt;Чат, в котором обсуждаете проект, становится вашим идеальным справочником и документацией, где можно быстро найти инфу о своём же проекте.&lt;/p&gt;
  &lt;p id=&quot;NkVG&quot;&gt;&lt;strong&gt;Как это может помочь?&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;P4Wu&quot;&gt;Любую вашу идею он может докрутить! Например, вы придумали, что рекламить надо через TikTok. Теперь все следующие идеи он будет учитывать с этим контекстом, подсказывая варианты и решения как с рекламой через TikTok, так и без него.&lt;/p&gt;
  &lt;p id=&quot;KaNK&quot;&gt;&lt;strong&gt;Как объяснить GPT свою идею?&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;AuPn&quot;&gt;Представьте, что вы делаете максимально подробную презентацию проекта для друга, которого хотите впечатлить. Нужно расписать каждую мелочь. Да, это займёт время, но оно того стоит — нейросеть станет вашим идеальным консультантом, понимая контекст на глубоком уровне.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;Ffob&quot;&gt;Любое взаимодействие с памятью ChatGPT подстраивает его индивидуально под вас. Проще говоря, создаёте себе идеального друга-консультанта, который всегда в теме ваших проектов.&lt;/p&gt;
  &lt;h2 id=&quot;81Xc&quot;&gt;Упрощение жизни&lt;/h2&gt;
  &lt;p id=&quot;Gt0L&quot;&gt;ChatGPT — это твой личный ассистент, который всегда под рукой. Он помогает сэкономить кучу времени и нервов. Больше не нужно перелопачивать сотни статей, разбираться, где правда, а где пустая болтовня, и пытаться самому собрать из всего этого цельную картину.&lt;/p&gt;
  &lt;p id=&quot;UrNd&quot;&gt;Просто задаёшь вопрос — и сразу получаешь суть. Никакого долгого ресёрча, никаких &amp;quot;наткнулся на что-то похожее, а в итоге это совсем не то&amp;quot;. &lt;u&gt;Только чёткий, понятный ответ, который подходит именно под твою ситуацию.&lt;/u&gt;&lt;/p&gt;
  &lt;h3 id=&quot;WkLH&quot;&gt;Сравнение ChatGPT и Google в различных задачах&lt;/h3&gt;
  &lt;p id=&quot;MdTM&quot;&gt;В вопросах индивидуального подхода ChatGPT будет намного пластичней, нежели Google. Чтобы увидеть разницу, предлагаем сравнить их на различных задачах.&lt;/p&gt;
  &lt;p id=&quot;aalU&quot;&gt;&lt;strong&gt;Представь, что тебе нужно затронуть научную сферу.&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;3HZs&quot;&gt;&lt;strong&gt;Через Google&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;xX7K&quot;&gt;Тебе придётся тратить время на чтение множества статей, разбираться в разных точках зрения и стилях изложения. И не факт, что нужная информация вообще будет на понятном тебе языке.&lt;/p&gt;
  &lt;p id=&quot;Co1h&quot;&gt;&lt;strong&gt;Через ChatGPT&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;6tDJ&quot;&gt;ChatGPT сразу выдаст суть, подробно объяснит, как всё работает, и будет разбирать тему, пока ты полностью её не поймёшь. Причём на любом языке.&lt;/p&gt;
  &lt;p id=&quot;Vd7D&quot;&gt;&lt;strong&gt;Плюс:&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;rAlv&quot;&gt;У ChatGPT есть крутая функция — &lt;strong&gt;DeepResearch&lt;/strong&gt;, и мы без преувеличения скажем: &lt;u&gt;это реальная имба&lt;/u&gt;. В ChatGPT эта фича доступна только по подписке, но ты можешь затраить её в нейронке &lt;a href=&quot;https://grok.com&quot; target=&quot;_blank&quot;&gt;Grok&lt;/a&gt;, там она доступна бесплатно.&lt;/p&gt;
  &lt;figure id=&quot;xQpC&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/38/bd/38bdc3dc-d228-4ff5-9878-5e87c75de1be.png&quot; width=&quot;872&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;CMqB&quot;&gt;Как это работает? Если интересно узнать подробней и наглядно, то можешь глянуть вот этот &lt;a href=&quot;https://youtu.be/YR0eJOXZe2Q&quot; target=&quot;_blank&quot;&gt;видос&lt;/a&gt;. А если интересно в кратце, то читай дальше.&lt;/p&gt;
  &lt;p id=&quot;qljM&quot;&gt;Ты просто задаёшь запрос, например: &amp;quot;&lt;strong&gt;Как мне найти скрытое API сайта?&amp;quot;&lt;/strong&gt;. ChatGPT запускает глубокий ресёрч (отсюда и название) и начинает собирать воедино всю информацию по теме.&lt;/p&gt;
  &lt;p id=&quot;UenB&quot;&gt;Он переберёт кучу источников, найдёт релевантные ссылки, зацепит важные моменты, погрузится в детали. Допустим, он увидит, что в теме фигурирует Network в Developer Tools — добавит это в контекст. Дальше пойдёт глубже: найдёт инфу о фильтрации XHR-запросов, инструментах, методах, нюансах.&lt;/p&gt;
  &lt;p id=&quot;0Vnx&quot;&gt;В итоге ты получаешь огромную, структурированную статью с разбором всех деталей:&lt;/p&gt;
  &lt;p id=&quot;mkrV&quot;&gt;&lt;strong&gt;• Что такое скрытое API?&lt;br /&gt;• Как его находят?&lt;br /&gt;• Какие инструменты использовать?&lt;br /&gt;• Какие у каждого метода плюсы и минусы?&lt;br /&gt;• На что обратить внимание, чтобы не ошибиться?&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;pX3e&quot;&gt;&lt;strong&gt;От А до Я.&lt;/strong&gt; Полное погружение в тему, без воды и лишнего ресёрча.&lt;/p&gt;
  &lt;p id=&quot;Iw0C&quot;&gt;Лично мы очень оценили эту функцию. Для студентов и чуваков, которые хотят глубоко разобраться в вопросе — &lt;u&gt;&lt;strong&gt;это настоящий GEM.&lt;/strong&gt;&lt;/u&gt;&lt;/p&gt;
  &lt;p id=&quot;KMxK&quot;&gt;&lt;strong&gt;Теперь рассмотрим на другом примере: трекинге каллорий в еде.&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;xhlV&quot;&gt;&lt;strong&gt;Как бы ты это сделал через Google&lt;/strong&gt;&lt;/p&gt;
  &lt;ol id=&quot;gpQQ&quot;&gt;
    &lt;li id=&quot;psQW&quot;&gt;Тебе нужно было бы выяснить: что это за еда, если не знаешь, то думать над тем, что за ингридиенты в неё входят&lt;/li&gt;
    &lt;li id=&quot;p3HN&quot;&gt;Потом забиваешь свой запрос и смотришь результаты&lt;/li&gt;
    &lt;li id=&quot;K5GN&quot;&gt;Если ты ничего не нашёл, то пробуешь переписать запрос&lt;/li&gt;
    &lt;li id=&quot;6R1M&quot;&gt;Опять ничего? Ну все, гг, ты что ешь вообще?&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;PQF6&quot;&gt;&lt;strong&gt;Как это происходит через ChatGPT&lt;/strong&gt;&lt;/p&gt;
  &lt;ol id=&quot;kyHm&quot;&gt;
    &lt;li id=&quot;fRi0&quot;&gt;Фоткаешь свой хавчик&lt;/li&gt;
    &lt;li id=&quot;QUA0&quot;&gt;Отправляешь изображение ChatGPT и пишешь запрос&lt;/li&gt;
    &lt;li id=&quot;UGwf&quot;&gt;Он думает над тем, что у тебя там на фотке и сверяет со своими знаниями&lt;/li&gt;
    &lt;li id=&quot;ES2N&quot;&gt;Выдает тебе сколько каллорий у тебя на тарелке&lt;/li&gt;
    &lt;li id=&quot;ytxK&quot;&gt;Если не то, то уточняешь вместе с ним и приходишь к ответу&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;Y8LX&quot;&gt;Мы рассмотрели самый изъезженный пример, а давай попробуем что-то более интересное. Например, ты услышал какой-то трек и не знаешь его названия.&lt;/p&gt;
  &lt;p id=&quot;RkKY&quot;&gt;&lt;strong&gt;Как бы ты это сделал через Google&lt;/strong&gt;&lt;/p&gt;
  &lt;ol id=&quot;TeAN&quot;&gt;
    &lt;li id=&quot;NWIn&quot;&gt;Вспоминаешь слова и составляешь запрос&lt;/li&gt;
    &lt;li id=&quot;w0Fp&quot;&gt;Видишь в результатах хрень&lt;/li&gt;
    &lt;li id=&quot;z3jb&quot;&gt;Сдаёшься&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;Sbux&quot;&gt;&lt;strong&gt;Как это происходит через ChatGPT&lt;/strong&gt;&lt;/p&gt;
  &lt;ol id=&quot;q9sk&quot;&gt;
    &lt;li id=&quot;weGx&quot;&gt;Ты можешь ему напеть фрагмент трека через голосовой чат или написать текстом, выдать всю информацию о том, где ты это видел, что за жанр, или, может быть, ты знаешь что-то еще.&lt;/li&gt;
    &lt;li id=&quot;p4De&quot;&gt;ChatGPT думает над ответом и задает уточняющие вопросы&lt;/li&gt;
    &lt;li id=&quot;OcRT&quot;&gt;После того, как все готово он выдает тебе ответ с твоим треком&lt;/li&gt;
  &lt;/ol&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;hTJf&quot;&gt;Главный тейк в том, что ты можешь использовать GPT буквально как ассистента, который знает всё. Google ограничен своим форматом — он лишь предоставляет сайты, на которых может быть нужная тебе информация. А GPT уже владеет всей этой информацией, и твоя задача — лишь вытащить её из него путём качественного запроса.&lt;/p&gt;
  &lt;h2 id=&quot;Z16M&quot;&gt;Какую нейронку и для чего юзать&lt;/h2&gt;
  &lt;p id=&quot;NGNp&quot;&gt;Сейчас появляется всё больше нейросетей, каждая из которых старается превзойти конкурентов в разных задачах. Погнали разберём, в чём сильные стороны каждой из них.&lt;/p&gt;
  &lt;p id=&quot;zWaG&quot;&gt;&lt;strong&gt;&lt;a href=&quot;https://chatgpt.com/&quot; target=&quot;_blank&quot;&gt;ChatGPT&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;figure id=&quot;9UON&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/cd/0b/cd0be9cb-c71e-414e-a282-0dfbf35b08b8.png&quot; width=&quot;1028&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;MkJu&quot;&gt;База, подходит для самых разных задач. Если тебе не нужно что-то узконаправленное, это идеальный выбор. Он хорошо справляется с генерацией текста, кодом, аналитикой и многими другими задачами.&lt;/p&gt;
  &lt;p id=&quot;LpKd&quot;&gt;Главный плюс – &lt;strong&gt;память&lt;/strong&gt;, чего нет у большинства других моделей. Это позволяет ему запоминать детали проекта и не упускать важную информацию в долгих обсуждениях.&lt;/p&gt;
  &lt;p id=&quot;s4H6&quot;&gt;&lt;strong&gt;&lt;a href=&quot;https://chat.deepseek.com/&quot; target=&quot;_blank&quot;&gt;DeepSeek&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;figure id=&quot;Jwrk&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/01/e4/01e4f10c-3fbc-44cb-b9df-d9ac46f655b9.png&quot; width=&quot;1071&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;o35j&quot;&gt;Ранее считался скрытым &amp;quot;гемчиком&amp;quot;, особенно до того, как ChatGPT открыл доступ к своей продвинутой модели o3-mini и o3-mini-high. Так как у него была доступна фича &amp;quot;думанья&amp;quot; абсолютно бесплатно. Сейчас же для обычного общения в браузере он не будет чем-то выделяться.&lt;/p&gt;
  &lt;p id=&quot;wY5M&quot;&gt;Из минусов можно отметить &lt;strong&gt;жёсткую цензуру&lt;/strong&gt;, так как проект был разработан в Китае.&lt;/p&gt;
  &lt;p id=&quot;YVQR&quot;&gt;Однако есть и важное преимущество – &lt;strong&gt;дешёвые токены&lt;/strong&gt; при использовании через API, что делает его хорошим выбором для автоматизированных решений и массовых задач.&lt;/p&gt;
  &lt;p id=&quot;eZOn&quot;&gt;Если же ты всё еще хочешь использовать DeepSeek, то тебе полагается +100 социальный кредит, миска риса и кошко девочка. Партия гордится твой выбор! 🇨🇳&lt;/p&gt;
  &lt;p id=&quot;qdxf&quot;&gt;&lt;strong&gt;&lt;a href=&quot;https://grok.com/&quot; target=&quot;_blank&quot;&gt;Grok&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;figure id=&quot;J94K&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/66/24/6624b31a-8bec-4c62-89bf-3e8adf1dfa63.png&quot; width=&quot;911&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;lyUP&quot;&gt;Настоящая &lt;strong&gt;имба для кода&lt;/strong&gt; – обходит большинство моделей в решении задач по программированию, а также крипты из-за его возможности читать X (ex-Twitter). Сильно выигрывает в понимании алгоритмов и выдаёт качественные решения. Однако его &amp;quot;думанье&amp;quot; может хромать и выдавать ответ хуже, чем при обычной генерации текста. Хотя, возможно, это только у нас такое.&lt;/p&gt;
  &lt;p id=&quot;Zvtd&quot;&gt;&lt;strong&gt;&lt;a href=&quot;https://claude.ai/&quot; target=&quot;_blank&quot;&gt;Claude&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;figure id=&quot;M5nO&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/8f/bf/8fbff8a8-7aca-4664-866a-1243642ad50c.png&quot; width=&quot;888&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;9rLt&quot;&gt;Тоже хорош для кода, но отличается &lt;strong&gt;креативным подходом&lt;/strong&gt; к задачам. В отличие от ChatGPT, его решения иногда оказываются не просто рабочими, а неожиданно полезными. Подходит для ситуаций, когда нужен нестандартный взгляд на проблему.&lt;/p&gt;
  &lt;h2 id=&quot;9Zyq&quot;&gt;Заключение&lt;/h2&gt;
  &lt;p id=&quot;UFNa&quot;&gt;В общем, всё упирается в то, как ты взаимодействуешь с нейронкой. Чёткие задачи, дополнительные детали и контекст — и ChatGPT (или любой другой AI) будет разрывать в нужном тебе направлении. Запиши свои мысли, эксперименты и инсайты, чтобы потом работать с ними уже на полном автомате. &lt;/p&gt;
  &lt;p id=&quot;vfuV&quot;&gt;Если есть замечания по формату статьи или нехватка какой-то информации, то дай знать в комментах.&lt;/p&gt;

</content></entry><entry><id>aiostudy:WCvsyuyzxu0</id><link rel="alternate" type="text/html" href="https://teletype.in/@aiostudy/WCvsyuyzxu0?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=aiostudy"></link><title>Как наш ученик заработал $50,000 на тестнете Berachain </title><published>2025-02-10T11:39:43.384Z</published><updated>2025-02-10T15:33:30.024Z</updated><summary type="html">@smeshny пришёл на курс уже с базовыми навыками программирования. До этого он покупал софт у Askaer для ретродропов и пытался кастомизировать модули под себя. Однако быстро осознал, что без более глубоких знаний в web3 и структуре софта не получится масштабировать проекты.</summary><content type="html">
  &lt;h2 id=&quot;HOwG&quot;&gt;Кейс, который случился прямо вот только что. И еще раз доказывает – на любом рынке можно зарабатывать.&lt;/h2&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;xxnc&quot;&gt;@smeshny пришёл на курс уже с базовыми навыками программирования. До этого он покупал софт у Askaer для ретродропов и пытался кастомизировать модули под себя. Однако быстро осознал, что без более глубоких знаний в web3 и структуре софта не получится масштабировать проекты.&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;blockquote id=&quot;enuP&quot;&gt;&lt;em&gt;– &amp;quot;Я уже экспериментировал с софтами от Askaer — покупал их для ретродропов, пытался переделывать модули под себя... Но всегда горело желание масштабировать проекты, а знаний мне явно не хватало.&amp;quot;&lt;/em&gt;&lt;/blockquote&gt;
  &lt;/section&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;SvLZ&quot;&gt;@smeshny сфокусировался на &lt;strong&gt;тестнете Berachain&lt;/strong&gt; и постоянно натыкался на кучу вопросов. Когда в очередной раз он закидал Askaer запросами по кастомизации, тот предложил: &lt;strong&gt;«Иди учись, раз у тебя столько идей»&lt;/strong&gt; Так @smeshny стал одним из самых вовлечённых наших студентов.&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;blockquote id=&quot;tB1i&quot;&gt;&lt;em&gt;«Меня зацепил Berachain. Я бесконечно спрашивал, как подправить софт под него, и Askaer сказал: ‘Чувак, иди на обуч, там всё подробно’. Видимо, столько вопросов ещё никто ему не задавал ))»&lt;/em&gt;&lt;/blockquote&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(55,  86%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;blockquote id=&quot;3PYj&quot;&gt;&lt;em&gt;&amp;quot;Круто) А что тебе зашло больше всего в нашем курсе?&amp;quot;&lt;/em&gt;&lt;/blockquote&gt;
  &lt;/section&gt;
  &lt;section style=&quot;background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;blockquote id=&quot;pgM6&quot;&gt;&lt;em&gt;&amp;quot;Особенно запомнилась тема №10. Там я получил &lt;strong&gt;знания, которых не найти в открытом доступе,&lt;/strong&gt; и понял, как именно архитектура софтов помогает масштабировать проекты. &lt;br /&gt;&lt;br /&gt;И еще — &lt;strong&gt;хакатон был просто зарядом энергии!&lt;/strong&gt; Участвовал не ради денежного приза, а чтобы почувствовать атмосферу соревнования и драйв команды.&amp;quot;&lt;/em&gt;&lt;/blockquote&gt;
  &lt;/section&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;5Le2&quot;&gt;При работе с Berachain у @smeshny возникла проблема: на сайт уходили некорректные байты, и он не мог их расшифровать. &lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;blockquote id=&quot;niWC&quot;&gt;&lt;em&gt;&amp;quot;Чтобы проверить гипотезу, я обратился к &lt;strong&gt;куратору Олегу&lt;/strong&gt; и отправил ему 1111 $BERA на тестовый кошелёк. И вот чудо — за пару часов он провёл 7 транзакций, исправил проблему и вернул остаток! Итог: Олег получил дроп в 70 BERA (примерно $1000 по хаях)!&lt;br /&gt;&lt;br /&gt;Кроме того, почти сразу после этого я написал софт для &lt;strong&gt;автоматического получения токенов с крана в тестнете Bera&lt;/strong&gt; и поделился им в нашей группе. Практически все участники канала &lt;strong&gt;начали пользоваться моим софтом&lt;/strong&gt; — для меня это было интуитивно понятно, ведь я просто повторил аналогичный кейс, разобранный на курсе.&amp;quot;&lt;/em&gt;&lt;/blockquote&gt;
  &lt;/section&gt;
  &lt;p id=&quot;x628&quot;&gt;Как итог, у @smeshny было целых 1220 кошельков — 1000 он создавал для тестирования, а оставшиеся использовал для основных операций. &lt;/p&gt;
  &lt;p id=&quot;Qx28&quot;&gt;&lt;strong&gt;Результат превзошёл все ожидания: &lt;/strong&gt;на 220 кошельках оказалось по 12–25 токенов, а на основном — целых 1200 токенов. Мульткол позволил ему заклеймить дроп всего за час. &lt;/p&gt;
  &lt;h3 id=&quot;EEpf&quot;&gt;&lt;strong&gt;При продаже токенов по цене от $8 до $12 за штуку он заработал около $50,000 на тестнете, не вложив ни копейки.&lt;/strong&gt;&lt;/h3&gt;
  &lt;hr /&gt;
  &lt;h2 id=&quot;osYH&quot;&gt;Что дальше?&lt;/h2&gt;
  &lt;p id=&quot;3NbP&quot;&gt;Теперь @smeshny рассматривает более масштабные проекты. Он упоминает тестнет Hyperchain, хотя там «конченый эксплорер» и отрабатывают его единицы, — значит, есть поле для новых возможностей. Основной фокус остаётся на поиске проектов, где он сможет развиваться и применять свои навыки.&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;blockquote id=&quot;a8kj&quot;&gt;&lt;em&gt;«Самое главное - четко понимать, чего ты хочешь. Деньги - это не цель, а лишь инструмент. Я понял это ещё 5 лет назад. Деньги сами по себе не имеют особой ценности, если их преследовать ради денег. &lt;br /&gt;&lt;br /&gt;Даже $50,000, которые я заработал на тестнете, для меня — не конечный результат. &lt;br /&gt;&lt;br /&gt;Настоящая ценность - в навыках и опыте, которые я получил, в удовольствии от работы над проектом и постоянном совершенствовании своего софта.»&lt;/em&gt;&lt;/blockquote&gt;
  &lt;/section&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;BKvm&quot;&gt;Мы на самом деле гордимся, что у нас есть такие сильные ученики и они создают такие сильные кейсы. &lt;/p&gt;
  &lt;p id=&quot;dJSR&quot;&gt;Но при этом, если ты читаешь эту статью, а сам никогда не кодил и переживаешь, что у тебя не получится – не парься! &lt;/p&gt;
  &lt;p id=&quot;iTT2&quot;&gt;На нашем флагманском курсе WEB3 Python Разработчик всё начинается &lt;strong&gt;с нуля&lt;/strong&gt; и идёт &lt;strong&gt;пошагово&lt;/strong&gt;. Мы проведём тебя за руку, чтобы ты освоил web3-разработку и смог повторять (а то и превосходить) такие результаты. Всё, что нужно, — желание учиться и действовать.&lt;/p&gt;
  &lt;section style=&quot;background-color:hsl(hsl(55,  86%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;yqse&quot;&gt;Готов ли ты сделать первый шаг? &lt;strong&gt;Пиши в нашу службу заботы &lt;a href=&quot;http://t.me/aio_supp&quot; target=&quot;_blank&quot;&gt;@aio_supp &lt;/a&gt;&lt;/strong&gt;– мы ответим на все твои вопросы, проконсультируем и покажем, как сейчас вообще можно зарабатывать на крипто-рынке&lt;/p&gt;
  &lt;/section&gt;

</content></entry><entry><id>aiostudy:EkBIIDarsYs</id><link rel="alternate" type="text/html" href="https://teletype.in/@aiostudy/EkBIIDarsYs?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=aiostudy"></link><title>Гайд на Chrome профиля</title><published>2025-02-09T14:29:32.975Z</published><updated>2025-02-10T09:07:11.294Z</updated><summary type="html">Привет! В этом гайде мы рассмотрим как из Chrome профилей сделать антидетект браузер. Сделаем мы это буквально за два расширения и немножко покопавшись в настройках браузера для фулл сейфти ворка.</summary><content type="html">
  &lt;p id=&quot;Ru5A&quot;&gt;Привет! В этом гайде мы рассмотрим как из Chrome профилей сделать антидетект браузер. Сделаем мы это буквально за два расширения и немножко покопавшись в настройках браузера для фулл сейфти ворка.&lt;/p&gt;
  &lt;h2 id=&quot;Kcjb&quot;&gt;Оглавление&lt;/h2&gt;
  &lt;p id=&quot;ncm1&quot;&gt;&lt;a href=&quot;#0WSy&quot;&gt;Создание профиля&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;scCY&quot;&gt;&lt;a href=&quot;#m2va&quot;&gt;Настройка профиля&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;A5Ra&quot;&gt;&lt;a href=&quot;#rYPt&quot;&gt;Расширения&lt;/a&gt;&lt;/p&gt;
  &lt;h2 id=&quot;0WSy&quot;&gt;Создание профиля&lt;/h2&gt;
  &lt;p id=&quot;4Pnu&quot;&gt;&lt;strong&gt;Открываем хром и создаем профиль&lt;/strong&gt;&lt;/p&gt;
  &lt;figure id=&quot;CEQ8&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/03/6b/036b426b-174e-4588-ba3b-92e104a1c67f.png&quot; width=&quot;1366&quot; /&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;1JzJ&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/9f/1f/9f1feff1-092c-4767-ba3e-823f9f99fbc5.png&quot; width=&quot;526&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Ucu2&quot;&gt;&lt;strong&gt;Кастомизируем профиль&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;nc1x&quot;&gt;Переходим по ссылке: &lt;code&gt;chrome://settings/manageProfile&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;xFAR&quot;&gt;Здесь мы можем закастомить наш профиль, указав ему: нейм, цвет темы и аву.&lt;/p&gt;
  &lt;figure id=&quot;sd4A&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/12/37/1237fb1f-8cba-49c8-a234-9bf07358eca7.png&quot; width=&quot;672&quot; /&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;xSkb&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/f8/c6/f8c6a9ab-1523-49fa-a928-a9c836ec4244.png&quot; width=&quot;668&quot; /&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;RRVm&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/8b/4a/8b4a0452-5264-466f-828d-95e25817f397.png&quot; width=&quot;672&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;p4nE&quot;&gt;А еще можем добавить ярлык на рабочий стол, чтобы было удобней открывать профиль. После того как ты активируешь эту опцию, то на рабочем столе сразу же появится ярлык, ты его можешь переместить куда тебе будет удобней.&lt;/p&gt;
  &lt;figure id=&quot;6APo&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/82/e4/82e49760-68d9-45da-8de0-49cd6f62bcde.png&quot; width=&quot;675&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;m2va&quot;&gt;Настройка профиля&lt;/h2&gt;
  &lt;h3 id=&quot;72yB&quot;&gt;Синхронизация&lt;/h3&gt;
  &lt;p id=&quot;VgYA&quot;&gt;Далее проходимся по настройкам. Их придется выставлять на каждый из профилей отдельно, так как у хром нет функции синхронизации настроек, тоже самое и с расширениями.&lt;/p&gt;
  &lt;p id=&quot;MbjL&quot;&gt;Переходим на: &lt;code&gt;chrome://settings/syncSetup&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;7jVK&quot;&gt;Там отключаем вот этот пункт (он должен быть первым в списке). Это нужно чтобы у нас профиль не синхронизировался с гугл аккаунтом, на который ты будешь заходишь.&lt;/p&gt;
  &lt;figure id=&quot;q2tB&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e3/97/e397af5d-4f68-4105-a07b-330e9611ba9d.png&quot; width=&quot;617&quot; /&gt;
  &lt;/figure&gt;
  &lt;h3 id=&quot;O9uD&quot;&gt;Сохранение данных&lt;/h3&gt;
  &lt;p id=&quot;fU5g&quot;&gt;Переходим по очереди на каждую из ссылок: &lt;/p&gt;
  &lt;p id=&quot;ChfN&quot;&gt;&lt;code&gt;chrome://settings/autofill&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;REX6&quot;&gt;&lt;code&gt;chrome://password-manager/settings&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;HFA2&quot;&gt;Отключайте всё, что только можно — нам не нужно, чтобы какие-либо данные сохранялись. Вдруг у вас есть вирусняк, который может их украсть. &lt;/p&gt;
  &lt;p id=&quot;NoyN&quot;&gt;А если нужно хранить пароли, то лучше делать это в менеджере паролей, например &lt;a href=&quot;https://keepassxc.org/&quot; target=&quot;_blank&quot;&gt;KeePassXC&lt;/a&gt; — он хранит всё локально на устройстве в зашифрованном виде и ничего никуда не отправляет.&lt;/p&gt;
  &lt;figure id=&quot;IjGt&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/c2/9b/c29b62bd-6c95-4023-9c81-48d06413c4e0.png&quot; width=&quot;679&quot; /&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;da74&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/2b/2a/2b2a247c-77aa-46ed-8fa0-10e46c522d23.png&quot; width=&quot;701&quot; /&gt;
  &lt;/figure&gt;
  &lt;h3 id=&quot;ygZO&quot;&gt;Приватность&lt;/h3&gt;
  &lt;p id=&quot;tUcN&quot;&gt;Переходим по всем вкладкам настроек и отключаем всё, что может угрожать вашей приватности. Включаем такие опции, как «Использовать только HTTPS», «Отправлять запрос &amp;quot;Do Not Track&amp;quot;» и другие подобные настройки.&lt;/p&gt;
  &lt;figure id=&quot;QhzL&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/4a/66/4a66ede4-5f03-437e-8186-f16670b1a484.png&quot; width=&quot;708&quot; /&gt;
  &lt;/figure&gt;
  &lt;h3 id=&quot;N98r&quot;&gt;Startup&lt;/h3&gt;
  &lt;p id=&quot;2cSn&quot;&gt;Идем сюда: &lt;code&gt;chrome://settings/onStartup&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;DNhv&quot;&gt;Настраивайте так, как вам удобно. Мы, например, выбрали вариант, при котором при открытии профиля восстанавливаются все вкладки, которые были открыты перед его закрытием.&lt;/p&gt;
  &lt;figure id=&quot;Yxdw&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/45/0b/450ba21c-de9e-47c4-8b19-d56497def792.png&quot; width=&quot;704&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;rYPt&quot;&gt;Расширения&lt;/h2&gt;
  &lt;p id=&quot;EYY3&quot;&gt;Переходим к расширениям, а начнем с самого главного.&lt;/p&gt;
  &lt;h3 id=&quot;54EH&quot;&gt;Trace&lt;/h3&gt;
  &lt;p id=&quot;E4gH&quot;&gt;&lt;a href=&quot;https://chromewebstore.google.com/detail/trace-online-tracking-pro/njkmjblmcfiobddjgebnoeldkjcplfjb&quot; target=&quot;_blank&quot;&gt;Скачать расширение&lt;/a&gt; из магазина Chrome&lt;/p&gt;
  &lt;figure id=&quot;hLex&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/13/b3/13b30bbc-a7ee-4213-af4e-3495c5e4605c.png&quot; width=&quot;630&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;gNWI&quot;&gt;Это ультимативное расширение которые подменяет все, что только можно. Благодаря нему ваш хром браузер становиться антидетект браузером.&lt;/p&gt;
  &lt;p id=&quot;Bnxg&quot;&gt;На странице расширения в магазине ты можешь посмотреть все, что умеет подменять это расширение (там рил огромный список).&lt;/p&gt;
  &lt;p id=&quot;BlYd&quot;&gt;В целом, дефолтный пресет уже хорош, но нам все еще нужно врубить пару настроек. Для этого откройте настройки расширения, перейдите в Advanced -&amp;gt; Protections и настройте их таким образом:&lt;/p&gt;
  &lt;p id=&quot;wYp4&quot;&gt;&lt;strong&gt;Вкладка Main Protections:&lt;/strong&gt;&lt;/p&gt;
  &lt;figure id=&quot;JBNN&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e4/84/e484619c-d78a-4488-b043-db5db1325dc4.png&quot; width=&quot;1049&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;KgZQ&quot;&gt;&lt;strong&gt;Вкладка Advanced Protections&lt;/strong&gt;&lt;/p&gt;
  &lt;figure id=&quot;IcPS&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/f7/89/f7890eb7-f0c5-4058-aa49-a1c56b187276.png&quot; width=&quot;1042&quot; /&gt;
  &lt;/figure&gt;
  &lt;h3 id=&quot;Jlr4&quot;&gt;SwitchyOmega&lt;/h3&gt;
  &lt;p id=&quot;8fFa&quot;&gt;&lt;a href=&quot;https://chromewebstore.google.com/detail/proxy-switchyomega/padekgcemlokbadohgkifijomclgjgif&quot; target=&quot;_blank&quot;&gt;Скачать расширение&lt;/a&gt; из магазина Chrome&lt;/p&gt;
  &lt;figure id=&quot;p9fH&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/a6/c4/a6c4e6ec-1dee-4558-a658-ad0bcfe5ebf9.png&quot; width=&quot;513&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;NPaW&quot;&gt;База — прокси всегда нужны для отработки проектов. Поэтому, мы будем использовать это расширения для работы с ними, можно и другое, но нам больше зашло оно.&lt;/p&gt;
  &lt;p id=&quot;bEB7&quot;&gt;Заходим в настройки расширения и слева выбираем proxy. Далее вставляешь данные от прокси. Логин и пароль можно указать нажав на замок.&lt;/p&gt;
  &lt;figure id=&quot;z0dF&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/7a/56/7a5650d7-25a3-4700-94e9-870f2569bb91.png&quot; width=&quot;863&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;EA5O&quot;&gt;Вот и всё! Мы буквально с помощью двух расширений добились функционала антидетект-браузера. Может быть, это не очень удобно с точки зрения синхронизации, зато ты можешь быть уверен в том, что твои данные в безопасности и никто не украдёт твой честно заработанный кэш.&lt;/p&gt;
  &lt;p id=&quot;EDvU&quot;&gt;🔗 Понравился гайд? Тогда сохраняй и делись статьей с корешами!&lt;/p&gt;
  &lt;p id=&quot;EbI7&quot;&gt;&lt;strong&gt;&lt;a href=&quot;https://t.me/aio_study&quot; target=&quot;_blank&quot;&gt;AIO Study&lt;/a&gt; | &lt;a href=&quot;https://aiostudy.com/?utm=study&quot; target=&quot;_blank&quot;&gt;Site&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</content></entry><entry><id>aiostudy:FysFcVaIV5v</id><link rel="alternate" type="text/html" href="https://teletype.in/@aiostudy/FysFcVaIV5v?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=aiostudy"></link><title>Разбор парсера Solana, EVM щитков</title><published>2025-01-27T11:10:11.882Z</published><updated>2025-01-27T18:11:53.541Z</updated><summary type="html">Вот и разбор нашего парсера щитков! Когда мы впервые рассказали о нем, мы и представить не могли, что он вызовет такой сильный отклик. Спасибо всем, кто проявил интерес к нашей работе ❤️</summary><content type="html">
  &lt;p id=&quot;r6EX&quot;&gt;Вот и разбор &lt;a href=&quot;https://t.me/aio_study/42&quot; target=&quot;_blank&quot;&gt;нашего парсера щитков!&lt;/a&gt; Когда мы впервые рассказали о нем, мы и представить не могли, что он вызовет такой сильный отклик. Спасибо всем, кто проявил интерес к нашей работе ❤️&lt;/p&gt;
  &lt;p id=&quot;Iod3&quot;&gt;Этот пост будет насыщен полезной информацией, так что приготовьтесь впитывать. В статье мы будем разбирать довольно сложные конструкции, которые мы постарались максимально просто и понятно объяснить. Однако, если какие-то моменты покажутся сложными, не переживай — ты всегда можешь обратиться к нам в комментариях или спросить ChatGPT за дополнительными объяснениями.&lt;/p&gt;
  &lt;h2 id=&quot;fQrI&quot;&gt;Что делает наш парсер?&lt;/h2&gt;
  &lt;p id=&quot;Z9HH&quot;&gt;Наш скрипт обрабатывает список никнеймов аккаунтов X (ex-Twitter) из файла &lt;code&gt;usernames.txt&lt;/code&gt;. Он последовательно проходит по каждому аккаунту, анализируя последние пять постов на наличие Solana или EVM контракта — проверяя как текст, так и изображения.&lt;/p&gt;
  &lt;p id=&quot;xdge&quot;&gt;После проверки поста скрипт сохраняет его последний ID, чтобы при следующем запуске продолжить с того места, где остановился, тем самым анализируя только новые твиты. Если в посте найден контракт, пользователь получает уведомление в Telegram через бота.&lt;/p&gt;
  &lt;p id=&quot;xQF8&quot;&gt;Когда все аккаунты обработаны, скрипт переходит в режим ожидания до следующего парсинга.&lt;/p&gt;
  &lt;h2 id=&quot;bHii&quot;&gt;Что ты должен уметь?&lt;/h2&gt;
  &lt;p id=&quot;V3Bo&quot;&gt;Как и говорили, мы написали статью, ориентированную на новичков. Все, что тебе нужно — базовые знания синтаксиса Python. А если ты хотя бы раз сталкивался с классами или слышал про ООП, то разбираться в материале будет еще проще, но это не обязательно.&lt;/p&gt;
  &lt;p id=&quot;Kv8z&quot;&gt;Также ознакомься с нашей &lt;a href=&quot;https://teletype.in/@aiostudy/OvPvQsVMhgY&quot; target=&quot;_blank&quot;&gt;первой статьей&lt;/a&gt;, в которой мы подробно объясняем, как установить Python, настроить VS Code и написать свой первый скрипт. В &lt;a href=&quot;https://teletype.in/@aiostudy/Pm_doUr5pnd&quot; target=&quot;_blank&quot;&gt;другой статье&lt;/a&gt; рассказывается, как создать скрипт для распределения баланса с OKX на кошельки, включая работу с API, HTTP, HMAC и другое.&lt;/p&gt;
  &lt;h2 id=&quot;xYEF&quot;&gt;Где посмотреть код скрипта?&lt;/h2&gt;
  &lt;p id=&quot;YkY0&quot;&gt;Весь исходный код парсера доступен на &lt;a href=&quot;https://github.com/AIOStudy/x_shit_parser&quot; target=&quot;_blank&quot;&gt;GitHub&lt;/a&gt;&lt;/p&gt;
  &lt;h2 id=&quot;1SuO&quot;&gt;Оглавление&lt;/h2&gt;
  &lt;p id=&quot;NqRp&quot;&gt;&lt;a href=&quot;#4ZpV&quot;&gt;1. Что такое классы&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;jGgh&quot;&gt;&lt;a href=&quot;#SS2D&quot;&gt;2. Смотрим на структуру скрипта&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;lsu6&quot;&gt;&lt;a href=&quot;#STbo&quot;&gt;3. Приступаем к разбору кода&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;Xgqu&quot;&gt;&lt;a href=&quot;#i2Sr&quot;&gt;4. Заключение&lt;/a&gt;&lt;/p&gt;
  &lt;h2 id=&quot;4ZpV&quot;&gt;Что такое классы&lt;/h2&gt;
  &lt;p id=&quot;uLo3&quot;&gt;Перед тем как начать разбор, мы должны разобраться с тем, что такое классы.&lt;/p&gt;
  &lt;p id=&quot;6NAn&quot;&gt;&lt;strong&gt;Классы&lt;/strong&gt; — это чертежи (шаблоны)для создания объектов. Они позволяют объединять данные (переменные) и функции (методы), работающие с этими данными, в одно целое.&lt;/p&gt;
  &lt;p id=&quot;A2zH&quot;&gt;Представь, что ты занимаешься разработкой игры, и тебе нужно моделировать персонажа. Персонаж может иметь различные характеристики, например, здоровье, силу и уровень. Он также может выполнять действия, например, атаковать врага или лечиться.&lt;/p&gt;
  &lt;p id=&quot;VPD6&quot;&gt;Ты можешь создать класс для описания такого персонажа. Например:&lt;/p&gt;
  &lt;pre id=&quot;UNIy&quot; data-lang=&quot;python&quot;&gt;class Character:
    def __init__(self, name, health, strength):
        self.name = name
        self.health = health
        self.strength = strength

    def attack(self, enemy):
        print(f&amp;quot;{self.name} атакует {enemy.name} с силой {self.strength}!&amp;quot;)
        enemy.health -= self.strength

    def heal(self):
        print(f&amp;quot;{self.name} лечит себя!&amp;quot;)
        self.health += 10&lt;/pre&gt;
  &lt;p id=&quot;ZFAj&quot;&gt;Здесь класс &lt;code&gt;Character&lt;/code&gt; описывает персонажа с его характеристиками и действиями. &lt;/p&gt;
  &lt;p id=&quot;cjS7&quot;&gt;Теперь погнали создадим объект этого персонажа и повзаимодействуем с ним:&lt;/p&gt;
  &lt;pre id=&quot;4VNU&quot; data-lang=&quot;python&quot;&gt;hero = Character(&amp;quot;Герой&amp;quot;, 100, 15)
villain = Character(&amp;quot;Злодей&amp;quot;, 80, 10)

hero.attack(villain)
villain.heal()&lt;/pre&gt;
  &lt;p id=&quot;bOmQ&quot;&gt;Мы создаем переменные &lt;code&gt;hero&lt;/code&gt; и &lt;code&gt;villain&lt;/code&gt;, каждая из которых является экземпляром класса &lt;code&gt;Character&lt;/code&gt;. При создании объекта передаем имя персонажа, его здоровье и силу. При вызове класса срабатывает его конструктор, который создает объект и возвращает его. Полученные объекты мы сохраняем в переменные и затем используем их для взаимодействия.&lt;/p&gt;
  &lt;p id=&quot;TnDZ&quot;&gt;Пока можешь не вдаваться в подробности кода, так как мы еще разберем это все при дальнейшем разборе парсера.&lt;/p&gt;
  &lt;h3 id=&quot;twEF&quot;&gt;Функции НЕ хуже классов&lt;/h3&gt;
  &lt;p id=&quot;adt7&quot;&gt;Теперь давай разберемся, почему функции не хуже классов — они просто применяются в разных ситуациях.&lt;/p&gt;
  &lt;p id=&quot;UBHE&quot;&gt;Если бы тебе нужно было просто посчитать урон, который наносит персонаж врагу, то проще было бы использовать функцию, например:&lt;/p&gt;
  &lt;pre id=&quot;IABy&quot; data-lang=&quot;python&quot;&gt;def calculate_damage(attack, defense):
    return attack - defense&lt;/pre&gt;
  &lt;p id=&quot;xSgM&quot;&gt;Зачем создавать сложный класс, если у тебя есть простая задача, которая не требует хранения состояния объектов и взаимодействия между ними?&lt;/p&gt;
  &lt;h2 id=&quot;SS2D&quot;&gt;Смотрим на структуру скрипта&lt;/h2&gt;
  &lt;p id=&quot;aYeL&quot;&gt;Начнем наш разбор с структуры скрипта. Это важно, так как нужно обеспечить не только функциональность, но и грамотно организовать структуру проекта. Это помогает поддерживать код и упрощает его расширение. &lt;/p&gt;
  &lt;p id=&quot;xD4u&quot;&gt;Поэтому далее мы объясним, за что отвечает каждый файл и почему проект организован именно таким образом.&lt;/p&gt;
  &lt;p id=&quot;3CZv&quot;&gt;&lt;strong&gt;Файлы:&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;X7vz&quot;&gt;&lt;strong&gt;&lt;code&gt;main.py&lt;/code&gt;&lt;/strong&gt;: Главный исполняемый файл проекта. Именно с него начинается выполнение софта. В этом файле происходит инициализация необходимых компонентов и запуск основных процессов парсинга.&lt;/p&gt;
  &lt;p id=&quot;mrw7&quot;&gt;&lt;strong&gt;&lt;code&gt;settings.py&lt;/code&gt;&lt;/strong&gt;: Файл конфигурации, содержащий настройки проекта. Здесь определены параметры, которые можно легко изменить без необходимости редактирования кода.&lt;/p&gt;
  &lt;p id=&quot;f2RM&quot;&gt;&lt;strong&gt;&lt;code&gt;utils.py&lt;/code&gt;&lt;/strong&gt;: Файл с вспомогательными функциями и утилитами, которые используются в разных частях проекта.&lt;/p&gt;
  &lt;p id=&quot;UN9n&quot;&gt;&lt;strong&gt;&lt;code&gt;requirements.txt&lt;/code&gt;&lt;/strong&gt;: Список зависимостей проекта. В этом файле перечислены все внешние библиотеки и модули, которые необходимы для корректной работы скрипта.&lt;/p&gt;
  &lt;p id=&quot;yRnP&quot;&gt;&lt;strong&gt;&lt;code&gt;x_usernames.txt&lt;/code&gt;&lt;/strong&gt;: Текстовый файл, содержащий список имен пользователей X.&lt;/p&gt;
  &lt;p id=&quot;ggKJ&quot;&gt;&lt;strong&gt;&lt;code&gt;modules&lt;/code&gt;&lt;/strong&gt;: Папка, предназначенная для хранения дополнительных модулей. Разделение кода на модули способствует его повторному использованию и облегчает поддержку.&lt;/p&gt;
  &lt;p id=&quot;7gIV&quot;&gt;&lt;code&gt;modules/parser.py&lt;/code&gt;: Обрабатывает твиты полученные из модуля &lt;code&gt;x.py&lt;/code&gt;, извлекает из них контрактные адреса (из текста или изображений), используя &lt;code&gt;utils.py&lt;/code&gt; и отправляет уведомления пользователю через &lt;code&gt;telegram.py&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;8nOt&quot;&gt;&lt;code&gt;modules/telegram.py&lt;/code&gt;: Отправляет сообщения в Telegram-чат, используя API Telegram.&lt;/p&gt;
  &lt;p id=&quot;XOk7&quot;&gt;&lt;code&gt;modules/tweet_id_storage.py&lt;/code&gt;: Отвечает за сохранение и извлечение идентификаторов последнего обработанного твита для каждого пользователя в JSON формате.&lt;/p&gt;
  &lt;p id=&quot;uBGJ&quot;&gt;&lt;code&gt;modules/x.py&lt;/code&gt;: Модуль для взаимодействия с API X, обрабатывая запросы для получения данных о пользователях и их твитах.&lt;/p&gt;
  &lt;p id=&quot;fA6x&quot;&gt;&lt;strong&gt;Почему так:&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;CJnw&quot;&gt;Подобная структура обеспечивает модульность, удобство настройки и поддержку кода. Логика разделена на запуск, конфигурацию, парсинг, взаимодействие с API, хранение данных и отправку уведомлений, что упрощает доработку и масштабирование.&lt;/p&gt;
  &lt;p id=&quot;QNaa&quot;&gt;Если бы все было в одном файле, то ты бы запарился его поддерживать и масштабировать. Когда скрипт не большой, то это допустимо, но в нашем же случае — нет.&lt;/p&gt;
  &lt;h2 id=&quot;STbo&quot;&gt;Приступаем к разбору кода&lt;/h2&gt;
  &lt;p id=&quot;vHwy&quot;&gt;Ну что, теперь наберись терпения, впереди тебя ждет разбор каждого файла и каждой строчки кода, так что ты точно во всем разберешься.&lt;/p&gt;
  &lt;h3 id=&quot;Ruyi&quot;&gt;settings.py&lt;/h3&gt;
  &lt;p id=&quot;CGWP&quot;&gt;Начнем с чего-то простого, например, с конфигурационного файла.&lt;/p&gt;
  &lt;p id=&quot;1cKT&quot;&gt;Этот файл содержит настройки для работы парсера. В нем определены параметры прокси (&lt;code&gt;PROXY&lt;/code&gt;), поведение парсинга (&lt;code&gt;MAX_RETRIES&lt;/code&gt;, &lt;code&gt;CHECK_RETWEETS&lt;/code&gt;, &lt;code&gt;PARSING_INTERVAL_MINUTES&lt;/code&gt;), а также доступ к API X (Twitter) через &lt;code&gt;BEARER_TOKEN&lt;/code&gt;. Кроме того, файл включает настройки для отправки уведомлений в Telegram (&lt;code&gt;TELEGRAM_BOT_TOKEN&lt;/code&gt;, &lt;code&gt;TELEGRAM_CHAT_ID&lt;/code&gt;).&lt;/p&gt;
  &lt;pre id=&quot;boha&quot; data-lang=&quot;python&quot;&gt;# Proxy
PROXY = (
    &amp;quot;scheme://username:password@host:port&amp;quot;  # оставь как есть, если прокси не нужен
)

# Parse settings
MAX_RETRIES = 3  # сколько раз повторять парсинг при ошибках
CHECK_RETWEETS = True  # проверять ли ретвиты на наличие контрактов (увеличивает количество запросов)
PARSING_INTERVAL_MINUTES = 60 # сколько минут ждать после прохода всех аккаунтов перед повторным парсингом

# X settings
BEARER_TOKEN = &amp;quot;your_bearer_token&amp;quot;

# Telegram settings
TELEGRAM_BOT_TOKEN = &amp;quot;your_bot_token&amp;quot;
TELEGRAM_CHAT_ID = &amp;quot;your_chat_id&amp;quot;&lt;/pre&gt;
  &lt;p id=&quot;AsSW&quot;&gt;&lt;strong&gt;Пояснение к коду:&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;xWfo&quot;&gt;Думаю, пояснения к коду здесь не понадобятся, поскольку он достаточно понятен даже для новичка. Единственное, стоит отметить, что настройки мы записали в верхнем регистре. В Python нет строгих констант, но существует соглашение — писать неизменяемые значения в верхнем регистре. Поскольку эти настройки не будут изменяться в ходе выполнения программы, они считаются константами, поэтому мы записываем их в верхнем регистре.&lt;/p&gt;
  &lt;h3 id=&quot;8tom&quot;&gt;main.py&lt;/h3&gt;
  &lt;p id=&quot;Q94c&quot;&gt;Этот файл содержит основной код для запуска парсинга. Он загружает список имен пользователей из файла &lt;code&gt;x_usernames.txt&lt;/code&gt; и периодически выполняет их обработку с помощью парсера (класс &lt;code&gt;XParser&lt;/code&gt;). После завершения парсинга всех аккаунтов скрипт делает паузу на заданное время, а затем снова выполняет парсинг аккаунтов.&lt;/p&gt;
  &lt;pre id=&quot;wOAb&quot; data-lang=&quot;python&quot;&gt;from time import sleep

from modules.parser import XParser
from settings import PARSING_INTERVAL_MINUTES


def main() -&amp;gt; None:
    parser = XParser()

    with open(&amp;quot;x_usernames.txt&amp;quot;, &amp;quot;r&amp;quot;) as file:
        usernames = file.readlines()

    while True:
        for username in usernames:
            print(f&amp;quot;Начат парсинг аккаунта {username.strip()}&amp;quot;)
            parser.parse_account(username.strip())
            print(f&amp;quot;Завершен парсинг аккаунта {username.strip()}&amp;quot;)

        print(
            f&amp;quot;Парсинг завершен. Ждем {PARSING_INTERVAL_MINUTES} минут до следующего парсинга...&amp;quot;
        )
        sleep(PARSING_INTERVAL_MINUTES * 60)


if __name__ == &amp;quot;__main__&amp;quot;:
    main()&lt;/pre&gt;
  &lt;p id=&quot;PIxc&quot;&gt;&lt;strong&gt;Пояснение к коду:&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;JCAt&quot;&gt;&lt;strong&gt;1. Импорты&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;Cdio&quot; data-lang=&quot;python&quot;&gt;from time import sleep
from modules.parser import XParser
from settings import PARSING_INTERVAL_MINUTES

parser = XParser()&lt;/pre&gt;
  &lt;ul id=&quot;NCix&quot;&gt;
    &lt;li id=&quot;HeN0&quot;&gt;&lt;code&gt;sleep&lt;/code&gt; — встроенная функция, приостанавливающая выполнение программы (используется для задержки между циклами).&lt;/li&gt;
    &lt;li id=&quot;q3WX&quot;&gt;&lt;code&gt;XParser&lt;/code&gt; — класс для парсинга аккаунтов (код находится в &lt;code&gt;modules/parser.py&lt;/code&gt;).&lt;/li&gt;
    &lt;li id=&quot;NFJF&quot;&gt;&lt;code&gt;PARSING_INTERVAL_MINUTES&lt;/code&gt; — настройка, определяющая интервал ожидания перед следующим запуском (берётся из &lt;code&gt;settings.py&lt;/code&gt;)&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;Ad5y&quot;&gt;&lt;strong&gt;2. Функция &lt;code&gt;main()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;aSKx&quot; data-lang=&quot;python&quot;&gt;def main() -&amp;gt; None:&lt;/pre&gt;
  &lt;p id=&quot;usMv&quot;&gt;Создаем функцию &lt;code&gt;main()&lt;/code&gt;, которая будет описывать основную логику работы программы.&lt;/p&gt;
  &lt;p id=&quot;AVQr&quot;&gt;Знак &lt;code&gt;-&amp;gt;&lt;/code&gt; и любой тип данных за ним (как в нашем примере &lt;code&gt;-&amp;gt; None&lt;/code&gt;) означает, что функция возвращает результат с типом &lt;code&gt;None&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;f8Zt&quot;&gt;&lt;strong&gt;Создание объекта парсера&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;tmKs&quot; data-lang=&quot;python&quot;&gt;parser = XParser()&lt;/pre&gt;
  &lt;p id=&quot;atqm&quot;&gt;Создаем объект parser, используя класс XParser, тот самый шаблон, по которому строится объект. Когда мы его вызываем, то у нас создается объект &lt;code&gt;XParser&lt;/code&gt; и записывается в переменную parser.&lt;/p&gt;
  &lt;p id=&quot;moeA&quot;&gt;Ты еще увидишь класс &lt;code&gt;XParser&lt;/code&gt; далее, когда будем разбирать модуль &lt;code&gt;parser.py&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;OyJc&quot;&gt;&lt;strong&gt;Чтение списка пользователей&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;eaUD&quot; data-lang=&quot;python&quot;&gt;with open(&amp;quot;x_usernames.txt&amp;quot;, &amp;quot;r&amp;quot;) as file:
    usernames = file.readlines()&lt;/pre&gt;
  &lt;p id=&quot;emKh&quot;&gt;Файл &lt;code&gt;x_usernames.txt&lt;/code&gt; открывается в режиме чтения (&lt;code&gt;&amp;quot;r&amp;quot;&lt;/code&gt;), а все строки загружаются в список &lt;code&gt;usernames&lt;/code&gt;. Использование &lt;code&gt;with open(...)&lt;/code&gt; автоматически закрывает файл после завершения работы с ним.&lt;/p&gt;
  &lt;p id=&quot;bb1L&quot;&gt;&lt;strong&gt;Бесконечный цикл&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;uQVu&quot; data-lang=&quot;python&quot;&gt;while True:&lt;/pre&gt;
  &lt;p id=&quot;wRUL&quot;&gt;Запускаем бесконечный цикл, который работает, пока скрипт не остановят вручную (&lt;code&gt;Ctrl + C&lt;/code&gt;) или не произойдет какое нибудь событие, которые заставит скрипт выйти из цикла. В нашем же случае, мы будем ждать пока пользователь сам не остановит скрипт.&lt;/p&gt;
  &lt;p id=&quot;0qqf&quot;&gt;&lt;strong&gt;Обработка каждого пользователя&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;G3aa&quot; data-lang=&quot;python&quot;&gt;for username in usernames:&lt;/pre&gt;
  &lt;p id=&quot;R3am&quot;&gt;Проходим по списку пользователей, считанных из файла.&lt;/p&gt;
  &lt;p id=&quot;2Koz&quot;&gt;&lt;strong&gt;Парсинг аккаунтов&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;hgDC&quot; data-lang=&quot;python&quot;&gt;print(f&amp;quot;Начат парсинг аккаунта {username.strip()}&amp;quot;)
parser.parse_account(username.strip())
print(f&amp;quot;Завершен парсинг аккаунта {username.strip()}&amp;quot;)&lt;/pre&gt;
  &lt;p id=&quot;9Qb7&quot;&gt;Метод &lt;code&gt;username.strip()&lt;/code&gt; удаляет лишние пробелы и символы &lt;code&gt;\n&lt;/code&gt;. Затем выводится сообщение о начале парсинга, после чего запускается метод &lt;code&gt;parse_account()&lt;/code&gt; для обработки аккаунта. По завершении парсинга отображается сообщение об окончании процесса.&lt;/p&gt;
  &lt;p id=&quot;n9Xw&quot;&gt;&lt;strong&gt;Ожидание перед следующим циклом&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;4Fci&quot; data-lang=&quot;python&quot;&gt;print(f&amp;quot;Парсинг завершен. Ждем {PARSING_INTERVAL_MINUTES} минут до следующего парсинга...&amp;quot;)
sleep(PARSING_INTERVAL_MINUTES * 60)&lt;/pre&gt;
  &lt;p id=&quot;Kbnv&quot;&gt;Выводится сообщение о завершении итерации, затем программа делает паузу (&lt;code&gt;sleep&lt;/code&gt;) на указанное количество минут. Мы умножаем &lt;code&gt;PARSING_INTERVAL_MINUTES&lt;/code&gt; на 60, так как &lt;code&gt;sleep()&lt;/code&gt; ожидает время в секундах&lt;/p&gt;
  &lt;p id=&quot;1pHU&quot;&gt;&lt;strong&gt;3. Запуск программы&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;mOAi&quot; data-lang=&quot;python&quot;&gt;if __name__ == &amp;quot;__main__&amp;quot;:
    main()&lt;/pre&gt;
  &lt;p id=&quot;GJqL&quot;&gt;Этот блок гарантирует, что &lt;code&gt;main()&lt;/code&gt; запустится только если скрипт выполняется напрямую (&lt;code&gt;python main.py&lt;/code&gt;), а не импортируется как модуль (&lt;code&gt;import main&lt;/code&gt;).&lt;/p&gt;
  &lt;h3 id=&quot;eOSG&quot;&gt;utils.py&lt;/h3&gt;
  &lt;p id=&quot;dTJL&quot;&gt;Здесь, как мы упомянали ранее, хранятся вспомогательные функции. Мы их будем использовать в модуле &lt;code&gt;parser.py&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;75ti&quot;&gt;В частности, здесь лежат функции по поиску адресов в тексте и картинке:&lt;/p&gt;
  &lt;p id=&quot;LEIq&quot;&gt;&lt;strong&gt;Поиск адреса контракта:&lt;/strong&gt;&lt;br /&gt;Функция анализирует текст, чтобы найти адреса контрактов Ethereum или Solana. Если такой адрес находится, он возвращается, иначе функция сообщает, что адресов нет.&lt;/p&gt;
  &lt;p id=&quot;0sDP&quot;&gt;&lt;strong&gt;Извлечение текста из изображения:&lt;/strong&gt;&lt;br /&gt;Функция загружает изображение по указанной ссылке, распознает текст на этом изображении с помощью технологии OCR и возвращает его в виде строки.&lt;/p&gt;
  &lt;pre id=&quot;odbM&quot; data-lang=&quot;python&quot;&gt;import re
from io import BytesIO

import pytesseract
import requests
from PIL import Image


def get_contract_address(text: str = &amp;quot;&amp;quot;) -&amp;gt; str | None:
    evm_pattern = r&amp;quot;0x[a-fA-F0-9]{40}&amp;quot;
    solana_pattern = r&amp;quot;[1-9A-HJ-NP-Za-km-z]{32,44}&amp;quot;

    evm_match = re.search(evm_pattern, text, re.MULTILINE | re.IGNORECASE | re.DOTALL)
    solana_match = re.search(
        solana_pattern, text, re.MULTILINE | re.IGNORECASE | re.DOTALL
    )

    if evm_match:
        return evm_match.group(0)
    elif solana_match:
        return solana_match.group(0)
    else:
        return None


def extract_text_from_image(image_url: str) -&amp;gt; str:
    with requests.request(&amp;quot;GET&amp;quot;, image_url) as response:
        img = Image.open(BytesIO(response.content))

    text = pytesseract.image_to_string(img)

    return text&lt;/pre&gt;
  &lt;p id=&quot;XjFB&quot;&gt;&lt;strong&gt;Пояснение к коду:&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;JMJR&quot;&gt;&lt;strong&gt;1. Импорты&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;eYbo&quot; data-lang=&quot;python&quot;&gt;import re
from io import BytesIO

import pytesseract
import requests
from PIL import Image&lt;/pre&gt;
  &lt;ul id=&quot;Kjfp&quot;&gt;
    &lt;li id=&quot;7eJI&quot;&gt;&lt;code&gt;re&lt;/code&gt; — модуль для работы с регулярными выражениями.&lt;/li&gt;
    &lt;li id=&quot;UavN&quot;&gt;&lt;code&gt;BytesIO&lt;/code&gt; — позволяет работать с бинарными данными в оперативной памяти, как с файловым объектом.&lt;/li&gt;
    &lt;li id=&quot;Wmik&quot;&gt;&lt;code&gt;pytesseract&lt;/code&gt; — библиотека для распознавания текста на изображениях с помощью Tesseract OCR.&lt;/li&gt;
    &lt;li id=&quot;40Hh&quot;&gt;&lt;code&gt;requests&lt;/code&gt; — библиотека для выполнения HTTP-запросов.&lt;/li&gt;
    &lt;li id=&quot;kwrH&quot;&gt;&lt;code&gt;PIL.Image&lt;/code&gt; — класс из библиотеки Pillow, используется для работы с изображениями.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;JvHS&quot;&gt;&lt;strong&gt;2. Функция &lt;code&gt;get_contract_address()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;hbE8&quot; data-lang=&quot;python&quot;&gt;def get_contract_address(text: str = &amp;quot;&amp;quot;) -&amp;gt; str | None:&lt;/pre&gt;
  &lt;p id=&quot;PZWn&quot;&gt;Эта функция ищет и извлекает из переданного текста адреса контрактов EVM и Solana.&lt;/p&gt;
  &lt;p id=&quot;ueTT&quot;&gt;&lt;strong&gt;Регулярные выражения для поиска&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;bh4a&quot;&gt;Регулярное выражение — это специальный шаблон для поиска текста в строках. Это своего рода &amp;quot;поиск по маске&amp;quot;, который может быть очень гибким. Например, регулярка может искать все числа в тексте или проверять, соответствует ли строка конкретному формату (например, email-адресу).&lt;/p&gt;
  &lt;p id=&quot;ugy1&quot;&gt;Если ты никогда не сталкивался с регулярными выражениями, то, во-первых, стоит немного изучить эту тему. Во-вторых, ты можешь воспользоваться ChatGPT, который поможет тебе составить нужный шаблон.&lt;/p&gt;
  &lt;p id=&quot;Od9C&quot;&gt;Вернемся к коду:&lt;/p&gt;
  &lt;pre id=&quot;cTM8&quot; data-lang=&quot;python&quot;&gt;evm_pattern = r&amp;quot;0x[a-fA-F0-9]{40}&amp;quot;
solana_pattern = r&amp;quot;[1-9A-HJ-NP-Za-km-z]{32,44}&amp;quot;&lt;/pre&gt;
  &lt;ul id=&quot;2mDM&quot;&gt;
    &lt;li id=&quot;BSoo&quot;&gt;&lt;code&gt;evm_pattern&lt;/code&gt; — шаблон для EVM-адресов (начинается с &lt;code&gt;0x&lt;/code&gt; и содержит 40 шестнадцатеричных символов).&lt;/li&gt;
    &lt;li id=&quot;thYC&quot;&gt;&lt;code&gt;solana_pattern&lt;/code&gt; — шаблон для Solana-адресов (от 32 до 44 символов, исключая некоторые буквы, чтобы избежать ошибок в идентификации).&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;fkyC&quot;&gt;&lt;strong&gt;Поиск адресов в тексте&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;teAi&quot; data-lang=&quot;python&quot;&gt;evm_match = re.search(evm_pattern, text, re.MULTILINE | re.IGNORECASE | re.DOTALL)
solana_match = re.search(
    solana_pattern, text, re.MULTILINE | re.IGNORECASE | re.DOTALL
)&lt;/pre&gt;
  &lt;p id=&quot;ORTN&quot;&gt;&lt;code&gt;re.search()&lt;/code&gt; ищет первое совпадение с регулярным выражением в строке.&lt;/p&gt;
  &lt;p id=&quot;rwvx&quot;&gt;Флаги &lt;code&gt;MULTILINE&lt;/code&gt;, &lt;code&gt;IGNORECASE&lt;/code&gt;, &lt;code&gt;DOTALL&lt;/code&gt; обеспечивают поиск по всему тексту без учёта регистра. Они объединяются с помощью &lt;code&gt;|&lt;/code&gt;, что позволяет применять сразу несколько флагов в одном вызове функции.&lt;/p&gt;
  &lt;p id=&quot;9sLA&quot;&gt;&lt;strong&gt;Возврат найденного адреса&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;KLKZ&quot; data-lang=&quot;python&quot;&gt;if evm_match:
    return evm_match.group(0)
elif solana_match:
    return solana_match.group(0)
else:
    return None&lt;/pre&gt;
  &lt;p id=&quot;SidX&quot;&gt;Мы проверяем, есть ли результат для каждого поиска по регулярному выражению. Если &lt;code&gt;evm_match&lt;/code&gt; содержит результат, то возвращаем первый найденный адрес. Если же нет, проверяем &lt;code&gt;solana_match&lt;/code&gt;. В случае, когда ни одно из поисков не дало результата, возвращаем &lt;code&gt;None&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;q2mi&quot;&gt;&lt;strong&gt;3. Функция &lt;code&gt;extract_text_from_image()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;GGpx&quot; data-lang=&quot;python&quot;&gt;def extract_text_from_image(image_url: str) -&amp;gt; str:&lt;/pre&gt;
  &lt;p id=&quot;pwfA&quot;&gt;Эта функция получает текст с изображения, загруженного по указанному URL. Этот URL мы получаем из твита при его обработке и принимаем в этой функции как аргумент.&lt;/p&gt;
  &lt;p id=&quot;GJxo&quot;&gt;&lt;strong&gt;Загрузка изображения&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;I3M5&quot; data-lang=&quot;python&quot;&gt;with requests.request(&amp;quot;GET&amp;quot;, image_url) as response:
    img = Image.open(BytesIO(response.content))&lt;/pre&gt;
  &lt;p id=&quot;m3bf&quot;&gt;Метод &lt;code&gt;requests.request(&amp;quot;GET&amp;quot;, image_url)&lt;/code&gt; выполняет HTTP-запрос для загрузки изображения. Затем &lt;code&gt;BytesIO(response.content)&lt;/code&gt; преобразует полученные бинарные данные в файловый объект. После этого &lt;code&gt;Image.open(...)&lt;/code&gt; открывает изображение с помощью библиотеки Pillow.&lt;/p&gt;
  &lt;p id=&quot;83BB&quot;&gt;&lt;strong&gt;Распознавание текста&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;dDtW&quot; data-lang=&quot;python&quot;&gt;text = pytesseract.image_to_string(img)&lt;/pre&gt;
  &lt;p id=&quot;iiSq&quot;&gt;Чтобы извлечь текст с изображения, нужно воспользоваться сторонней библиотекой, такой как pytesseract.&lt;/p&gt;
  &lt;p id=&quot;a9Wf&quot;&gt;Функция &lt;code&gt;pytesseract.image_to_string(img)&lt;/code&gt; использует Tesseract OCR для распознавания текста.&lt;/p&gt;
  &lt;p id=&quot;pVk1&quot;&gt;Tesseract OCR — это инструмент, который читает текст с изображений и преобразует его в текстовый формат.&lt;/p&gt;
  &lt;p id=&quot;2ExU&quot;&gt;&lt;strong&gt;Возврат результата&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;31nt&quot; data-lang=&quot;python&quot;&gt;return text&lt;/pre&gt;
  &lt;p id=&quot;pKNM&quot;&gt;Функция возвращает распознанный текст в виде строки.&lt;/p&gt;
  &lt;h3 id=&quot;G8h8&quot;&gt;modules/parser.py&lt;/h3&gt;
  &lt;p id=&quot;DsyC&quot;&gt;Модуль &lt;code&gt;parser.py&lt;/code&gt; использует другой модуль, &lt;code&gt;x.py&lt;/code&gt;, для взаимодействия с API платформы X (Twitter). Он использует методы этого модуля для получения информации о пользователе, его твитах и медиафайлах, а затем анализирует твиты на наличие контрактов в тексте или изображениях.&lt;/p&gt;
  &lt;pre id=&quot;AiUn&quot; data-lang=&quot;python&quot;&gt;from typing import List

from modules.telegram import send_message_to_user
from modules.tweet_id_storage import TweetIdStorage
from modules.x import XAPIHandler
from settings import CHECK_RETWEETS
from utils import extract_text_from_image, get_contract_address


class XParser:
    def __init__(self):
        self.x_api_handler = XAPIHandler()
        self.tweet_id_storage = TweetIdStorage()

    def parse_account(self, username: str) -&amp;gt; None:
        user_id = self.x_api_handler.fetch_user_id_by_username(username)
        fetched_tweets = self.x_api_handler.fetch_user_tweets(username, user_id)

        if not fetched_tweets.get(&amp;quot;data&amp;quot;):
            print(f&amp;quot;Нет новых твитов от {username}&amp;quot;)
            return

        for tweet in reversed(fetched_tweets[&amp;quot;data&amp;quot;]):
            if CHECK_RETWEETS and tweet.get(&amp;quot;referenced_tweets&amp;quot;):
                for ref_tweet in tweet[&amp;quot;referenced_tweets&amp;quot;]:
                    ref_tweet = self.x_api_handler.get_tweet_by_id(ref_tweet[&amp;quot;id&amp;quot;])
                    ref_tweet_data = ref_tweet.get(&amp;quot;data&amp;quot;, {})

                    media = ref_tweet.get(&amp;quot;includes&amp;quot;, {}).get(&amp;quot;media&amp;quot;, [])

                    image_urls = []
                    for media_item in media:
                        if media_item.get(&amp;quot;url&amp;quot;):
                            image_urls.append(media_item[&amp;quot;url&amp;quot;])

                    self._process_tweet(
                        username,
                        ref_tweet_data[&amp;quot;id&amp;quot;],
                        ref_tweet_data.get(&amp;quot;note_tweet&amp;quot;, {}).get(&amp;quot;text&amp;quot;)
                        or ref_tweet_data.get(&amp;quot;text&amp;quot;, &amp;quot;&amp;quot;),
                        image_urls,
                    )
            else:
                self.tweet_id_storage.save_last_tweet_id(username, tweet[&amp;quot;id&amp;quot;])

                media = fetched_tweets.get(&amp;quot;includes&amp;quot;, {}).get(&amp;quot;media&amp;quot;, [])
                media_keys = tweet.get(&amp;quot;attachments&amp;quot;, {}).get(&amp;quot;media_keys&amp;quot;, [])

                image_urls = []
                for media_item in media:
                    if media_item[&amp;quot;media_key&amp;quot;] in media_keys and media_item.get(&amp;quot;url&amp;quot;):
                        image_urls.append(media_item[&amp;quot;url&amp;quot;])

                self._process_tweet(
                    username,
                    tweet[&amp;quot;id&amp;quot;],
                    tweet.get(&amp;quot;note_tweet&amp;quot;, {}).get(&amp;quot;text&amp;quot;) or tweet.get(&amp;quot;text&amp;quot;, &amp;quot;&amp;quot;),
                    image_urls,
                )

    def _process_tweet(
        self,
        username: str,
        tweet_id: str = &amp;quot;&amp;quot;,
        tweet_text: str = &amp;quot;&amp;quot;,
        image_urls: List[str] = [],
    ) -&amp;gt; None:
        if contract := get_contract_address(tweet_text):
            self._notify_contract_found(contract, username, tweet_id, &amp;quot;text&amp;quot;)
            return

        for image_url in image_urls:
            image_text = extract_text_from_image(image_url)
            if contract := get_contract_address(image_text):
                self._notify_contract_found(contract, username, tweet_id, &amp;quot;image&amp;quot;)

    def _notify_contract_found(
        self, contract: str, username: str, tweet_id: str, source: str
    ) -&amp;gt; None:
        tweet_url = f&amp;quot;https://x.com/{username}/status/{tweet_id}&amp;quot;

        if source == &amp;quot;text&amp;quot;:
            message = f&amp;quot;Контракт найден в тексте твита: &amp;#x60;{contract}&amp;#x60;\n\n[Ссылка на твит]({tweet_url})&amp;quot;
        else:
            message = f&amp;quot;Контракт найден в изображении твита и может быть неправильным: &amp;#x60;{contract}&amp;#x60;\n\n[Ссылка на твит]({tweet_url})&amp;quot;

        send_message_to_user(message)&lt;/pre&gt;
  &lt;p id=&quot;QDFZ&quot;&gt;&lt;strong&gt;Пояснение к коду:&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;M4HJ&quot;&gt;&lt;strong&gt;1. Импорты&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;yeVK&quot; data-lang=&quot;python&quot;&gt;from typing import List

from modules.telegram import send_message_to_user
from modules.tweet_id_storage import TweetIdStorage
from modules.x import XAPIHandler
from settings import CHECK_RETWEETS
from utils import extract_text_from_image, get_contract_address&lt;/pre&gt;
  &lt;ul id=&quot;dqfg&quot;&gt;
    &lt;li id=&quot;f6YE&quot;&gt;&lt;code&gt;List&lt;/code&gt; из &lt;code&gt;typing&lt;/code&gt; — для аннотации типов данных.&lt;/li&gt;
    &lt;li id=&quot;em18&quot;&gt;&lt;code&gt;send_message_to_user&lt;/code&gt; — функция для отправки сообщений пользователям.&lt;/li&gt;
    &lt;li id=&quot;lpZH&quot;&gt;&lt;code&gt;TweetIdStorage&lt;/code&gt; — класс для хранения ID обработанных твитов.&lt;/li&gt;
    &lt;li id=&quot;T3wf&quot;&gt;&lt;code&gt;XAPIHandler&lt;/code&gt; — класс для работы с API X.&lt;/li&gt;
    &lt;li id=&quot;FP0t&quot;&gt;&lt;code&gt;CHECK_RETWEETS&lt;/code&gt; — настройка из &lt;code&gt;settings&lt;/code&gt;, указывающая, нужно ли проверять ретвиты.&lt;/li&gt;
    &lt;li id=&quot;PZB7&quot;&gt;&lt;code&gt;extract_text_from_image&lt;/code&gt; — функция для извлечения текста из изображений.&lt;/li&gt;
    &lt;li id=&quot;bQW0&quot;&gt;&lt;code&gt;get_contract_address&lt;/code&gt; — функция для поиска контрактных адресов в тексте.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;iKtG&quot;&gt;&lt;strong&gt;2. Класс &lt;code&gt;XParser&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;w3bN&quot; data-lang=&quot;python&quot;&gt;class XParser:&lt;/pre&gt;
  &lt;p id=&quot;YgqE&quot;&gt;Этот класс является шаблоном для создания объектов, отвечающих за парсинг твитов.&lt;/p&gt;
  &lt;p id=&quot;4gtz&quot;&gt;&lt;strong&gt;Инициализация класса&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;zqnn&quot; data-lang=&quot;python&quot;&gt;def __init__(self):
    self.x_api_handler = XAPIHandler()
    self.tweet_id_storage = TweetIdStorage()&lt;/pre&gt;
  &lt;p id=&quot;EOS2&quot;&gt;При создании объекта &lt;code&gt;XParser&lt;/code&gt; автоматически вызывается его конструктор &lt;code&gt;__init__()&lt;/code&gt;, который инициализирует необходимые компоненты:&lt;/p&gt;
  &lt;ul id=&quot;MvAC&quot;&gt;
    &lt;li id=&quot;l7Bt&quot;&gt;&lt;strong&gt;&lt;code&gt;self.x_api_handler = XAPIHandler()&lt;/code&gt;&lt;/strong&gt; — создаётся объект для работы с API X. Класс &lt;code&gt;XAPIHandler&lt;/code&gt; является основным для взаимодействия с этим API.&lt;/li&gt;
    &lt;li id=&quot;m4E7&quot;&gt;&lt;strong&gt;&lt;code&gt;self.tweet_id_storage = TweetIdStorage()&lt;/code&gt;&lt;/strong&gt; — создаётся объект для работы с &amp;quot;базой данных&amp;quot; (обычный JSON файл), в котором хранятся последние ID твитов для каждого аккаунта. С помощью этого объекта мы можем сохранять и читать последние ID твитов.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;olGS&quot;&gt;&lt;strong&gt;Немного про __init__ и атрибуты:&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;e4qo&quot;&gt;В методе &lt;code&gt;__init__()&lt;/code&gt; мы задаём атрибуты для объектов, используя префикс &lt;code&gt;self.&lt;/code&gt;, чтобы привязать их к конкретному экземпляру класса. Такие атрибуты являются уникальными для каждого экземпляра: изменение значения, например, &lt;code&gt;self.a&lt;/code&gt; в одном объекте, не повлияет на значение этого атрибута в другом объекте, даже если они принадлежат одному классу.&lt;/p&gt;
  &lt;p id=&quot;YogB&quot;&gt;Кроме того, существуют классовые атрибуты, которые являются общими для всех экземпляров класса. Ты сможешь увидеть их применение при разборе модуля &lt;code&gt;tweet_id_storage.py&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;JH0A&quot;&gt;&lt;strong&gt;3. Метод &lt;code&gt;parse_account()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;wSiB&quot; data-lang=&quot;python&quot;&gt;def parse_account(self, username: str) -&amp;gt; None:&lt;/pre&gt;
  &lt;p id=&quot;tSk1&quot;&gt;Этот метод получает и обрабатывает твиты пользователя.&lt;/p&gt;
  &lt;p id=&quot;oI5I&quot;&gt;&lt;strong&gt;Получение твитов&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;MWMP&quot; data-lang=&quot;python&quot;&gt;user_id = self.x_api_handler.fetch_user_id_by_username(username)
fetched_tweets = self.x_api_handler.fetch_user_tweets(username, user_id)&lt;/pre&gt;
  &lt;p id=&quot;HabQ&quot;&gt;Получаем &lt;code&gt;user_id&lt;/code&gt; по &lt;code&gt;username&lt;/code&gt;, затем загружаем список твитов пользователя. Для этого мы используем объект &lt;code&gt;x_api_handler&lt;/code&gt; класса &lt;code&gt;XAPIHandler&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;jl1o&quot;&gt;&lt;strong&gt;Проверка новых твитов&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;2e7j&quot; data-lang=&quot;python&quot;&gt;if not fetched_tweets.get(&amp;quot;data&amp;quot;):
    print(f&amp;quot;Нет новых твитов от {username}&amp;quot;)
    return&lt;/pre&gt;
  &lt;p id=&quot;0cUW&quot;&gt;Если новых твитов нет, программа сообщает об этом и выходит из функции.&lt;/p&gt;
  &lt;p id=&quot;Svla&quot;&gt;&lt;strong&gt;Проходимся по твитам&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;86HM&quot; data-lang=&quot;python&quot;&gt;for tweet in reversed(fetched_tweets[&amp;quot;data&amp;quot;]):&lt;/pre&gt;
  &lt;p id=&quot;6plE&quot;&gt;Проходим по списку твитов в обратном порядке (от старых к новым), чтобы обрабатывать их в хронологическом порядке.&lt;/p&gt;
  &lt;p id=&quot;KDVU&quot;&gt;&lt;strong&gt;Обработка ретвитов&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;yvvw&quot; data-lang=&quot;python&quot;&gt;if CHECK_RETWEETS and tweet.get(&amp;quot;referenced_tweets&amp;quot;):
    for ref_tweet in tweet[&amp;quot;referenced_tweets&amp;quot;]:
        ref_tweet = self.x_api_handler.get_tweet_by_id(ref_tweet[&amp;quot;id&amp;quot;])
        ref_tweet_data = ref_tweet.get(&amp;quot;data&amp;quot;, {})
                    
        media = ref_tweet.get(&amp;quot;includes&amp;quot;, {}).get(&amp;quot;media&amp;quot;, [])
        image_urls = []
        for media_item in media:
            if media_item.get(&amp;quot;url&amp;quot;):
                image_urls.append(media_item[&amp;quot;url&amp;quot;])&lt;/pre&gt;
  &lt;p id=&quot;Xq3s&quot;&gt;Если &lt;code&gt;CHECK_RETWEETS&lt;/code&gt; включен и твит является ретвитом, мы перебираем все ссылки на оригинальные твиты, получаем их ID и загружаем данные оригинального твита с помощью метода &lt;code&gt;get_tweet_by_id()&lt;/code&gt;. Затем мы извлекаем его текст и проверяем, содержит ли он медиафайлы. Если у оригинального твита есть вложенные изображения, мы формируем список ссылок на них и передаём в дальнейшую обработку. Таким образом, если твит является ретвитом, мы анализируем не только сам ретвит, но и его оригинальный источник.&lt;/p&gt;
  &lt;p id=&quot;D6cV&quot;&gt;Структуру ответа API мы знаем из &lt;a href=&quot;https://docs.x.com/x-api/posts/post-lookup-by-post-id&quot; target=&quot;_blank&quot;&gt;официальной документации X&lt;/a&gt;, что позволяет нам корректно обрабатывать данные, такие как &lt;code&gt;referenced_tweets&lt;/code&gt;, &lt;code&gt;media&lt;/code&gt;, &lt;code&gt;text&lt;/code&gt; и другие ключи в JSON-ответе.&lt;/p&gt;
  &lt;p id=&quot;2Ztp&quot;&gt;&lt;strong&gt;Обработка обычных твитов&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;NCsK&quot; data-lang=&quot;python&quot;&gt;else:
    self.tweet_id_storage.save_last_tweet_id(username, tweet[&amp;quot;id&amp;quot;])&lt;/pre&gt;
  &lt;p id=&quot;NHlD&quot;&gt;Если это не ретвит, сохраняем ID твита с помощью &lt;code&gt;TweetIdStorage&lt;/code&gt;. Этот класс позволяет нам записывать и читать последние обработанные &lt;code&gt;tweet_id&lt;/code&gt; из JSON-файла, который служит своеобразной базой данных. Это предотвращает повторную обработку уже разобранных твитов при последующих запусках.&lt;/p&gt;
  &lt;p id=&quot;jNlT&quot;&gt;&lt;strong&gt;Извлечение изображений&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;VZI2&quot; data-lang=&quot;python&quot;&gt;media = fetched_tweets.get(&amp;quot;includes&amp;quot;, {}).get(&amp;quot;media&amp;quot;, [])
media_keys = tweet.get(&amp;quot;attachments&amp;quot;, {}).get(&amp;quot;media_keys&amp;quot;, [])
image_urls = []
for media_item in media:
    if media_item[&amp;quot;media_key&amp;quot;] in media_keys and media_item.get(&amp;quot;url&amp;quot;):
        image_urls.append(media_item[&amp;quot;url&amp;quot;])&lt;/pre&gt;
  &lt;p id=&quot;hxx1&quot;&gt;Из полученного списка &lt;code&gt;media&lt;/code&gt; извлекаем все элементы, у которых есть &lt;code&gt;media_key&lt;/code&gt;, совпадающий с &lt;code&gt;media_keys&lt;/code&gt; твита, и у которых присутствует поле &lt;code&gt;url&lt;/code&gt;. Это позволяет нам получить только те изображения, которые действительно принадлежат данному твиту, а не другим вложенным элементам. Таким образом, мы формируем список &lt;code&gt;image_urls&lt;/code&gt;, содержащий ссылки на изображения, прикреплённые к твиту.&lt;/p&gt;
  &lt;p id=&quot;0RqN&quot;&gt;&lt;strong&gt;Обработка твита&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;JEgy&quot; data-lang=&quot;python&quot;&gt;self._process_tweet(
    username,
    tweet[&amp;quot;id&amp;quot;],
    tweet.get(&amp;quot;note_tweet&amp;quot;, {}).get(&amp;quot;text&amp;quot;) or tweet.get(&amp;quot;text&amp;quot;, &amp;quot;&amp;quot;),
    image_urls,
)&lt;/pre&gt;
  &lt;p id=&quot;bXVH&quot;&gt;Передаём данные в &lt;code&gt;_process_tweet()&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;cy08&quot;&gt;&lt;strong&gt;4. Метод &lt;code&gt;_process_tweet()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;8m8K&quot; data-lang=&quot;python&quot;&gt;def _process_tweet(
    self,
    username: str,
    tweet_id: str = &amp;quot;&amp;quot;,
    tweet_text: str = &amp;quot;&amp;quot;,
    image_urls: List[str] = [],
 ) -&amp;gt; None:&lt;/pre&gt;
  &lt;p id=&quot;zVwL&quot;&gt;Проверяет, есть ли контрактный адрес в тексте или на изображениях.&lt;/p&gt;
  &lt;p id=&quot;JzRi&quot;&gt;&lt;strong&gt;Поиск контракта в тексте&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;5chV&quot; data-lang=&quot;python&quot;&gt;if contract := get_contract_address(tweet_text):
    self._notify_contract_found(contract, username, tweet_id, &amp;quot;text&amp;quot;)
    return&lt;/pre&gt;
  &lt;p id=&quot;fFFt&quot;&gt;Конструкция &lt;code&gt;contract := get_contract_address(tweet_text)&lt;/code&gt; использует оператор моржового присваивания (&lt;code&gt;:=&lt;/code&gt;), который одновременно присваивает значение переменной &lt;code&gt;contract&lt;/code&gt; и проверяет его. Это эквивалентно записи:&lt;/p&gt;
  &lt;pre id=&quot;0csY&quot; data-lang=&quot;python&quot;&gt;contract = get_contract_address(tweet_text)
if contract:
    self._notify_contract_found(contract, username, tweet_id, &amp;quot;text&amp;quot;)
    return&lt;/pre&gt;
  &lt;p id=&quot;ADTC&quot;&gt;Если &lt;code&gt;get_contract_address(tweet_text)&lt;/code&gt; вернёт не &lt;code&gt;None&lt;/code&gt;, &lt;code&gt;contract&lt;/code&gt; получит это значение, и условие выполнится. Это сокращает код и делает его компактнее.&lt;/p&gt;
  &lt;p id=&quot;cbdg&quot;&gt;Если контракт найден, вызываем &lt;code&gt;_notify_contract_found()&lt;/code&gt; и выходим из функции.&lt;/p&gt;
  &lt;p id=&quot;TNrb&quot;&gt;&lt;strong&gt;Поиск контракта на изображениях&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;5mu9&quot; data-lang=&quot;python&quot;&gt;for image_url in image_urls:
    image_text = extract_text_from_image(image_url)
    if contract := get_contract_address(image_text):
        self._notify_contract_found(contract, username, tweet_id, &amp;quot;image&amp;quot;)&lt;/pre&gt;
  &lt;p id=&quot;PqbD&quot;&gt;Если контракт найден на изображении, отправляем уведомление.&lt;/p&gt;
  &lt;p id=&quot;ydsF&quot;&gt;&lt;strong&gt;5. Метод &lt;code&gt;_notify_contract_found()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;wXMk&quot; data-lang=&quot;python&quot;&gt;def _notify_contract_found(
    self, contract: str, username: str, tweet_id: str, source: str
) -&amp;gt; None:&lt;/pre&gt;
  &lt;p id=&quot;Pr8X&quot;&gt;Отправляет сообщение пользователю, если найден контракт.&lt;/p&gt;
  &lt;p id=&quot;4jua&quot;&gt;&lt;strong&gt;Формирование URL твита&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;OOws&quot; data-lang=&quot;python&quot;&gt;tweet_url = f&amp;quot;https://x.com/{username}/status/{tweet_id}&amp;quot;&lt;/pre&gt;
  &lt;p id=&quot;uf0q&quot;&gt;Создаём ссылку на твит.&lt;/p&gt;
  &lt;p id=&quot;luBp&quot;&gt;&lt;strong&gt;Формирование сообщения&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;UK0x&quot; data-lang=&quot;python&quot;&gt;message = f&amp;quot;Контракт найден в {&amp;#x27;тексте&amp;#x27; if source == &amp;#x27;text&amp;#x27; else &amp;#x27;изображении&amp;#x27;} твита: &amp;#x60;{contract}&amp;#x60;\n\n[Ссылка на твит]({tweet_url})&amp;quot;&lt;/pre&gt;
  &lt;p id=&quot;yS7s&quot;&gt;Формируем сообщение в зависимости от того, где найден контракт. Отметим, что в f строках, помимо переменных, можно использовать и тернарный оператор (не пугайся, это просто if, else)&lt;/p&gt;
  &lt;p id=&quot;52Jb&quot;&gt;&lt;strong&gt;Отправка сообщения&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;SzU7&quot; data-lang=&quot;python&quot;&gt;send_message_to_user(message)&lt;/pre&gt;
  &lt;p id=&quot;VHYj&quot;&gt;Отправляем уведомление пользователю в телеграм через функцию &lt;code&gt;send_message_to_user()&lt;/code&gt; из модуля &lt;code&gt;telegram.py&lt;/code&gt;&lt;/p&gt;
  &lt;h3 id=&quot;gxjA&quot;&gt;modules/telegram.py&lt;/h3&gt;
  &lt;p id=&quot;MfYs&quot;&gt;Очень простой модуль, все что он делает — уведомляет пользователя в телеграм через отправку сообщения ботом о найденом контракте.&lt;/p&gt;
  &lt;pre id=&quot;fH8Y&quot; data-lang=&quot;python&quot;&gt;import requests

from settings import TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID


def send_message_to_user(text: str = &amp;quot;&amp;quot;):
    requests.post(
        f&amp;quot;https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage?chat_id={TELEGRAM_CHAT_ID}&amp;amp;text={text}&amp;amp;parse_mode=Markdown&amp;quot;
    )&lt;/pre&gt;
  &lt;p id=&quot;RnaF&quot;&gt;&lt;strong&gt;Пояснение к коду:&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;d8dQ&quot;&gt;&lt;strong&gt;1. Импорты&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;qZnE&quot; data-lang=&quot;python&quot;&gt;import requests
from settings import TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID&lt;/pre&gt;
  &lt;p id=&quot;b9nz&quot;&gt;Этот код импортирует:&lt;/p&gt;
  &lt;ul id=&quot;LBLv&quot;&gt;
    &lt;li id=&quot;UKP0&quot;&gt;&lt;code&gt;requests&lt;/code&gt; — библиотеку для выполнения HTTP-запросов.&lt;/li&gt;
    &lt;li id=&quot;qXrp&quot;&gt;&lt;code&gt;TELEGRAM_BOT_TOKEN&lt;/code&gt; и &lt;code&gt;TELEGRAM_CHAT_ID&lt;/code&gt; — настройки, которые хранят токен бота и ID чата, куда отправляются сообщения.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;a6n8&quot;&gt;&lt;strong&gt;2. Функция &lt;code&gt;send_message_to_user()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;lVW1&quot; data-lang=&quot;python&quot;&gt;def send_message_to_user(text: str = &amp;quot;&amp;quot;):&lt;/pre&gt;
  &lt;p id=&quot;MKn1&quot;&gt;Эта функция отвечает за отправку текстового сообщения пользователю через API Telegram.&lt;/p&gt;
  &lt;p id=&quot;2YbT&quot;&gt;&lt;strong&gt;Отправляем сообщение через requests&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;rq74&quot; data-lang=&quot;python&quot;&gt;requests.post(
    f&amp;quot;https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage?chat_id={TELEGRAM_CHAT_ID}&amp;amp;text={text}&amp;amp;parse_mode=Markdown&amp;quot;
)&lt;/pre&gt;
  &lt;p id=&quot;F9xp&quot;&gt;Для отправки сообщения используется метод &lt;code&gt;requests.post()&lt;/code&gt;, который выполняет HTTP-запрос к Telegram API. В этом запросе формируется URL, содержащий токен бота и параметры, необходимые для отправки сообщения:&lt;/p&gt;
  &lt;ol id=&quot;f9dN&quot;&gt;
    &lt;li id=&quot;73J0&quot;&gt;&lt;code&gt;chat_id={TELEGRAM_CHAT_ID}&lt;/code&gt; — указывает, в какой чат должно быть отправлено сообщение. Этот ID привязан к пользователю или группе, в которой работает бот.&lt;/li&gt;
    &lt;li id=&quot;nF4g&quot;&gt;&lt;code&gt;text={text}&lt;/code&gt; — передаваемый текст сообщения, который будет отображаться в чате.&lt;/li&gt;
    &lt;li id=&quot;xrc4&quot;&gt;&lt;code&gt;parse_mode=Markdown&lt;/code&gt; — Telegram поддерживает форматирование Markdown, что позволяет выделять текст жирным (&lt;code&gt;**жирный**&lt;/code&gt;), курсивом (&lt;code&gt;_курсив_&lt;/code&gt;) или вставлять ссылки (&lt;code&gt;[ссылка](&lt;a href=&quot;https://example.com&quot; target=&quot;_blank&quot;&gt;https://example.com&lt;/a&gt;)&lt;/code&gt;).&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;K6po&quot;&gt;Для этого можно было бы использовать библиотеку, но мы решили не перегружать как код, не нужными либами, так и вас.&lt;/p&gt;
  &lt;h3 id=&quot;feeI&quot;&gt;modules/tweet_id_storage.py&lt;/h3&gt;
  &lt;p id=&quot;1Vy4&quot;&gt;Модуль &lt;code&gt;tweet_id_storage.py&lt;/code&gt; отвечает за сохранение и получение идентификаторов последних твитов для каждого пользователя. Он использует локальный файл &lt;code&gt;latest_tweets_id.json&lt;/code&gt; для хранения данных. Метод &lt;code&gt;get_last_tweet_id&lt;/code&gt; позволяет получить идентификатор последнего твита для конкретного пользователя, а метод &lt;code&gt;save_last_tweet_id&lt;/code&gt; сохраняет новый идентификатор твита в файл, обновляя информацию для указанного пользователя. Этот модуль обеспечивает отслеживание последних обработанных твитов, чтобы избежать повторной обработки тех же твитов.&lt;/p&gt;
  &lt;pre id=&quot;jzfY&quot; data-lang=&quot;python&quot;&gt;import json
import os


class TweetIdStorage:
    LATEST_TWEETS_ID_PATH = &amp;quot;latest_tweets_id.json&amp;quot;

    def get_last_tweet_id(self, username: str) -&amp;gt; str:
        if os.path.exists(self.LATEST_TWEETS_ID_PATH):
            with open(self.LATEST_TWEETS_ID_PATH, &amp;quot;r&amp;quot;) as file:
                data = json.loads(file.read())
        else:
            data = {}

        return data.get(username, None)

    def save_last_tweet_id(self, username: str, tweet_id: str):
        if os.path.exists(self.LATEST_TWEETS_ID_PATH):
            with open(self.LATEST_TWEETS_ID_PATH, &amp;quot;r&amp;quot;) as file:
                data = json.loads(file.read())
        else:
            data = {}

        data[username] = tweet_id

        with open(self.LATEST_TWEETS_ID_PATH, &amp;quot;w&amp;quot;) as file:
            file.write(json.dumps(data))&lt;/pre&gt;
  &lt;p id=&quot;pVMk&quot;&gt;&lt;strong&gt;Пояснение к коду:&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;1nF0&quot;&gt;&lt;strong&gt;1. Импорты&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;EGdv&quot; data-lang=&quot;python&quot;&gt;import json
import os&lt;/pre&gt;
  &lt;p id=&quot;SoRj&quot;&gt;Этот модуль импортирует два стандартных модуля Python:&lt;/p&gt;
  &lt;ul id=&quot;6mKW&quot;&gt;
    &lt;li id=&quot;C3ng&quot;&gt;&lt;code&gt;json&lt;/code&gt; — библиотека для работы с JSON-данными, которая позволяет сериализовать (преобразовывать объекты Python в строковый формат JSON) и десериализовать (из JSON-строки обратно в объект Python). Мы используем её для хранения ID твитов в файле и работы с этим хранилищем как с обычным словарём.&lt;/li&gt;
    &lt;li id=&quot;yMhC&quot;&gt;&lt;code&gt;os&lt;/code&gt; — модуль для работы с операционной системой, который предоставляет функции для взаимодействия с файловой системой. В данном случае он помогает нам проверять, существует ли файл &lt;code&gt;latest_tweets_id.json&lt;/code&gt;, прежде чем пытаться его открыть. Это предотвращает ошибки при обращении к несуществующему файлу.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;CZgO&quot;&gt;&lt;strong&gt;2. Класс &lt;code&gt;TweetIdStorage&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;O1QK&quot; data-lang=&quot;python&quot;&gt;class TweetIdStorage:
    LATEST_TWEETS_ID_PATH = &amp;quot;latest_tweets_id.json&amp;quot;&lt;/pre&gt;
  &lt;p id=&quot;2SfE&quot;&gt;Этот класс предназначен для сохранения и получения последнего ID твита, связанного с пользователем.&lt;/p&gt;
  &lt;ul id=&quot;pA3W&quot;&gt;
    &lt;li id=&quot;t9Wd&quot;&gt;&lt;code&gt;LATEST_TWEETS_ID_PATH&lt;/code&gt; — это классовый атрибут, который хранит имя JSON-файла, в котором сохраняются данные. Этот файл можно рассматривать как небольшую базу данных.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;rNRc&quot;&gt;&lt;strong&gt;Что такое классовые атрибуты&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;3kCD&quot;&gt;Мы говорили, что рассмотрим классовые атрибуты при разборе этого модуля. Так вот, &lt;code&gt;LATEST_TWEETS_ID_PATH&lt;/code&gt; — это тот самый атрибут. В отличие от обычных атрибутов, классовые атрибуты являются общими для всех объектов класса. Это значит, что если изменить значение атрибута, например, &lt;code&gt;self.a&lt;/code&gt;, у одного объекта, оно изменится и у всех остальных объектов этого класса.&lt;/p&gt;
  &lt;p id=&quot;Sl0N&quot;&gt;&lt;strong&gt;3. Функция &lt;code&gt;get_last_tweet_id()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;cZ60&quot; data-lang=&quot;python&quot;&gt;def get_last_tweet_id(self, username: str) -&amp;gt; str:&lt;/pre&gt;
  &lt;p id=&quot;rkpc&quot;&gt;Эта функция загружает JSON-файл и получает последний сохранённый ID твита для конкретного пользователя.&lt;/p&gt;
  &lt;p id=&quot;4qAI&quot;&gt;&lt;strong&gt;Проверка файла на существование&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;pztr&quot; data-lang=&quot;python&quot;&gt;if os.path.exists(self.LATEST_TWEETS_ID_PATH):&lt;/pre&gt;
  &lt;p id=&quot;Dxvx&quot;&gt;Сначала проверяется наличие файла &lt;code&gt;latest_tweets_id.json&lt;/code&gt; с помощью функции &lt;code&gt;os.path.exists&lt;/code&gt;. Эта функция принимает путь к файлу, и так как файл хранится в корне проекта, достаточно указать только его название, которое хранится в &lt;code&gt;self.LATEST_TWEETS_ID_PATH&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;Atbh&quot;&gt;&lt;strong&gt;Чтение данных из файла&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;ulVp&quot; data-lang=&quot;python&quot;&gt;with open(self.LATEST_TWEETS_ID_PATH, &amp;quot;r&amp;quot;) as file:
    data = json.loads(file.read())&lt;/pre&gt;
  &lt;p id=&quot;KroX&quot;&gt;Открываем файл в режиме чтения (&lt;code&gt;&amp;quot;r&amp;quot;&lt;/code&gt;), затем с помощью &lt;code&gt;file.read()&lt;/code&gt; считываем его содержимое в виде строки. После этого используем &lt;code&gt;json.loads()&lt;/code&gt;, чтобы преобразовать JSON-формат в питоновский словарь. Теперь &lt;code&gt;data&lt;/code&gt; содержит словарь, где ключи — это имена пользователей, а значения — ID их последних твитов.&lt;/p&gt;
  &lt;pre id=&quot;gaEr&quot; data-lang=&quot;python&quot;&gt;else:
    data = {}&lt;/pre&gt;
  &lt;p id=&quot;yY0J&quot;&gt;Если файла нет, создаётся пустой словарь &lt;code&gt;data&lt;/code&gt;, чтобы избежать ошибок при доступе к несуществующим данным.&lt;/p&gt;
  &lt;p id=&quot;iOnS&quot;&gt;&lt;strong&gt;Возвращаемый результат&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;lvYQ&quot; data-lang=&quot;python&quot;&gt;return data.get(username, None)&lt;/pre&gt;
  &lt;p id=&quot;xRVz&quot;&gt;Функция ищет в словаре ключ с именем пользователя (&lt;code&gt;username&lt;/code&gt;) и возвращает его значение (ID последнего твита). Если ключ отсутствует, возвращается &lt;code&gt;None&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;jjH5&quot;&gt;&lt;strong&gt;4. Функция &lt;code&gt;save_last_tweet_id()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;T2EB&quot; data-lang=&quot;python&quot;&gt;def save_last_tweet_id(self, username: str, tweet_id: str):&lt;/pre&gt;
  &lt;p id=&quot;gT4G&quot;&gt;Эта функция сохраняет последний ID твита пользователя в JSON-файл.&lt;/p&gt;
  &lt;p id=&quot;Jwwp&quot;&gt;&lt;strong&gt;Проверка файла на существование и чтение из него&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;3UUV&quot; data-lang=&quot;python&quot;&gt;if os.path.exists(self.LATEST_TWEETS_ID_PATH):
    with open(self.LATEST_TWEETS_ID_PATH, &amp;quot;r&amp;quot;) as file:
        data = json.loads(file.read())&lt;/pre&gt;
  &lt;p id=&quot;ytn0&quot;&gt;Как и в &lt;code&gt;get_last_tweet_id()&lt;/code&gt;, сначала проверяется, существует ли JSON-файл. Если он есть, его содержимое загружается в виде словаря.&lt;/p&gt;
  &lt;pre id=&quot;Nfsq&quot; data-lang=&quot;python&quot;&gt;else:
    data = {}&lt;/pre&gt;
  &lt;p id=&quot;b96h&quot;&gt;Если файла нет, создаётся пустой словарь.&lt;/p&gt;
  &lt;p id=&quot;3jzB&quot;&gt;&lt;strong&gt;Обновляем ID последнего твита для юзера&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;vnZm&quot; data-lang=&quot;python&quot;&gt;data[username] = tweet_id&lt;/pre&gt;
  &lt;p id=&quot;PA7i&quot;&gt;Далее в словарь добавляется/изменяется запись, где ключ — это имя пользователя, а значение — ID твита.&lt;/p&gt;
  &lt;p id=&quot;6oKD&quot;&gt;&lt;strong&gt;Записываем результат обратно в файл&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;ges0&quot; data-lang=&quot;python&quot;&gt;with open(self.LATEST_TWEETS_ID_PATH, &amp;quot;w&amp;quot;) as file:
    file.write(json.dumps(data))&lt;/pre&gt;
  &lt;p id=&quot;cci1&quot;&gt;Сначала обновлённый словарь с данными преобразуется в JSON-строку с помощью &lt;code&gt;json.dumps()&lt;/code&gt;. Затем, используя &lt;code&gt;file.write()&lt;/code&gt;, эта строка записывается в файл, открытый в режиме &lt;code&gt;&amp;quot;w&amp;quot;&lt;/code&gt; (перезапись файла).&lt;/p&gt;
  &lt;h3 id=&quot;RnqR&quot;&gt;modules/x.py&lt;/h3&gt;
  &lt;p id=&quot;9AWJ&quot;&gt;Модуль &lt;code&gt;x.py&lt;/code&gt; обеспечивает взаимодействие с API платформы X (Twitter). Он позволяет выполнять запросы для получения данных о пользователях, их твитах и конкретных твитах по идентификатору. Основные функции включают извлечение идентификатора пользователя по его имени, получение списка твитов пользователя с учетом ранее обработанных, а также получение информации о твите по его ID. Модуль обрабатывает лимиты запросов, поддерживает прокси и интегрируется с модулем &lt;code&gt;tweet_id_storage.py&lt;/code&gt; для хранения последних обработанных твитов.&lt;/p&gt;
  &lt;pre id=&quot;LF4t&quot; data-lang=&quot;python&quot;&gt;import time
from typing import Any, Dict

import requests

from modules.tweet_id_storage import TweetIdStorage
from settings import BEARER_TOKEN, MAX_RETRIES, PROXY


class XAPIHandler:
    BASE_URL = &amp;quot;https://api.x.com/2&amp;quot;

    def __init__(self):
        self.tweet_id_storage = TweetIdStorage()

    def _make_request(
        self,
        endpoint: str,
        method: str,
        data: Dict[str, Any] = {},
        params: Dict[str, str] = {},
    ) -&amp;gt; Dict[str, Any]:
        headers = {
            &amp;quot;Authorization&amp;quot;: f&amp;quot;Bearer {BEARER_TOKEN}&amp;quot;,
        }

        retries = 0
        while retries &amp;lt; MAX_RETRIES:
            try:
                response = requests.request(
                    method=method,
                    url=self.BASE_URL + endpoint,
                    headers=headers,
                    data=data,
                    params=params,
                    proxies={&amp;quot;http&amp;quot;: PROXY, &amp;quot;https&amp;quot;: PROXY}
                    if PROXY != &amp;quot;scheme://username:password@host:port&amp;quot;
                    else None,
                )
                response.raise_for_status()

                return response.json()
            except requests.exceptions.HTTPError as error:
                if error.response.status_code == 429:
                    reset_time = error.response.headers[&amp;quot;X-Rate-Limit-Reset&amp;quot;]
                    time_to_wait = int(reset_time) - int(time.time())
                    print(
                        f&amp;quot;Превышено максимальное количество запросов. Подождите {time_to_wait} секунд&amp;quot;
                    )
                    time.sleep(time_to_wait)
                else:
                    print(error.response.text)
                    retries += 1

        raise Exception(&amp;quot;Превышено максимальное количество попыток&amp;quot;)

    def fetch_user_id_by_username(self, username: str) -&amp;gt; str:
        user = self._make_request(f&amp;quot;/users/by/username/{username}&amp;quot;, method=&amp;quot;GET&amp;quot;)

        return user[&amp;quot;data&amp;quot;][&amp;quot;id&amp;quot;]

    def fetch_user_tweets(self, username: str, user_id: str) -&amp;gt; Dict[str, Any]:
        last_tweet_id = self.tweet_id_storage.get_last_tweet_id(username)

        params = {
            &amp;quot;expansions&amp;quot;: &amp;quot;attachments.media_keys,referenced_tweets.id&amp;quot;,
            &amp;quot;media.fields&amp;quot;: &amp;quot;url,type,media_key&amp;quot;,
            &amp;quot;tweet.fields&amp;quot;: &amp;quot;text,note_tweet&amp;quot;,
        }

        if last_tweet_id:
            params[&amp;quot;since_id&amp;quot;] = last_tweet_id
            params[&amp;quot;max_results&amp;quot;] = &amp;quot;100&amp;quot;
        else:
            params[&amp;quot;max_results&amp;quot;] = &amp;quot;5&amp;quot;

        return self._make_request(
            f&amp;quot;/users/{user_id}/tweets&amp;quot;, method=&amp;quot;GET&amp;quot;, params=params
        )

    def get_tweet_by_id(self, tweet_id: str) -&amp;gt; Dict[str, Any]:
        params = {
            &amp;quot;expansions&amp;quot;: &amp;quot;attachments.media_keys,referenced_tweets.id&amp;quot;,
            &amp;quot;media.fields&amp;quot;: &amp;quot;url,type,media_key&amp;quot;,
            &amp;quot;tweet.fields&amp;quot;: &amp;quot;text,note_tweet&amp;quot;,
        }

        return self._make_request(f&amp;quot;/tweets/{tweet_id}&amp;quot;, method=&amp;quot;GET&amp;quot;, params=params)&lt;/pre&gt;
  &lt;p id=&quot;NVr7&quot;&gt;&lt;strong&gt;Пояснение к коду:&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;Kxt8&quot;&gt;Далее разберем работу кода, который взаимодействует с этим API. Вся информация получена из &lt;a href=&quot;https://docs.x.com/x-api/introduction&quot; target=&quot;_blank&quot;&gt;официальной документации&lt;/a&gt;. Рекомендуем всегда начинать с изучения документации при работе с любыми API.&lt;/p&gt;
  &lt;p id=&quot;fAVx&quot;&gt;&lt;strong&gt;1. Импорты&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;pmXJ&quot; data-lang=&quot;python&quot;&gt;import time
from typing import Any, Dict
import requests
from modules.tweet_id_storage import TweetIdStorage
from settings import BEARER_TOKEN, MAX_RETRIES, PROXY&lt;/pre&gt;
  &lt;p id=&quot;vFE4&quot;&gt;Мы импортируем:&lt;/p&gt;
  &lt;ul id=&quot;z2mN&quot;&gt;
    &lt;li id=&quot;0KrE&quot;&gt;&lt;code&gt;time&lt;/code&gt; — используется для работы с задержками (&lt;code&gt;sleep&lt;/code&gt;).&lt;/li&gt;
    &lt;li id=&quot;x73V&quot;&gt;&lt;code&gt;Any&lt;/code&gt; и &lt;code&gt;Dict&lt;/code&gt; из &lt;code&gt;typing&lt;/code&gt; — используются для аннотации типов.&lt;/li&gt;
    &lt;li id=&quot;synz&quot;&gt;&lt;code&gt;requests&lt;/code&gt; — библиотека для отправки HTTP-запросов.&lt;/li&gt;
    &lt;li id=&quot;bGpC&quot;&gt;&lt;code&gt;TweetIdStorage&lt;/code&gt; — класс для чтение и добавления ID последних обработанных твитов.&lt;/li&gt;
    &lt;li id=&quot;cPZc&quot;&gt;&lt;code&gt;BEARER_TOKEN&lt;/code&gt;, &lt;code&gt;MAX_RETRIES&lt;/code&gt;, &lt;code&gt;PROXY&lt;/code&gt; — настройки, используемые для работы с API X.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;Hkf0&quot;&gt;&lt;strong&gt;2. Класс &lt;code&gt;XAPIHandler&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;7Qfr&quot; data-lang=&quot;python&quot;&gt;class XAPIHandler:
    BASE_URL = &amp;quot;https://api.x.com/2&amp;quot;&lt;/pre&gt;
  &lt;p id=&quot;XBue&quot;&gt;Этот класс предназначен для взаимодействия с API X.&lt;/p&gt;
  &lt;ul id=&quot;KCl1&quot;&gt;
    &lt;li id=&quot;5CSN&quot;&gt;&lt;code&gt;BASE_URL&lt;/code&gt; — это классовый атрибут, который доступен всем объектам класса &lt;code&gt;XAPIHandler&lt;/code&gt;. Он задаёт базовый URL, к которому добавляются конечные точки API для формирования запросов.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;jVWq&quot;&gt;&lt;strong&gt;Инициализация класса&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;5e8q&quot; data-lang=&quot;python&quot;&gt;def __init__(self):
    self.tweet_id_storage = TweetIdStorage()&lt;/pre&gt;
  &lt;p id=&quot;Aisu&quot;&gt;При создании объекта класса &lt;code&gt;XAPIHandler&lt;/code&gt; создаётся объект &lt;code&gt;TweetIdStorage&lt;/code&gt;, который будет использоваться для чтения и сохранения ID последних твитов, чтобы избежать повторной обработки одних и тех же данных.&lt;/p&gt;
  &lt;p id=&quot;spbO&quot;&gt;&lt;strong&gt;3. Метод &lt;code&gt;_make_request()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;fbLj&quot; data-lang=&quot;python&quot;&gt;def _make_request(
    self,
    endpoint: str,
    method: str,
    data: Dict[str, Any] = {},
    params: Dict[str, str] = {},
) -&amp;gt; Dict[str, Any]:&lt;/pre&gt;
  &lt;p id=&quot;x2F9&quot;&gt;Этот метод выполняет HTTP-запросы к API X. Принимает следующие аргументы:&lt;/p&gt;
  &lt;ul id=&quot;s3ij&quot;&gt;
    &lt;li id=&quot;qCPq&quot;&gt;&lt;code&gt;endpoint&lt;/code&gt; — конечная точка API, например, &lt;code&gt;&amp;quot;/users/by/username/{username}&amp;quot;&lt;/code&gt;. То есть, мы ожидаем, что это будет путь к X API, но без &lt;a href=&quot;https://api.x.com/2&quot; target=&quot;_blank&quot;&gt;&lt;code&gt;https://api.x.com/2&lt;/code&gt;&lt;/a&gt;, так как это у нас уже записано в &lt;code&gt;self.BASE_URL&lt;/code&gt;&lt;/li&gt;
    &lt;li id=&quot;SuRu&quot;&gt;&lt;code&gt;method&lt;/code&gt; — HTTP-метод (&lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;POST&lt;/code&gt; и т. д.)&lt;/li&gt;
    &lt;li id=&quot;WMPl&quot;&gt;&lt;code&gt;data&lt;/code&gt; — данные, передаваемые в теле запроса (по умолчанию пустой словарь)&lt;/li&gt;
    &lt;li id=&quot;63cn&quot;&gt;&lt;code&gt;params&lt;/code&gt; — параметры запроса, передаваемые в URL (по умолчанию также пустой словарь)&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;I49R&quot;&gt;&lt;strong&gt;Формирование запроса&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;wgHb&quot; data-lang=&quot;python&quot;&gt;headers = {
    &amp;quot;Authorization&amp;quot;: f&amp;quot;Bearer {BEARER_TOKEN}&amp;quot;,
}&lt;/pre&gt;
  &lt;p id=&quot;HyBu&quot;&gt;Добавляется заголовок &lt;code&gt;Authorization&lt;/code&gt;, содержащий токен &lt;code&gt;BEARER_TOKEN&lt;/code&gt;, который требуется для работы с API X.&lt;/p&gt;
  &lt;p id=&quot;xXth&quot;&gt;&lt;strong&gt;Цикл с попытками запроса&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;Welq&quot; data-lang=&quot;python&quot;&gt;retries = 0
while retries &amp;lt; MAX_RETRIES:&lt;/pre&gt;
  &lt;p id=&quot;RFKR&quot;&gt;Ограничивается число попыток запроса по &lt;code&gt;MAX_RETRIES&lt;/code&gt;, чтобы избежать бесконечных повторных попыток в случае ошибки.&lt;/p&gt;
  &lt;p id=&quot;uGYT&quot;&gt;&lt;strong&gt;Отправка запроса&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;Qpq9&quot; data-lang=&quot;python&quot;&gt;try:
    response = requests.request(
        method=method,
        url=self.BASE_URL + endpoint,
        headers=headers,
        data=data,
        params=params,
        proxies={&amp;quot;http&amp;quot;: PROXY, &amp;quot;https&amp;quot;: PROXY}
        if PROXY != &amp;quot;scheme://username:password@host:port&amp;quot;
        else None,
)
    response.raise_for_status()
    return response.json()&lt;/pre&gt;
  &lt;p id=&quot;XYqA&quot;&gt;Отправляем HTTP-запрос по адресу, составленному из &lt;code&gt;BASE_URL&lt;/code&gt; и переданного &lt;code&gt;endpoint&lt;/code&gt;. Заголовки запроса включают авторизационный токен, который необходим для доступа к API.&lt;/p&gt;
  &lt;p id=&quot;80s3&quot;&gt;Если &lt;code&gt;PROXY&lt;/code&gt; указан, то он будет использоваться для маршрутизации запроса.&lt;/p&gt;
  &lt;p id=&quot;uAq0&quot;&gt;После отправки запроса вызывается &lt;code&gt;response.raise_for_status()&lt;/code&gt;, который проверяет код ответа. Если сервер возвращает ошибку (например, 404 — не найдено или 500 — внутренняя ошибка), то мы вызываем исключение.&lt;/p&gt;
  &lt;p id=&quot;NzKZ&quot;&gt;Если запрос выполнен успешно, выполняем &lt;code&gt;response.json()&lt;/code&gt;, который преобразует ответ API в словарь Python.&lt;/p&gt;
  &lt;p id=&quot;Y3WW&quot;&gt;&lt;strong&gt;Обработка ошибки &amp;quot;Слишком много запросов&amp;quot; (код 429)&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;QaXo&quot; data-lang=&quot;python&quot;&gt;except requests.exceptions.HTTPError as error:
    if error.response.status_code == 429:
        reset_time = error.response.headers[&amp;quot;X-Rate-Limit-Reset&amp;quot;]
        time_to_wait = int(reset_time) - int(time.time())
        print(
            f&amp;quot;Превышено максимальное количество запросов. Подождите {time_to_wait} секунд&amp;quot;
        )
        time.sleep(time_to_wait)&lt;/pre&gt;
  &lt;p id=&quot;XTFf&quot;&gt;X API имеет ограничения на количество запросов для бесплатной версии, поэтому нам нужно обрабатывать данную ситуацию.&lt;/p&gt;
  &lt;p id=&quot;aUmr&quot;&gt;Если API X отвечает кодом &lt;code&gt;429&lt;/code&gt; (слишком много запросов), скрипт получает из заголовков ответа значение &lt;code&gt;X-Rate-Limit-Reset&lt;/code&gt;, которое указывает, когда можно отправить следующий запрос.&lt;/p&gt;
  &lt;p id=&quot;GmJO&quot;&gt;Далее вычисляется разница между этим значением и текущим временем, чтобы определить, сколько секунд необходимо подождать. После этого выполнение кода приостанавливается на рассчитанный интервал с помощью &lt;code&gt;time.sleep(time_to_wait)&lt;/code&gt;, а затем запрос повторяется.&lt;/p&gt;
  &lt;p id=&quot;vnJy&quot;&gt;&lt;strong&gt;Обработка других ошибок&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;v6N5&quot; data-lang=&quot;python&quot;&gt;else:
    print(error.response.text)
    retries += 1&lt;/pre&gt;
  &lt;p id=&quot;CIZZ&quot;&gt;Если ошибка не связана с лимитом запросов, выводится текст ошибки и увеличивается &lt;code&gt;retries&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;WymW&quot;&gt;&lt;strong&gt;Выход из while цикла&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;23JD&quot;&gt;После того как &lt;code&gt;retries&lt;/code&gt; превысит &lt;code&gt;MAX_RETRIES&lt;/code&gt;, скрипт выходит из while цикла и вызывает исключение.&lt;/p&gt;
  &lt;pre id=&quot;8oKg&quot; data-lang=&quot;python&quot;&gt;raise Exception(&amp;quot;Превышено максимальное количество попыток&amp;quot;)&lt;/pre&gt;
  &lt;p id=&quot;LnrI&quot;&gt;&lt;strong&gt;4. Метод &lt;code&gt;fetch_user_id_by_username&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;HocX&quot;&gt;Этот метод получает ID пользователя по его &lt;code&gt;username&lt;/code&gt;.&lt;/p&gt;
  &lt;pre id=&quot;w9Tz&quot; data-lang=&quot;python&quot;&gt;def fetch_user_id_by_username(self, username: str) -&amp;gt; str:
    user = self._make_request(f&amp;quot;/users/by/username/{username}&amp;quot;, method=&amp;quot;GET&amp;quot;)
    return user[&amp;quot;data&amp;quot;][&amp;quot;id&amp;quot;]&lt;/pre&gt;
  &lt;p id=&quot;4PpO&quot;&gt;Выполняем запрос используя ранее описанный метод &lt;code&gt;self._make_request()&lt;/code&gt;. В него мы передаем &lt;code&gt;endpoint&lt;/code&gt; на который нужно сделать &lt;code&gt;GET&lt;/code&gt; запрос для получения ID пользователя по его &lt;code&gt;username&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;CGSB&quot;&gt;Ответом от X API будет словарь, который содержит данные о пользователе. Из него мы вытаскиваем ID пользователя и возвращаем.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;yC4q&quot;&gt;&lt;strong&gt;5. Метод &lt;code&gt;fetch_user_tweets&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;4w06&quot; data-lang=&quot;python&quot;&gt;def fetch_user_tweets(self, username: str, user_id: str) -&amp;gt; Dict[str, Any]:&lt;/pre&gt;
  &lt;p id=&quot;nV7o&quot;&gt;Этот метод позволяет получить твиты пользователя. В качестве аргумента принимает &lt;code&gt;username&lt;/code&gt; и &lt;code&gt;user_id&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;IXMl&quot;&gt;&lt;strong&gt;Вытаскиваем ID последних постов&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;tQkE&quot; data-lang=&quot;python&quot;&gt;last_tweet_id = self.tweet_id_storage.get_last_tweet_id(username)&lt;/pre&gt;
  &lt;p id=&quot;YCF6&quot;&gt;Сначала берём ID последнего сохранённого твита пользователя. Для этого используем уже знакомый нам &lt;code&gt;self.tweet_id_storage.get_last_tweet_id()&lt;/code&gt; и передаем ему &lt;code&gt;username&lt;/code&gt; аккаунта.&lt;/p&gt;
  &lt;p id=&quot;nEdn&quot;&gt;&lt;strong&gt;Указываем параметры запроса к X API&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;sgzP&quot; data-lang=&quot;python&quot;&gt;params = {
    &amp;quot;expansions&amp;quot;: &amp;quot;attachments.media_keys,referenced_tweets.id&amp;quot;,
    &amp;quot;media.fields&amp;quot;: &amp;quot;url,type,media_key&amp;quot;,
    &amp;quot;tweet.fields&amp;quot;: &amp;quot;text,note_tweet&amp;quot;,
}&lt;/pre&gt;
  &lt;p id=&quot;idno&quot;&gt;Нам нужно получить твиты вместе с ретвитами, приложенными изображениями, а также полный текст. Из документации мы узнали, что для этого необходимо указать следующие параметры:&lt;/p&gt;
  &lt;p id=&quot;Flfb&quot;&gt;&lt;code&gt;expansions&lt;/code&gt; используется для включения связанных объектов, которые не входят в основной ответ API:&lt;/p&gt;
  &lt;ul id=&quot;MxIP&quot;&gt;
    &lt;li id=&quot;yrni&quot;&gt;&lt;code&gt;referenced_tweets.id&lt;/code&gt; — позволяет получать ретвиты и цитаты.&lt;/li&gt;
    &lt;li id=&quot;XWTG&quot;&gt;&lt;code&gt;attachments.media_keys&lt;/code&gt; — включает идентификаторы медиафайлов, прикрепленных к твиту.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;26Vp&quot;&gt;&lt;code&gt;tweet.fields&lt;/code&gt; определяет, какие свойства твита должны быть включены в ответ API:&lt;/p&gt;
  &lt;ul id=&quot;U1MR&quot;&gt;
    &lt;li id=&quot;neQZ&quot;&gt;&lt;code&gt;text&lt;/code&gt; — сам текст твита.&lt;/li&gt;
    &lt;li id=&quot;ld6M&quot;&gt;&lt;code&gt;note_tweet&lt;/code&gt; — примечания к твиту.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;7Qc2&quot;&gt;Если твит содержит изображения, видео или GIF, то для получения информации о них используется &lt;code&gt;media.fields&lt;/code&gt;:&lt;/p&gt;
  &lt;ul id=&quot;WUsy&quot;&gt;
    &lt;li id=&quot;9mxO&quot;&gt;&lt;code&gt;media_key&lt;/code&gt; — уникальный идентификатор медиафайла.&lt;/li&gt;
    &lt;li id=&quot;a77T&quot;&gt;&lt;code&gt;type&lt;/code&gt; — тип медиа (&lt;code&gt;photo&lt;/code&gt;, &lt;code&gt;video&lt;/code&gt;, &lt;code&gt;animated_gif&lt;/code&gt;).&lt;/li&gt;
    &lt;li id=&quot;5KmE&quot;&gt;&lt;code&gt;url&lt;/code&gt; — ссылка на медиафайл (доступна для изображений).&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;vsE5&quot;&gt;&lt;strong&gt;Модифицируем параметры в зависимости от наличия &lt;code&gt;last_tweet_id&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;XvBu&quot; data-lang=&quot;python&quot;&gt;if last_tweet_id:
    params[&amp;quot;since_id&amp;quot;] = last_tweet_id
    params[&amp;quot;max_results&amp;quot;] = &amp;quot;100&amp;quot;
else:
    params[&amp;quot;max_results&amp;quot;] = &amp;quot;5&amp;quot;&lt;/pre&gt;
  &lt;ul id=&quot;9scg&quot;&gt;
    &lt;li id=&quot;aOJu&quot;&gt;Если есть &lt;code&gt;last_tweet_id&lt;/code&gt;, берём твиты только после него (до 100 штук).&lt;/li&gt;
    &lt;li id=&quot;woYX&quot;&gt;Если нет — просто берём последние 5 твитов.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;cWtU&quot;&gt;&lt;strong&gt;Возвращаем результат&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;NrL3&quot; data-lang=&quot;python&quot;&gt;return self._make_request(f&amp;quot;/users/{user_id}/tweets&amp;quot;, method=&amp;quot;GET&amp;quot;, params=params)&lt;/pre&gt;
  &lt;p id=&quot;zrHM&quot;&gt;В качестве результата мы возвращаем ответ от запрос на &lt;code&gt;GET /users/{user_id}/tweets&lt;/code&gt;, что вернет нам твиты пользователя&lt;/p&gt;
  &lt;hr /&gt;
  &lt;p id=&quot;eDmQ&quot;&gt;&lt;strong&gt;6. Метод &lt;code&gt;get_tweet_by_id&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;gGLe&quot; data-lang=&quot;python&quot;&gt;def get_tweet_by_id(self, tweet_id: str) -&amp;gt; Dict[str, Any]:&lt;/pre&gt;
  &lt;p id=&quot;gfP7&quot;&gt;Получаем информацию о конкретном твите, что пригодится при разборе ретвитов, так как их изображения не хранятся в ответе из &lt;code&gt;fetch_user_tweets&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;Y13N&quot;&gt;&lt;strong&gt;Указываем параметры к запросу&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;MHFl&quot; data-lang=&quot;python&quot;&gt;params = {
    &amp;quot;expansions&amp;quot;: &amp;quot;attachments.media_keys,referenced_tweets.id&amp;quot;,
    &amp;quot;media.fields&amp;quot;: &amp;quot;url,type,media_key&amp;quot;,
    &amp;quot;tweet.fields&amp;quot;: &amp;quot;text,note_tweet&amp;quot;,
}&lt;/pre&gt;
  &lt;p id=&quot;2Fqt&quot;&gt;Снова указываем параматеры к запросу, они будут такими же как и в предыдущий раз.&lt;/p&gt;
  &lt;p id=&quot;7nZ5&quot;&gt;&lt;strong&gt;Возвращаем результат&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;5J4a&quot; data-lang=&quot;python&quot;&gt;return self._make_request(f&amp;quot;/tweets/{tweet_id}&amp;quot;, method=&amp;quot;GET&amp;quot;, params=params)&lt;/pre&gt;
  &lt;p id=&quot;KFXI&quot;&gt;Делаем запрос на &lt;code&gt;GET /tweets/{tweet_id}&lt;/code&gt; и возвращаем результат&lt;/p&gt;
  &lt;h2 id=&quot;i2Sr&quot;&gt;Заключение&lt;/h2&gt;
  &lt;p id=&quot;8Olb&quot;&gt;Мы разобрали наш парсер X аккаунтов от а до я. Надеемся вам все было понятно, а если нет, то го в комменты — ответим и поясним за любую строчку в коде.&lt;/p&gt;
  &lt;p id=&quot;jFNR&quot;&gt;Данный скрипт мы написали всего за один день. Да, пришлось попотеть с API X, но в целом код, ну очень простой. Поэтому не бойся и просто начинай писать. Никогда не будет всё чётко и гладко, главное быть готовым к трудностям.&lt;/p&gt;
  &lt;p id=&quot;F3O1&quot;&gt;📌 Сохраняй статью и делись с друзьями, пускай тоже прошарят за код &lt;/p&gt;
  &lt;p id=&quot;5YO8&quot;&gt;&lt;a href=&quot;https://t.me/aio_study&quot; target=&quot;_blank&quot;&gt;AIO Study&lt;/a&gt; | &lt;a href=&quot;https://aiostudy.com/&quot; target=&quot;_blank&quot;&gt;Site&lt;/a&gt;&lt;/p&gt;

</content></entry><entry><id>aiostudy:Pm_doUr5pnd</id><link rel="alternate" type="text/html" href="https://teletype.in/@aiostudy/Pm_doUr5pnd?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=aiostudy"></link><title>Пишем софт по раскидыванию баланса с биржи</title><published>2025-01-19T15:28:40.895Z</published><updated>2025-01-20T20:06:22.331Z</updated><summary type="html">Привет! В этой статье ты вместе с нами сможешь забабахать свой первый полезный софт. Перед прочтением, мы настоятельно рекомендуем прочитать нашу первую статью о написании скрипта, если ты раньше никогда не кодил.</summary><content type="html">
  &lt;p id=&quot;h1vK&quot;&gt;Привет! В этой статье ты вместе с нами сможешь забабахать свой первый полезный софт. Перед прочтением, мы настоятельно рекомендуем прочитать нашу &lt;a href=&quot;https://teletype.in/@aiostudy/OvPvQsVMhgY&quot; target=&quot;_blank&quot;&gt;первую статью&lt;/a&gt; о написании скрипта, если ты раньше никогда не кодил.&lt;/p&gt;
  &lt;p id=&quot;6rTB&quot;&gt;&lt;strong&gt;Что будет делать написанный скрипт?&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;Hvzi&quot;&gt;Софт будет раскидывать баланс с биржи OKX на кошельки, которые ты укажешь в файле. Выводить сможешь любой токен и его количество, указанное в настройках.&lt;/p&gt;
  &lt;p id=&quot;tpMF&quot;&gt;&lt;strong&gt;Что ты должен уметь?&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;2UhJ&quot;&gt;Для понимания материала потребуется базовое знание синтаксиса Python. Если что-то будет непонятно, не бойся обратиться к ChatGPT за помощью.&lt;/p&gt;
  &lt;p id=&quot;E7i6&quot;&gt;&lt;strong&gt;Где я могу посмотреть код скрипта?&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;O8Oq&quot;&gt;Ты можешь посмотреть и скачать наш код с &lt;a href=&quot;https://github.com/AIOStudy/okx_spreader&quot; target=&quot;_blank&quot;&gt;GitHub репозитория&lt;/a&gt;.&lt;/p&gt;
  &lt;h2 id=&quot;FQa9&quot;&gt;Оглавление&lt;/h2&gt;
  &lt;p id=&quot;JvdG&quot;&gt;&lt;a href=&quot;#dymX&quot;&gt;Что такое API&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;OLqt&quot;&gt;&lt;a href=&quot;#IapK&quot;&gt;Получаем ключи для взаимодействия с OKX API&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;bnmL&quot;&gt;&lt;a href=&quot;#P4sL&quot;&gt;Создаем проект и структуру файлов&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;v2Ro&quot;&gt;&lt;a href=&quot;#Hp99&quot;&gt;Начинаем писать код&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;3jjw&quot;&gt;&lt;a href=&quot;#rFG1&quot;&gt;Подготовка и запуск скрипта&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;g4So&quot;&gt;&lt;a href=&quot;#8Bji&quot;&gt;Как можно улучшить скрипт&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;9UfW&quot;&gt;&lt;a href=&quot;#Wryx&quot;&gt;Заключение&lt;/a&gt;&lt;/p&gt;
  &lt;h2 id=&quot;dymX&quot;&gt;Что такое API&lt;/h2&gt;
  &lt;p id=&quot;AFaL&quot;&gt;Для написания софта нам понадобится работать с OKX API. Так что сначала разберемся с тем, что такое API.&lt;/p&gt;
  &lt;p id=&quot;MdiY&quot;&gt;&lt;strong&gt;API (Application Programming Interface)&lt;/strong&gt; — Если упростить, то это набор инструментов, которые позволяют различным программам взаимодействовать друг с другом. В нашем случае API OKX — это способ для нашего софта взаимодействовать с биржей для выполнения операций, таких как вывод средств, просмотр баланса и так далее.&lt;/p&gt;
  &lt;p id=&quot;Xpou&quot;&gt;&lt;strong&gt;Пример&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;EDy3&quot;&gt;Ты приходишь в ресторан, и чтобы заказать еду, ты говоришь официанту (API), что именно тебе нужно. Ты не общаешься напрямую с кухней (биржей), а через официанта, который передает заказ. Он также доставляет твою еду (ответ от биржи) обратно к твоему столику.&lt;/p&gt;
  &lt;h2 id=&quot;IapK&quot;&gt;Получаем ключи для взаимодействия с OKX API&lt;/h2&gt;
  &lt;p id=&quot;KVOw&quot;&gt;Чтобы пользоваться OKX API нам нужно создать ключи доступа. Делается легко, просто следуй гайду ниже.&lt;/p&gt;
  &lt;p id=&quot;OrUU&quot;&gt;1. Переходим &lt;a href=&quot;https://www.okx.com/account/my-api&quot; target=&quot;_blank&quot;&gt;сюда&lt;/a&gt; и нажимаем &amp;quot;Create API key&amp;quot;.&lt;/p&gt;
  &lt;figure id=&quot;oTL3&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/7b/50/7b507cf3-e51b-43cb-b25c-a3ea121b8c62.png&quot; width=&quot;2876&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;5UUM&quot;&gt;2. Заполняем поля и в Permissions указываем все возможные разрешения, иначе наш скрипт не сможет выводить или торговать токенами. Также можете указать список разрешенных IP для взаимодействия с API. После того как все заполнили жмём на &amp;quot;Submit all&amp;quot;.&lt;/p&gt;
  &lt;figure id=&quot;fgDo&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/87/73/87737f96-04f7-4b8a-8387-e1f1d13f6a03.png&quot; width=&quot;2544&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;oJzk&quot;&gt;3. После создания нас вернет обратно. Тут нужно нажать на кнопку &amp;quot;view&amp;quot; рядом с созданным нами API ключем.&lt;/p&gt;
  &lt;figure id=&quot;zP1D&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/60/35/6035a94d-09c9-4648-96dd-cc956407c9e5.png&quot; width=&quot;2516&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;zbxB&quot;&gt;4. Теперь необходимо сохранить API-ключ как OKX_API_KEY, Secret key как OKX_API_SECRET, а также Passphrase, который ты указывал при создании API, как OKX_API_PASSPHRASE. Эти данные будут использованы позже.&lt;/p&gt;
  &lt;figure id=&quot;khx3&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/dc/b2/dcb2363c-7102-44d3-8e52-ec90add40f03.png&quot; width=&quot;1166&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;P4sL&quot;&gt;Создаем проект и структуру файлов&lt;/h2&gt;
  &lt;p id=&quot;CUCf&quot;&gt;Приступаем к созданию нашего фундамента для софта. Создаем папку, например, okx_spreader и открываем её в VS Code или другом редакторе кода. Далее создаем следующую структуру файлов:&lt;br /&gt;&lt;/p&gt;
  &lt;figure id=&quot;PYgw&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/28/b3/28b3bc37-0d22-485a-9689-16f62eb066e3.png&quot; width=&quot;476&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;GHKO&quot;&gt;Давай разберем каждый попунктно:&lt;/p&gt;
  &lt;ul id=&quot;vNkK&quot;&gt;
    &lt;li id=&quot;0jcv&quot;&gt;&lt;strong&gt;modules&lt;/strong&gt; — директория, в которой хранятся модули для нашего скрипта, такие как &lt;code&gt;okx.py&lt;/code&gt; и &lt;code&gt;transfer.py&lt;/code&gt;. Эти модули будут реализовывать основную функциональность скрипта.&lt;/li&gt;
    &lt;li id=&quot;tK7Y&quot;&gt;&lt;strong&gt;modules/okx.py&lt;/strong&gt; — модуль, отвечающий за взаимодействие с API биржи OKX.&lt;/li&gt;
    &lt;li id=&quot;2hdC&quot;&gt;&lt;strong&gt;modules/transfer.py&lt;/strong&gt; — модуль, который управляет выводом средств. Для каждого кошелька он инициирует вывод токенов используя &lt;code&gt;okx.py&lt;/code&gt; модуль.&lt;/li&gt;
    &lt;li id=&quot;lepL&quot;&gt;&lt;strong&gt;main.py&lt;/strong&gt; — основной файл для запуска нашего софта.&lt;/li&gt;
    &lt;li id=&quot;ih5m&quot;&gt;&lt;strong&gt;recipients.txt&lt;/strong&gt; — файл, содержащий список адресов, на которые будут переводиться токены.&lt;/li&gt;
    &lt;li id=&quot;5mh5&quot;&gt;&lt;strong&gt;settings.py&lt;/strong&gt; — файл для хранения различных настроек, необходимых для работы скрипта.&lt;/li&gt;
    &lt;li id=&quot;1Adg&quot;&gt;&lt;strong&gt;utils.py&lt;/strong&gt; — файл с вспомогательными функциями, которые могут быть использованы в разных модулях проекта.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h2 id=&quot;Hp99&quot;&gt;Начинаем писать код&lt;/h2&gt;
  &lt;h3 id=&quot;dEpL&quot;&gt;settings.py&lt;/h3&gt;
  &lt;p id=&quot;h69Q&quot;&gt;Нам нужно создать отдельный конфигурационный файл, чтобы все параметры были в одном месте, и их можно было легко изменять без необходимости редактировать основной код. В этом файле мы определяем следующие параметры:&lt;/p&gt;
  &lt;ul id=&quot;w5VN&quot;&gt;
    &lt;li id=&quot;cUXj&quot;&gt;&lt;strong&gt;TRANSFER_AMOUNT_RANGE&lt;/strong&gt; — диапазон, в котором будет генерироваться сумма перевода (например, от 3 до 5). Это необходимо, чтобы сумма перевода была не фиксированной, а случайной в пределах заданного диапазона.&lt;/li&gt;
    &lt;li id=&quot;9N4F&quot;&gt;&lt;strong&gt;TRANSFER_CURRENCY&lt;/strong&gt; — тип валюты, который будем переводить, в нашем случае это &lt;strong&gt;USDT&lt;/strong&gt;.&lt;/li&gt;
    &lt;li id=&quot;wPPD&quot;&gt;&lt;strong&gt;TRANSFER_CHAIN&lt;/strong&gt; — сеть, на которую будем инициировать перевод, например, &lt;strong&gt;Arbitrum One&lt;/strong&gt;.&lt;/li&gt;
    &lt;li id=&quot;YMQH&quot;&gt;&lt;strong&gt;OKX_API_KEY, OKX_API_SECRET, OKX_API_PASSPHRASE&lt;/strong&gt; — это параметры для аутентификации при работе с API биржи OKX. Помнишь я тебя попросил сохранить данные под определенным неймингом? Самое время будет их заполнить.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;HEi6&quot;&gt;Конфигурация хранится отдельно, чтобы избежать повторного написания одинаковых данных в разных местах кода.&lt;/p&gt;
  &lt;pre id=&quot;z7yy&quot; data-lang=&quot;python&quot;&gt;# transfer settings
TRANSFER_AMOUNT_RANGE = [3, 5]  # диапазон суммы перевода с OKX на кошелек
TRANSFER_CURRENCY = &amp;quot;USDT&amp;quot;  # токен для перевода (как записано на OKX)
TRANSFER_CHAIN = &amp;quot;Arbitrum One&amp;quot;  # сеть куда перевести (как записано на OKX)

# exchange settings
OKX_API_KEY = &amp;quot;your_okx_api_key&amp;quot;
OKX_API_SECRET = &amp;quot;your_okx_api_secret&amp;quot;
OKX_API_PASSPHRASE = &amp;quot;your_okx_api_passphrase&amp;quot;&lt;/pre&gt;
  &lt;h3 id=&quot;u6gX&quot;&gt;main.py&lt;/h3&gt;
  &lt;p id=&quot;Abv7&quot;&gt;Основной файл, он будет работать с вводом пользователя и запускать нужный нам модуль.&lt;/p&gt;
  &lt;p id=&quot;Qpf9&quot;&gt;Нам нужно спросить пользователя, хочет ли он начать процесс перевода. Если ответ положительный (пользователь вводит &amp;quot;YES&amp;quot; или &amp;quot;Y&amp;quot; в любом регистре), то запускается функция, которая отвечает за переводы. Если же пользователь отказывается или вводит что-то иное, программа завершится.&lt;/p&gt;
  &lt;pre id=&quot;VDS0&quot; data-lang=&quot;python&quot;&gt;from modules.transfer import start_transfer

def main():
    # Спрашиваем пользователя, хочет ли он начать раскидку баланса и сохраняем ответ в переменную choice
    choice = input(&amp;quot;Начать раскидку баланса? [Y/N]: &amp;quot;)

    # Если пользователь ответил &amp;quot;YES&amp;quot; или &amp;quot;Y&amp;quot; (в любом регистре), то запускаем функцию start_transfer
    if choice.upper() in [&amp;quot;YES&amp;quot;, &amp;quot;Y&amp;quot;]:
        start_transfer()
    else:
        print(&amp;quot;Выход...&amp;quot;)
        exit()


if __name__ == &amp;quot;__main__&amp;quot;:
    main()&lt;/pre&gt;
  &lt;p id=&quot;teSE&quot;&gt;&lt;strong&gt;Пояснение к коду:&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;9dSd&quot;&gt;&lt;strong&gt;1. Импорт функции &lt;code&gt;start_transfer&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre id=&quot;raqU&quot; data-lang=&quot;python&quot;&gt;from modules.transfer import start_transfer&lt;/pre&gt;
  &lt;p id=&quot;VIjs&quot;&gt;Эта строка импортирует функцию &lt;code&gt;start_transfer&lt;/code&gt; из модуля &lt;code&gt;transfer&lt;/code&gt;, расположенного в папке &lt;code&gt;modules&lt;/code&gt;. Функция &lt;code&gt;start_transfer&lt;/code&gt; будет использоваться для страта вывода токенов с OKX на кошельки, указанные в файле &lt;code&gt;recipients.txt&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;5N50&quot;&gt;&lt;strong&gt;2. Определение функции &lt;code&gt;main&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre id=&quot;mexL&quot; data-lang=&quot;python&quot;&gt;def main():&lt;/pre&gt;
  &lt;p id=&quot;HcTz&quot;&gt;Функция &lt;code&gt;main&lt;/code&gt; — это точка входа в вашу программу. Она будет управлять основным процессом взаимодействия с пользователем.&lt;/p&gt;
  &lt;p id=&quot;Pp6f&quot;&gt;&lt;strong&gt;3. Получение ввода от пользователя&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre id=&quot;cM6Z&quot; data-lang=&quot;python&quot;&gt;choice = input(&amp;quot;Начать раскидку баланса? [Y/N]: &amp;quot;)&lt;/pre&gt;
  &lt;p id=&quot;aimN&quot;&gt;Здесь мы просим пользователя ввести, хочет ли он начать процесс распределения баланса, и сохраняем его ответ в переменной &lt;code&gt;choice&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;UxCB&quot;&gt;&lt;strong&gt;4. Проверка ввода пользователя&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre id=&quot;8Rn6&quot; data-lang=&quot;python&quot;&gt;if choice.upper() in [&amp;quot;YES&amp;quot;, &amp;quot;Y&amp;quot;]:&lt;/pre&gt;
  &lt;p id=&quot;41W3&quot;&gt;Мы проверяем, ввел ли пользователь &amp;quot;YES&amp;quot; или &amp;quot;Y&amp;quot;, используя метод &lt;code&gt;upper()&lt;/code&gt; для преобразования ввода в верхний регистр. Это делает проверку нечувствительной к регистру. Вместо нескольких отдельных условий, мы просто проверяем, содержится ли преобразованный ввод в списке &lt;code&gt;[&amp;quot;YES&amp;quot;, &amp;quot;Y&amp;quot;]&lt;/code&gt;. Например, если пользователь ввел &amp;quot;yes&amp;quot;, метод &lt;code&gt;upper()&lt;/code&gt; преобразует его в &amp;quot;YES&amp;quot;, который присутствует в списке. Таким образом, условие выполняется, и мы попадаем внутрь блока &lt;code&gt;if&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;sVdC&quot;&gt;&lt;strong&gt;5. Вызов функции &lt;code&gt;start_transfer&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;
  &lt;p id=&quot;6XrT&quot;&gt;Если пользователь ввел &amp;quot;YES&amp;quot; или &amp;quot;Y&amp;quot;, мы вызываем функцию &lt;code&gt;start_transfer&lt;/code&gt;, чтобы начать процесс распределения баланса.&lt;/p&gt;
  &lt;pre id=&quot;LXz9&quot; data-lang=&quot;python&quot;&gt;start_transfer()&lt;/pre&gt;
  &lt;p id=&quot;hlSk&quot;&gt;&lt;strong&gt;6. Обработка другого ввода&lt;/strong&gt;:&lt;/p&gt;
  &lt;p id=&quot;6iVB&quot;&gt;Если пользователь ввел что-то другое, не &amp;quot;YES&amp;quot; или &amp;quot;Y&amp;quot;, то мы выводим сообщение &amp;quot;Выход...&amp;quot; и завершаем программу с помощью стандартной функции &lt;code&gt;exit()&lt;/code&gt;.&lt;/p&gt;
  &lt;pre id=&quot;OzcR&quot; data-lang=&quot;python&quot;&gt;else:
    print(&amp;quot;Выход...&amp;quot;)
    exit()&lt;/pre&gt;
  &lt;p id=&quot;HtCj&quot;&gt;&lt;strong&gt;7. Запуск функции &lt;code&gt;main&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;
  &lt;p id=&quot;F6Go&quot;&gt;В конце добавляется проверка, чтобы убедиться, что этот код выполняется только при непосредственном запуске файла, а не при его импорте как модуля. То есть, если файл запускается командой &lt;code&gt;python main.py&lt;/code&gt;, а не импортируется через &lt;code&gt;import main.py&lt;/code&gt;. Если условие выполняется, вызывается функция &lt;code&gt;main&lt;/code&gt;&lt;/p&gt;
  &lt;pre id=&quot;IcrS&quot; data-lang=&quot;python&quot;&gt;if __name__ == &amp;quot;__main__&amp;quot;:
    main()&lt;/pre&gt;
  &lt;h3 id=&quot;RtGd&quot;&gt;modules/transfer.py&lt;/h3&gt;
  &lt;p id=&quot;PBsr&quot;&gt;Этот файл отвечает за сам процесс перевода средств. Мы будем читать список получателей (адресов кошельков) из файла &lt;code&gt;recipients.txt&lt;/code&gt;. Для каждого получателя вызываем функцию &lt;code&gt;withdraw()&lt;/code&gt;, которая выполнит перевод на конкретный кошелек через OKX API.&lt;/p&gt;
  &lt;p id=&quot;mieq&quot;&gt;Таким образом, основной логикой будет являться итерация по списку адресов и вызов функции перевода.&lt;/p&gt;
  &lt;pre id=&quot;tHPD&quot; data-lang=&quot;python&quot;&gt;from modules.okx import withdraw

def start_transfer():
    with open(&amp;quot;recipients.txt&amp;quot;, &amp;quot;r&amp;quot;) as file:
        recipients = file.readlines()
    
    for recipient in recipients:
        withdraw(recipient.strip())&lt;/pre&gt;
  &lt;p id=&quot;68zV&quot;&gt;&lt;strong&gt;Пояснение к коду:&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;xLp3&quot;&gt;&lt;strong&gt;1. Импорт функции &lt;code&gt;withdraw&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;
  &lt;p id=&quot;d2gh&quot;&gt;Сначала мы импортируем функцию &lt;code&gt;withdraw&lt;/code&gt; из модуля &lt;code&gt;okx.py&lt;/code&gt;. Эта функция будет использоваться для выполнения вывода средств на указанные адреса используя функцию &lt;code&gt;withdraw&lt;/code&gt; из &lt;code&gt;okx.py&lt;/code&gt;&lt;/p&gt;
  &lt;pre id=&quot;mQOl&quot; data-lang=&quot;python&quot;&gt;from modules.okx import withdraw&lt;/pre&gt;
  &lt;p id=&quot;4cFP&quot;&gt;&lt;strong&gt;2. Определение функции &lt;code&gt;start_transfer&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;
  &lt;p id=&quot;6cR9&quot;&gt;Мы создаем функцию &lt;code&gt;start_transfer&lt;/code&gt;, которая будет отвечать за чтение списка адресов и вызов функции &lt;code&gt;withdraw&lt;/code&gt; для каждого из них.&lt;/p&gt;
  &lt;pre id=&quot;SH9z&quot; data-lang=&quot;python&quot;&gt;def start_transfer():&lt;/pre&gt;
  &lt;p id=&quot;JvtX&quot;&gt;&lt;strong&gt;3. Чтение файла с адресами&lt;/strong&gt;:&lt;/p&gt;
  &lt;p id=&quot;Ez0V&quot;&gt;Мы используем контекстный менеджер &lt;code&gt;with&lt;/code&gt;, чтобы открыть файл &lt;code&gt;recipients.txt&lt;/code&gt; для чтения. Контекстный менеджер гарантирует, что файл будет закрыт автоматически, как только выполнение выйдет из блока &lt;code&gt;with&lt;/code&gt;, независимо от того, произошла ли ошибка в процессе работы с файлом. Это делает код более безопасным и удобным, так как не нужно вручную закрывать файл.&lt;/p&gt;
  &lt;p id=&quot;pytj&quot;&gt;Функция &lt;code&gt;open&lt;/code&gt; используется для открытия файла. Она принимает два аргумента. Первый — это путь к файлу. В нашем случае файл называется &lt;code&gt;recipients.txt&lt;/code&gt; и находится в той же папке, что и скрипт, поэтому достаточно указать только имя файла. Второй аргумент — это режим открытия файла. В данном случае мы используем &lt;code&gt;&amp;quot;r&amp;quot;&lt;/code&gt;, что означает режим чтения (read). Функция &lt;code&gt;open&lt;/code&gt; возвращает объект файла, который мы сохраняем в переменной &lt;code&gt;file&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;8KID&quot;&gt;Файл &lt;code&gt;recipients.txt&lt;/code&gt; должен содержать список адресов получателей, где каждый адрес находится на новой строке. Мы считываем все строки файла с помощью метода &lt;code&gt;readlines()&lt;/code&gt;, который возвращает список, где каждая строка файла становится отдельным элементом списка.&lt;/p&gt;
  &lt;pre id=&quot;crdy&quot; data-lang=&quot;python&quot;&gt;with open(&amp;quot;recipients.txt&amp;quot;, &amp;quot;r&amp;quot;) as file:
    recipients = file.readlines()&lt;/pre&gt;
  &lt;p id=&quot;OxmW&quot;&gt;&lt;strong&gt;4. Цикл по списку адресов:&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;5TjN&quot;&gt;Мы перебираем все адреса из списка &lt;code&gt;recipients&lt;/code&gt; с помощью цикла &lt;code&gt;for&lt;/code&gt;. Для каждого адреса вызываем функцию &lt;code&gt;withdraw&lt;/code&gt;, передавая ей в качестве аргумента адрес получателя. Перед этим мы убираем из адреса лишние пробелы и символы новой строки (&lt;code&gt;\n&lt;/code&gt;) с помощью метода &lt;code&gt;strip()&lt;/code&gt;, чтобы убедиться, что передаем только саму строку адреса без ненужных символов.&lt;/p&gt;
  &lt;pre id=&quot;CQb7&quot; data-lang=&quot;python&quot;&gt;for recipient in recipients:
    withdraw(recipient.strip())&lt;/pre&gt;
  &lt;h3 id=&quot;9k6F&quot;&gt;modules/okx.py&lt;/h3&gt;
  &lt;p id=&quot;O6Wp&quot;&gt;Теперь перейдем к самой сложной части — разберем логику взаимодействия с API OKX для вывода средств на кошелек. Дальше будут термины, которые могут быть не совсем понятны, но не переживай, мы все подробно объясним в пояснении.&lt;/p&gt;
  &lt;p id=&quot;k6bZ&quot;&gt;Этот модуль отвечает за выполнение перевода средств через API OKX. В функции &lt;code&gt;withdraw()&lt;/code&gt; мы формируем HTTP-запрос с нужными параметрами для перевода. Важным моментом является рандомизация суммы перевода из диапазона, который мы указали в конфигурационном файле.&lt;/p&gt;
  &lt;p id=&quot;a4vv&quot;&gt;Каждый запрос к API требует подписи для безопасности, поэтому мы используем алгоритм HMAC для генерации подписи (как того требует OKX API), которая затем будет добавлена в заголовки запроса.&lt;/p&gt;
  &lt;p id=&quot;Z5ij&quot;&gt;Функция &lt;code&gt;withdraw()&lt;/code&gt;:&lt;/p&gt;
  &lt;ul id=&quot;adwh&quot;&gt;
    &lt;li id=&quot;6QzK&quot;&gt;Вычисляет случайную сумму для перевода.&lt;/li&gt;
    &lt;li id=&quot;8poo&quot;&gt;Формирует тело запроса с нужными параметрами: валютой, суммой, сетью, адресом получателя и другими данными.&lt;/li&gt;
    &lt;li id=&quot;4yZU&quot;&gt;Подписывает запрос с помощью вспомогательной функции &lt;code&gt;sign_request()&lt;/code&gt;.&lt;/li&gt;
    &lt;li id=&quot;v0qv&quot;&gt;Отправляет запрос на сервер API OKX и выводит сообщение об успешности перевода.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;pre id=&quot;r11D&quot; data-lang=&quot;python&quot;&gt;import json
import random
import requests
from settings import (
    OKX_API_KEY,
    OKX_API_PASSPHRASE,
    TRANSFER_AMOUNT_RANGE,
    TRANSFER_CHAIN,
    TRANSFER_CURRENCY,
)
from utils import sign_request

OKX_BASE_API_URL = &amp;quot;https://www.okx.com&amp;quot;  # базовый URL для запросов к API OKX

def withdraw(recipient: str):
    method = &amp;quot;POST&amp;quot;
    request_path = &amp;quot;/api/v5/asset/withdrawal&amp;quot;

    amount_to_transfer = random.uniform(
        TRANSFER_AMOUNT_RANGE[0], TRANSFER_AMOUNT_RANGE[1]
    )

    body = {
        &amp;quot;ccy&amp;quot;: TRANSFER_CURRENCY,
        &amp;quot;amt&amp;quot;: str(amount_to_transfer),
        &amp;quot;dest&amp;quot;: &amp;quot;4&amp;quot;,  # 4 - кошелек, 3 - биржа
        &amp;quot;chain&amp;quot;: f&amp;quot;{TRANSFER_CURRENCY}-{TRANSFER_CHAIN}&amp;quot;,
        &amp;quot;toAddr&amp;quot;: recipient,
        &amp;quot;walletType&amp;quot;: &amp;quot;private&amp;quot;,
    }

    timestamp, base64_signature = sign_request(
        method=method, request_path=request_path, body=json.dumps(body)
    )

    headers = {
        &amp;quot;OK-ACCESS-KEY&amp;quot;: OKX_API_KEY,
        &amp;quot;OK-ACCESS-SIGN&amp;quot;: base64_signature,
        &amp;quot;OK-ACCESS-PASSPHRASE&amp;quot;: OKX_API_PASSPHRASE,
        &amp;quot;OK-ACCESS-TIMESTAMP&amp;quot;: timestamp,
    }

    response = requests.request(
        method=method,
        url=OKX_BASE_API_URL + request_path,
        headers=headers,
        json=body,
    )

    response_data = response.json()

    if response_data.get(&amp;quot;code&amp;quot;, &amp;quot;&amp;quot;) == &amp;quot;0&amp;quot;:
        print(
            f&amp;quot;Инициировал перевод | {amount_to_transfer} {TRANSFER_CURRENCY} | {recipient}&amp;quot;
        )
    else:
        print(f&amp;quot;Не удалось инициировать перевод | {response_data.get(&amp;#x27;msg&amp;#x27;, &amp;#x27;No message provided&amp;#x27;)}&amp;quot;)

    return response_data&lt;/pre&gt;
  &lt;p id=&quot;lxyz&quot;&gt;&lt;strong&gt;Пояснение:&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;iOcM&quot;&gt;На данном этапе у тебя, вероятно, возникло множество вопросов, так что давай разберемся по порядку.&lt;/p&gt;
  &lt;p id=&quot;0Dn6&quot;&gt;&lt;strong&gt;Откуда мы знаем, куда и как обращаться к OKX API?&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;zcBM&quot;&gt;У любого качественного API есть документация, и у OKX она тоже есть. Вот &lt;a href=&quot;https://www.okx.com/docs-v5/en/#funding-account-rest-api-withdrawal&quot; target=&quot;_blank&quot;&gt;тут&lt;/a&gt; можно посмотреть как использовать их API для вывода средств.&lt;/p&gt;
  &lt;p id=&quot;8xb4&quot;&gt;&lt;strong&gt;Что такое HTTP?&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;SIRi&quot;&gt;&lt;strong&gt;HTTP&lt;/strong&gt; — протокол, который используется для обмена данными в интернете. Когда мы отправляем запрос к серверу, мы зачастую используем HTTP, чтобы попросить сервер выполнить какую-то задачу, например, вывести средства на кошелек. Существуют и другие протоколы общения в сети, но сегодня не об этом.&lt;/p&gt;
  &lt;p id=&quot;DCnJ&quot;&gt;&lt;strong&gt;Что такое HMAC и зачем нужно подписывать запросы?&lt;/strong&gt;&lt;/p&gt;
  &lt;ol id=&quot;nnp9&quot;&gt;
    &lt;li id=&quot;D4AX&quot;&gt;&lt;strong&gt;Для безопасности.&lt;/strong&gt; Подпись запроса помогает убедиться, что никто не подменил данные, которые ты отправляешь на сервер. Без подписи кто-то мог бы изменить твой запрос и, например, перевести деньги на свой кошелек. Подпись защищает от этого.&lt;/li&gt;
    &lt;li id=&quot;jzK7&quot;&gt;&lt;strong&gt;Требование API OKX.&lt;/strong&gt; OKX требует, чтобы все запросы были подписаны. Если запрос не подписан, API просто отклонит его. В &lt;a href=&quot;https://www.okx.com/docs-v5/en/#overview-rest-authentication&quot; target=&quot;_blank&quot;&gt;документации OKX&lt;/a&gt; подробно объясняется, как правильно подписывать запросы, чтобы сервер принял их.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;Kdf8&quot;&gt;&lt;strong&gt;HMAC&lt;/strong&gt; — метод, с помощью которого мы создаем подпись для наших запросов. Он использует специальный секретный ключ и алгоритм, который помогает создать уникальную &amp;quot;отпечаток&amp;quot; данных запроса, чтобы сервер знал, что запрос действительно пришел от тебя и не был изменен.&lt;/p&gt;
  &lt;p id=&quot;LoIy&quot;&gt;&lt;strong&gt;Пояснение к коду:&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;AUga&quot;&gt;&lt;strong&gt;1. Импорт необходимых библиотек и настроек&lt;/strong&gt;:&lt;/p&gt;
  &lt;p id=&quot;jBx1&quot;&gt;Мы импортируем стандартные библиотеки &lt;code&gt;json&lt;/code&gt;, &lt;code&gt;random&lt;/code&gt; и &lt;code&gt;requests&lt;/code&gt; для работы с JSON-данными, генерации случайных чисел и отправки HTTP-запросов, соответственно. Также импортируем несколько настроек из файла &lt;code&gt;settings.py&lt;/code&gt;, таких как ключи для API, диапазон сумм для перевода, сеть и валюту. И из файла &lt;code&gt;utils.py&lt;/code&gt; импортируется функция &lt;code&gt;sign_request&lt;/code&gt;, которая используется для создания подписи запроса.&lt;/p&gt;
  &lt;pre id=&quot;IBTC&quot; data-lang=&quot;python&quot;&gt;import json
import random
import requests
from settings import (
    OKX_API_KEY,
    OKX_API_PASSPHRASE,
    TRANSFER_AMOUNT_RANGE,
    TRANSFER_CHAIN,
    TRANSFER_CURRENCY,
)
from utils import sign_request&lt;/pre&gt;
  &lt;p id=&quot;AmjP&quot;&gt;&lt;strong&gt;2. Базовый URL для запросов к API OKX&lt;/strong&gt;:&lt;/p&gt;
  &lt;p id=&quot;Yb0z&quot;&gt;Здесь определяется базовый URL, по которому будут отправляться запросы к API биржи OKX. Если проще, то просто указываем домен OKX вместе с https схемой.&lt;/p&gt;
  &lt;pre id=&quot;2TbH&quot; data-lang=&quot;python&quot;&gt;OKX_BASE_API_URL = &amp;quot;https://www.okx.com&amp;quot;&lt;/pre&gt;
  &lt;p id=&quot;q90R&quot;&gt;&lt;strong&gt;3. Определение функции &lt;code&gt;withdraw&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;
  &lt;p id=&quot;AxAg&quot;&gt;Функция &lt;code&gt;withdraw&lt;/code&gt; принимает один аргумент — &lt;code&gt;recipient&lt;/code&gt;, который представляет собой адрес получателя перевода. Мы его передаем из &lt;code&gt;modules/transfer.py&lt;/code&gt;, если вдруг ты забыл.&lt;/p&gt;
  &lt;pre id=&quot;sGDd&quot; data-lang=&quot;python&quot;&gt;def withdraw(recipient: str):&lt;/pre&gt;
  &lt;p id=&quot;cQ2E&quot;&gt;&lt;strong&gt;4. Подготовка запроса&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre id=&quot;ZuQP&quot; data-lang=&quot;python&quot;&gt;method = &amp;quot;POST&amp;quot;
request_path = &amp;quot;/api/v5/asset/withdrawal&amp;quot;&lt;/pre&gt;
  &lt;p id=&quot;n2bC&quot;&gt;Устанавливаем метод HTTP запроса (&lt;code&gt;POST&lt;/code&gt;) и путь к API-методу для вывода средств. Мы пишем именно такие значение, так как в документации OKX API по выводу средств указан именно такое метод и данный &lt;code&gt;request_path&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;KAmi&quot;&gt;&lt;strong&gt;5. Генерация случайной суммы для перевода&lt;/strong&gt;:&lt;/p&gt;
  &lt;p id=&quot;dvdV&quot;&gt;С помощью функции &lt;code&gt;random.uniform&lt;/code&gt; генерируется случайное число с плавующей запятой в пределах диапазона, заданного в настройках &lt;code&gt;TRANSFER_AMOUNT_RANGE&lt;/code&gt;. Это будет сумма, которую мы будем выводить.&lt;/p&gt;
  &lt;pre id=&quot;r3Mh&quot; data-lang=&quot;python&quot;&gt;amount_to_transfer = random.uniform(
    TRANSFER_AMOUNT_RANGE[0], TRANSFER_AMOUNT_RANGE[1]
)&lt;/pre&gt;
  &lt;p id=&quot;KJ5a&quot;&gt;&lt;strong&gt;6. Создание тела запроса&lt;/strong&gt;:&lt;/p&gt;
  &lt;p id=&quot;Hq9G&quot;&gt;Формируем словарь &lt;code&gt;body&lt;/code&gt;, который будет передан в запросе. Здесь мы указываем валюту перевода, сумму, тип назначения (кошелек или биржа), сеть и адрес получателя.&lt;/p&gt;
  &lt;p id=&quot;dS0X&quot;&gt;Ты можешь заметить, что &lt;code&gt;&amp;quot;dest&amp;quot;&lt;/code&gt; может быть как 4, так и 3. Если бы мы хотели провести внутрибиржевый перевод, то нам понадобилось указать тут цифру 3 и вместа адреса указать email или другой индификатор OKX аккаунта.&lt;/p&gt;
  &lt;pre id=&quot;eFo5&quot; data-lang=&quot;python&quot;&gt;body = {
    &amp;quot;ccy&amp;quot;: TRANSFER_CURRENCY,
    &amp;quot;amt&amp;quot;: str(amount_to_transfer),
    &amp;quot;dest&amp;quot;: &amp;quot;4&amp;quot;,  # 4 - кошелек, 3 - биржа
    &amp;quot;chain&amp;quot;: f&amp;quot;{TRANSFER_CURRENCY}-{TRANSFER_CHAIN}&amp;quot;,
    &amp;quot;toAddr&amp;quot;: recipient,
    &amp;quot;walletType&amp;quot;: &amp;quot;private&amp;quot;,
}&lt;/pre&gt;
  &lt;p id=&quot;qzjf&quot;&gt;&lt;strong&gt;7. Создание подписи запроса&lt;/strong&gt;:&lt;/p&gt;
  &lt;p id=&quot;u85N&quot;&gt;Для безопасности запросов к API необходимо подписывать их. Мы используем функцию &lt;code&gt;sign_request&lt;/code&gt; (напишем её позже) для создания подписи. Она возвращает timestamp и signature.&lt;/p&gt;
  &lt;pre id=&quot;hslt&quot; data-lang=&quot;python&quot;&gt;timestamp, base64_signature = sign_request(
    method=method, request_path=request_path, body=json.dumps(body)
)&lt;/pre&gt;
  &lt;p id=&quot;nuyH&quot;&gt;&lt;strong&gt;8. Подготовка заголовков для запроса&lt;/strong&gt;:&lt;/p&gt;
  &lt;p id=&quot;yXhc&quot;&gt;Здесь мы формируем заголовки для HTTP-запроса, включая ключ API, подпись, passphrase и метку времени.&lt;/p&gt;
  &lt;pre id=&quot;5dnD&quot; data-lang=&quot;python&quot;&gt;headers = {
    &amp;quot;OK-ACCESS-KEY&amp;quot;: OKX_API_KEY,
    &amp;quot;OK-ACCESS-SIGN&amp;quot;: base64_signature,
    &amp;quot;OK-ACCESS-PASSPHRASE&amp;quot;: OKX_API_PASSPHRASE,
    &amp;quot;OK-ACCESS-TIMESTAMP&amp;quot;: timestamp,
}&lt;/pre&gt;
  &lt;p id=&quot;MnTr&quot;&gt;&lt;strong&gt;9. Отправка запроса&lt;/strong&gt;:&lt;/p&gt;
  &lt;p id=&quot;5mMD&quot;&gt;Мы отправляем HTTP-запрос с помощью библиотеки &lt;code&gt;requests&lt;/code&gt;, передавая метод, сформированный URL, заголовки и тело запроса.&lt;/p&gt;
  &lt;pre id=&quot;fYR3&quot; data-lang=&quot;python&quot;&gt;response = requests.request(
    method=method,
    url=OKX_BASE_API_URL + request_path,
    headers=headers,
    json=body,
)&lt;/pre&gt;
  &lt;p id=&quot;VxcI&quot;&gt;&lt;strong&gt;10. Обработка ответа&lt;/strong&gt;:&lt;/p&gt;
  &lt;p id=&quot;uJsn&quot;&gt;Полученный ответ от OKX API парсим как JSON.&lt;/p&gt;
  &lt;p id=&quot;SQff&quot;&gt;&lt;strong&gt;JSON&lt;/strong&gt; — это широко используемый формат данных для обмена информацией с API. Он универсален и совместим с большинством языков программирования, что делает его удобным для применения в различных системах.&lt;/p&gt;
  &lt;p id=&quot;hQrD&quot;&gt;Далее проверяем ответ: &lt;/p&gt;
  &lt;p id=&quot;719P&quot;&gt;Если в ответе код &amp;quot;0&amp;quot;, это означает, что перевод был успешно инициирован, и мы выводим сообщение с информацией о переводе. В противном случае выводим сообщение об ошибке.&lt;/p&gt;
  &lt;p id=&quot;0PUy&quot;&gt;Спросишь как мы узнали, что будет в ответе? Тут есть два варианта:&lt;/p&gt;
  &lt;ol id=&quot;tgIF&quot;&gt;
    &lt;li id=&quot;ACgx&quot;&gt;Выполнить запрос и запринтить сообщение&lt;/li&gt;
    &lt;li id=&quot;w8U7&quot;&gt;Подглядеть в документацию OKX API.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;pre id=&quot;z9BS&quot; data-lang=&quot;python&quot;&gt;response_data = response.json()
if response_data.get(&amp;quot;code&amp;quot;, &amp;quot;&amp;quot;) == &amp;quot;0&amp;quot;:
    print(
        f&amp;quot;Инициировал перевод | {amount_to_transfer} {TRANSFER_CURRENCY} | {recipient}&amp;quot;
    )
else:
    print(f&amp;quot;Не удалось инициировать перевод | {response_data.get(&amp;#x27;msg&amp;#x27;, &amp;#x27;No message provided&amp;#x27;)}&amp;quot;)&lt;/pre&gt;
  &lt;p id=&quot;eX1x&quot;&gt;&lt;strong&gt;11. Возврат результата&lt;/strong&gt;:&lt;/p&gt;
  &lt;p id=&quot;x7DH&quot;&gt;Функция возвращает полученные данные ответа от API, чтобы мы могли использовать их дальше, если это необходимо. В нашем случае ответ вернется обратно в &lt;code&gt;modules/transfer.py&lt;/code&gt;&lt;/p&gt;
  &lt;pre id=&quot;msI6&quot; data-lang=&quot;python&quot;&gt;return response_data&lt;/pre&gt;
  &lt;h3 id=&quot;4xUE&quot;&gt;utils.py&lt;/h3&gt;
  &lt;p id=&quot;sxkE&quot;&gt;Здесь мы распишем различные вспомогательные функции, такие как подпись запроса к OKX API или получение timestamp.&lt;/p&gt;
  &lt;pre id=&quot;3PQI&quot; data-lang=&quot;python&quot;&gt;import hmac
from base64 import b64encode
from datetime import datetime, timezone
from typing import Tuple
from settings import OKX_API_SECRET

def sign_request(method: str, request_path: str, body: str = &amp;quot;&amp;quot;) -&amp;gt; Tuple[str, str]:
    timestamp = get_iso_timestamp()
    message = timestamp + method + request_path + body
    signature = hmac.new(OKX_API_SECRET.encode(), message.encode(), &amp;quot;SHA256&amp;quot;).digest()
    base64_signature = b64encode(signature).decode()

    return timestamp, base64_signature

def get_iso_timestamp() -&amp;gt; str:
    utc_timestamp = datetime.now(timezone.utc).isoformat(timespec=&amp;quot;milliseconds&amp;quot;)
    utc_timestamp = utc_timestamp.replace(&amp;quot;+00:00&amp;quot;, &amp;quot;Z&amp;quot;)
    return utc_timestamp&lt;/pre&gt;
  &lt;p id=&quot;GLmi&quot;&gt;&lt;strong&gt;Пояснение к коду:&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;qJDa&quot;&gt;&lt;strong&gt;1. Импорт необходимых библиотек:&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;cjzP&quot;&gt;Импортируем необходимые библиотеки: &lt;code&gt;hmac&lt;/code&gt; для создания подписи к запросу для вывода, &lt;code&gt;b64encode&lt;/code&gt; для кодирования подписи в формат base64, как того требует OKX API, &lt;code&gt;datetime&lt;/code&gt; и &lt;code&gt;timezone&lt;/code&gt; для работы с текущим временем в UTC, а также &lt;code&gt;Tuple&lt;/code&gt; для аннотирования типов возвращаемых значений функции. Кроме того, из файла &lt;code&gt;settings&lt;/code&gt; загружается секретный ключ API — &lt;code&gt;OKX_API_SECRET&lt;/code&gt;, который используется для генерации подписи.&lt;/p&gt;
  &lt;pre id=&quot;ymJ3&quot; data-lang=&quot;python&quot;&gt;import hmac
from base64 import b64encode
from datetime import datetime, timezone
from typing import Tuple
from settings import OKX_API_SECRET&lt;/pre&gt;
  &lt;p id=&quot;jaD8&quot;&gt;&lt;strong&gt;2. Функция &lt;code&gt;sign_request&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;7cVI&quot;&gt;Функция &lt;code&gt;sign_request&lt;/code&gt; используется для создания подписи запроса к API OKX. Она принимает три аргумента: HTTP-метод запроса (&lt;code&gt;method&lt;/code&gt;), путь запроса (&lt;code&gt;request_path&lt;/code&gt;) и тело запроса (&lt;code&gt;body&lt;/code&gt;), которое по умолчанию пустое.&lt;/p&gt;
  &lt;pre id=&quot;Ub14&quot; data-lang=&quot;python&quot;&gt;def sign_request(method: str, request_path: str, body: str = &amp;quot;&amp;quot;) -&amp;gt; Tuple[str, str]:&lt;/pre&gt;
  &lt;p id=&quot;XNvE&quot;&gt;&lt;strong&gt;3. Получение timestamp&lt;/strong&gt;:&lt;/p&gt;
  &lt;p id=&quot;MEAO&quot;&gt;Мы вызываем функцию &lt;code&gt;get_iso_timestamp&lt;/code&gt;, чтобы получить метку времени в формате ISO и записать ответ в переменнюу timestamp.&lt;/p&gt;
  &lt;pre id=&quot;Nkfe&quot; data-lang=&quot;python&quot;&gt;timestamp = get_iso_timestamp()&lt;/pre&gt;
  &lt;p id=&quot;iQ1E&quot;&gt;&lt;strong&gt;4. Формирование сообщения для подписи&lt;/strong&gt;:&lt;/p&gt;
  &lt;p id=&quot;ndq8&quot;&gt;Для создания подписи мы формируем строку сообщения, которое включает в себя:&lt;/p&gt;
  &lt;ul id=&quot;eduW&quot;&gt;
    &lt;li id=&quot;TR6s&quot;&gt;Метку времени (&lt;code&gt;timestamp&lt;/code&gt;).&lt;/li&gt;
    &lt;li id=&quot;BTGF&quot;&gt;HTTP-метод запроса (&lt;code&gt;method&lt;/code&gt;).&lt;/li&gt;
    &lt;li id=&quot;N4ZR&quot;&gt;Путь запроса (&lt;code&gt;request_path&lt;/code&gt;).&lt;/li&gt;
    &lt;li id=&quot;IKc1&quot;&gt;Тело запроса (&lt;code&gt;body&lt;/code&gt;), которое может быть пустым.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;1lm0&quot;&gt;Это также расписано в документации OKX API&lt;/p&gt;
  &lt;pre id=&quot;mSNf&quot; data-lang=&quot;python&quot;&gt;message = timestamp + method + request_path + body&lt;/pre&gt;
  &lt;p id=&quot;zZo0&quot;&gt;&lt;strong&gt;5. Создание подписи с помощью HMAC&lt;/strong&gt;:&lt;/p&gt;
  &lt;p id=&quot;duoV&quot;&gt;Мы используем алгоритм HMAC с SHA256 для создания хэш-значения подписи. Хэш создается с использованием секретного ключа API (&lt;code&gt;OKX_API_SECRET&lt;/code&gt;) и строки &lt;code&gt;message&lt;/code&gt;, которую мы сформировали ранее.&lt;/p&gt;
  &lt;p id=&quot;Oj4g&quot;&gt;Для обеих переменных — &lt;code&gt;OKX_API_SECRET&lt;/code&gt; и &lt;code&gt;message&lt;/code&gt; — применяется метод &lt;code&gt;encode()&lt;/code&gt;. Это преобразует их из строкового представления в байтовое, так как функция &lt;code&gt;hmac.new()&lt;/code&gt; требует, чтобы входные данные были в виде байтов.&lt;/p&gt;
  &lt;p id=&quot;6awq&quot;&gt;Затем создается объект HMAC с использованием метода &lt;code&gt;hmac.new()&lt;/code&gt;, где передаются:&lt;/p&gt;
  &lt;ul id=&quot;xmqp&quot;&gt;
    &lt;li id=&quot;10PA&quot;&gt;Секретный ключ (&lt;code&gt;OKX_API_SECRET.encode()&lt;/code&gt;),&lt;/li&gt;
    &lt;li id=&quot;cPdn&quot;&gt;Сообщение (&lt;code&gt;message.encode()&lt;/code&gt;),&lt;/li&gt;
    &lt;li id=&quot;dXAb&quot;&gt;Алгоритм хэширования (&lt;code&gt;&amp;quot;SHA256&amp;quot;&lt;/code&gt;).&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;MH5M&quot;&gt;Метод &lt;code&gt;.digest()&lt;/code&gt; возвращает итоговое хэш-значение подписи в виде байтов. Это значение используется для аутентификации запросов к API.&lt;/p&gt;
  &lt;pre id=&quot;hjDt&quot; data-lang=&quot;python&quot;&gt;signature = hmac.new(OKX_API_SECRET.encode(), message.encode(), &amp;quot;SHA256&amp;quot;).digest()&lt;/pre&gt;
  &lt;p id=&quot;mJgl&quot;&gt;&lt;strong&gt;6. Конвертация подписи в формат base64&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;KFJa&quot;&gt;После того как мы подписали наш запрос, мы конвертируем это в формат base64 для передачи в заголовках HTTP-запроса.&lt;/p&gt;
  &lt;p id=&quot;PAG8&quot;&gt;&lt;strong&gt;BASE64&lt;/strong&gt; — это способ кодирования строки, но не шифрования. То есть, любой текст, закодированный в base64, можно легко расшифровать. Этот формат используется исключительно для удобства представления данных.&lt;/p&gt;
  &lt;pre id=&quot;6tGz&quot; data-lang=&quot;python&quot;&gt;base64_signature = b64encode(signature).decode()&lt;/pre&gt;
  &lt;p id=&quot;uvRE&quot;&gt;&lt;strong&gt;7. Возврат timestamp и подписи&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;2bX2&quot;&gt;Функция возвращает два значения: временную метку и подпись в формате base64.&lt;/p&gt;
  &lt;pre id=&quot;VkRX&quot; data-lang=&quot;python&quot;&gt;return timestamp, base64_signature&lt;/pre&gt;
  &lt;p id=&quot;GgGP&quot;&gt;&lt;strong&gt;8. Определение функции &lt;code&gt;get_iso_timestamp&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;v7ed&quot;&gt;Эта функция получает текущее время в формате ISO 8601. Мы используем &lt;code&gt;datetime.now(timezone.utc)&lt;/code&gt; для получения текущего времени в UTC. Затем, с помощью метода &lt;code&gt;isoformat(timespec=&amp;quot;milliseconds&amp;quot;)&lt;/code&gt;, мы получаем строку с точностью до миллисекунд. В конце заменяем строку &amp;quot;+00:00&amp;quot; на &amp;quot;Z&amp;quot;, чтобы привести метку времени к стандарту ISO 8601, который используется в OKX API.&lt;/p&gt;
  &lt;pre id=&quot;l5Ma&quot; data-lang=&quot;python&quot;&gt;def get_iso_timestamp() -&amp;gt; str:
    utc_timestamp = datetime.now(timezone.utc).isoformat(timespec=&amp;quot;milliseconds&amp;quot;)
    utc_timestamp = utc_timestamp.replace(&amp;quot;+00:00&amp;quot;, &amp;quot;Z&amp;quot;)
    return utc_timestamp&lt;/pre&gt;
  &lt;h2 id=&quot;rFG1&quot;&gt;Подготовка и запуск скрипта&lt;/h2&gt;
  &lt;p id=&quot;CYMx&quot;&gt;Окей, мы написали полностью код, теперь нам нужно сделать необходимую подготовку для его запуска. &lt;/p&gt;
  &lt;p id=&quot;Ah98&quot;&gt;&lt;strong&gt;1. Создаем виртуальное окружение.&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;Jtb4&quot; data-lang=&quot;shell&quot;&gt;python -m venv .venv&lt;/pre&gt;
  &lt;p id=&quot;dcu5&quot;&gt;Далее нам нужно активировать его&lt;/p&gt;
  &lt;pre id=&quot;3I6V&quot;&gt;.venv\Scripts\activate&lt;/pre&gt;
  &lt;p id=&quot;pZfz&quot;&gt;Готово, теперь у нас есть изолированное Python окружение для работы с написанным скриптом.&lt;/p&gt;
  &lt;p id=&quot;vdes&quot;&gt;&lt;strong&gt;2. Устанавливаем необходимые зависимости&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;FCuo&quot;&gt;Мы использовали в основном стандартные Python библиотеки, правда одна одна сторонняя все же есть. Это requests, она используется для выполнения HTTP запросов, давай её установим.&lt;/p&gt;
  &lt;pre id=&quot;Hpfc&quot; data-lang=&quot;shell&quot;&gt;pip install requests&lt;/pre&gt;
  &lt;p id=&quot;SEAC&quot;&gt;&lt;strong&gt;3. Указываем адреса в recipients.txt&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;3G9v&quot;&gt;Тут все просто, берем и вставляем наши адреса кошельков в recipients.txt. Каждый кошелек должен быть на новой строке.&lt;/p&gt;
  &lt;p id=&quot;WZB1&quot;&gt;&lt;strong&gt;4. Запускаем&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;KfQj&quot;&gt;Теперь мы готовы к запуску, для этого вводим следующую команду:&lt;/p&gt;
  &lt;pre id=&quot;j8VC&quot; data-lang=&quot;shell&quot;&gt;python main.py&lt;/pre&gt;
  &lt;p id=&quot;XsZ6&quot;&gt;После того как скрипт запущен он должен спросить нас, готовы ли мы начать раскидку баланса.&lt;/p&gt;
  &lt;figure id=&quot;qa1d&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/28/b1/28b10dfc-d461-49f0-bb80-e80cd8c213f2.png&quot; width=&quot;658&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;8Bji&quot;&gt;Как можно улучшить скрипт&lt;/h2&gt;
  &lt;p id=&quot;rsPY&quot;&gt;Мы с тобой написали лишь базовый функционал, который можно расширять. Например, ты можешь добавить проверку баланса на OKX перед переводом средств или добавить ожидания выполнения транзакции.&lt;/p&gt;
  &lt;p id=&quot;3C46&quot;&gt;Небольшие наводки, если вдруг тебе станет это интересно:&lt;/p&gt;
  &lt;ol id=&quot;Rmbp&quot;&gt;
    &lt;li id=&quot;zNmx&quot;&gt;Для проверки баланса можешь использовать эту &lt;a href=&quot;https://www.okx.com/docs-v5/en/#funding-account-rest-api-get-balance&quot; target=&quot;_blank&quot;&gt;ручку&lt;/a&gt;.&lt;/li&gt;
    &lt;li id=&quot;2HrD&quot;&gt;Если ты захотел добавить ожидание тразакции, то тебе понадобится вытащить из ответа Withdrawal ID (хранится в data[&amp;quot;wdId&amp;quot;]) и затем использовать эту &lt;a href=&quot;https://www.okx.com/docs-v5/en/#funding-account-rest-api-get-balance&quot; target=&quot;_blank&quot;&gt;ручку&lt;/a&gt;.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;h2 id=&quot;Wryx&quot;&gt;Заключение&lt;/h2&gt;
  &lt;p id=&quot;JPk2&quot;&gt;Надеемся, эта статья оказалась для тебя полезной и принесла много ценной информации. В процессе написания кода мы охватили множество тем, с которыми тебе предстоит столкнуться еще не раз. И, конечно, мы создали скрипт, который автоматически распределяет токены по нескольким кошелькам. Это простой, но невероятно полезный инструмент, который позволяет попробовать себя в разработке.&lt;/p&gt;
  &lt;p id=&quot;Npwy&quot;&gt;Если статья тебе понравилась, сохрани её 📋, чтобы не потерять.&lt;/p&gt;
  &lt;p id=&quot;Ej51&quot;&gt;Не забудь написать в комментариях 👇, что именно ты хотел бы увидеть в следующий раз!&lt;/p&gt;
  &lt;p id=&quot;omen&quot;&gt;&lt;a href=&quot;https://t.me/aio_study&quot; target=&quot;_blank&quot;&gt;AIO Study&lt;/a&gt; | &lt;a href=&quot;https://aiostudy.com/&quot; target=&quot;_blank&quot;&gt;Site&lt;/a&gt;&lt;/p&gt;

</content></entry><entry><id>aiostudy:OvPvQsVMhgY</id><link rel="alternate" type="text/html" href="https://teletype.in/@aiostudy/OvPvQsVMhgY?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=aiostudy"></link><title>Гайд на написание первого скрипта для самых маленьких 👶</title><published>2025-01-05T12:33:39.602Z</published><updated>2025-01-05T17:52:46.196Z</updated><summary type="html">Сегодня мы поговорим о том, как написать свой первый скрипт, даже если ты раньше никогда не писал код. Да, ты не ослышался — мы дадим тебе пошаговую инструкцию, которая поможет тебе запустить свой первый скрипт и не сломать себе голову в процессе.</summary><content type="html">
  &lt;p id=&quot;Cked&quot;&gt;Сегодня мы поговорим о том, как написать свой первый скрипт, &lt;u&gt;даже если ты раньше никогда не писал код&lt;/u&gt;. Да, ты не ослышался — &lt;strong&gt;мы дадим тебе пошаговую инструкцию&lt;/strong&gt;, которая поможет тебе запустить свой первый скрипт и не сломать себе голову в процессе.&lt;/p&gt;
  &lt;h2 id=&quot;Ya2h&quot;&gt;Оглавление&lt;/h2&gt;
  &lt;ol id=&quot;28Wj&quot;&gt;
    &lt;li id=&quot;ANkL&quot;&gt;&lt;a href=&quot;#NaxD&quot;&gt;Установка Python&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;Dx62&quot;&gt;&lt;a href=&quot;#JXvN&quot;&gt;Установка редактора кода&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;PjAb&quot;&gt;&lt;a href=&quot;#rXHk&quot;&gt;Составление плана по написанию скрипта&lt;/a&gt;&lt;/li&gt;
    &lt;li id=&quot;aHi7&quot;&gt;&lt;a href=&quot;#SEJM&quot;&gt;Написание скрипта&lt;/a&gt;&lt;/li&gt;
  &lt;/ol&gt;
  &lt;h2 id=&quot;j5wN&quot;&gt;Чему ты научишься? 🧠&lt;/h2&gt;
  &lt;p id=&quot;WW34&quot;&gt;&lt;strong&gt;1. Установишь &lt;em&gt;интерпретатор&lt;/em&gt; Python.&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;lVx4&quot;&gt;&lt;strong&gt;Интерпретатор&lt;/strong&gt; — это программа, которая читает и выполняет твой код. Без неё твой скрипт просто текст.&lt;/p&gt;
  &lt;p id=&quot;zbq4&quot;&gt;&lt;strong&gt;2. Установишь и настроишь &lt;em&gt;редактор кода&lt;/em&gt;.&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;dqCQ&quot;&gt;&lt;strong&gt;Редактор кода&lt;/strong&gt; - Это место, где ты будешь писать и тестировать свои скрипты.&lt;/p&gt;
  &lt;p id=&quot;HLUq&quot;&gt;&lt;strong&gt;3. Научишься работать с &lt;em&gt;RPC.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;jEq9&quot;&gt;&lt;strong&gt;RPC&lt;/strong&gt; — это способ общения с нодой Ethereum для отправки запросов, например, на создание транзакции или проверку баланса.&lt;/p&gt;
  &lt;p id=&quot;wj8G&quot;&gt;&lt;strong&gt;Нода Ethereum&lt;/strong&gt; — это компьютер, который помогает сети Ethereum работать, проверяя и сохраняя все данные о переводах и смарт-контрактах.&lt;/p&gt;
  &lt;p id=&quot;PdgL&quot;&gt;&lt;strong&gt;4. Напишешь и запустишь скрипт, который запрашивает баланс твоего EVM-кошелька в сети Ethereum.&lt;/strong&gt;&lt;/p&gt;
  &lt;h2 id=&quot;MMKl&quot;&gt;Сэтапим наше окружение для работы с кодом&lt;/h2&gt;
  &lt;h3 id=&quot;NaxD&quot;&gt;Шаг 1. Устанавливаем Python 🐍💻&lt;/h3&gt;
  &lt;p id=&quot;wuJy&quot;&gt;1. Перейди на &lt;a href=&quot;http://python.org/&quot; target=&quot;_blank&quot;&gt;сайт&lt;/a&gt; и скачай последнюю версию Python.&lt;/p&gt;
  &lt;p id=&quot;RfoW&quot;&gt;2. Запусти установщик и поставь галочку на &amp;quot;&lt;strong&gt;Add Python to PATH&lt;/strong&gt;&amp;quot; и &amp;quot;&lt;strong&gt;Use admin privileges when installing py.exe&lt;/strong&gt;&amp;quot;, далее чтобы установить нажми на &amp;quot;Install Now&amp;quot; (потребует права администратора, соглашаемся). &lt;/p&gt;
  &lt;figure id=&quot;gsGc&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/d8/7e/d87e55b3-367b-4a30-b846-f2f80c5b4b24.png&quot; width=&quot;656&quot; /&gt;
  &lt;/figure&gt;
  &lt;h3 id=&quot;JXvN&quot;&gt;Шаг 2. Устанавливаем редактор кода 🖊️🖥️&lt;/h3&gt;
  &lt;p id=&quot;fIco&quot;&gt;Для написания кода нужен текстовый редактор. Рекомендуем &lt;s&gt;Блокнот&lt;/s&gt; Visual Studio Code (VS Code) так как он стал базой для написания кода.&lt;/p&gt;
  &lt;p id=&quot;uAlm&quot;&gt;1. Скачай Visual Studio Code с &lt;a href=&quot;https://code.visualstudio.com/&quot; target=&quot;_blank&quot;&gt;официального сайта&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;xp9f&quot;&gt;2. Запусти установщик и следуй инструкциям. Можно отметить &lt;strong&gt;&amp;quot;Create desktop shortcut&amp;quot;&lt;/strong&gt;, если хочешь ярлык на рабочем столе.&lt;/p&gt;
  &lt;figure id=&quot;BjCt&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/bd/2b/bd2bd430-3eb8-47db-8d80-6e2f8d1109e9.png&quot; width=&quot;598&quot; /&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;ZgQQ&quot;&gt;3. Установи расширение &amp;quot;Python&amp;quot; для удобной работы. В VS Code слева, в меню, выбери иконку с кубами и в поиске введи &amp;quot;Python&amp;quot;. Найди и установи это расширение.&lt;/p&gt;
  &lt;figure id=&quot;6OJA&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/5b/74/5b74fcdd-c1bd-40d1-a2d5-05f584f9a03f.png&quot; width=&quot;1366&quot; /&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;gZBE&quot;&gt;Приступаем к ворку над скриптом&lt;/h2&gt;
  &lt;h3 id=&quot;rXHk&quot;&gt;&lt;strong&gt;Шаг 1. Прорабатываем действия перед написанием кода 🤔&lt;/strong&gt;&lt;/h3&gt;
  &lt;p id=&quot;j0Wn&quot;&gt;Составим план написания скрипта, для примера возьмем чекер баланса EVM-кошелька в сети Ethereum. Составить план ты можешь с ChatGPT или немного погуглив. Просто задаешь запрос по типу &amp;quot;Как получить баланс EVM-кошелька в сети Ethereum&amp;quot;.&lt;/p&gt;
  &lt;blockquote id=&quot;Rzjl&quot;&gt;Кстати, умение гуглить это еще одна база для каждого кодера 😎&lt;/blockquote&gt;
  &lt;p id=&quot;QVD9&quot;&gt;Вот что у нас вышло:&lt;/p&gt;
  &lt;p id=&quot;qTOX&quot;&gt;1. Подключиться к &lt;a href=&quot;#wj8G&quot;&gt;Ethereum-ноде&lt;/a&gt; через &lt;a href=&quot;#jEq9&quot;&gt;RPC&lt;/a&gt;.&lt;br /&gt;2. Указать адрес кошелька.&lt;br /&gt;3. Получить баланс кошелька в &lt;em&gt;Wei&lt;/em&gt; и преобразовать его в ETH.&lt;/p&gt;
  &lt;p id=&quot;KyvY&quot;&gt;&lt;strong&gt;Wei&lt;/strong&gt; — это наименьшая единица эфира, 1 ETH = 10^18 Wei.&lt;/p&gt;
  &lt;p id=&quot;exiL&quot;&gt;4. Вывести результат в удобном формате.&lt;/p&gt;
  &lt;h3 id=&quot;SEJM&quot;&gt;Шаг 2. Приступаем к написанию кода 👨‍💻&lt;/h3&gt;
  &lt;section style=&quot;background-color:hsl(hsl(55,  86%, var(--autocolor-background-lightness, 95%)), 85%, 85%);&quot;&gt;
    &lt;p id=&quot;JXS5&quot;&gt;Важно ⚠️:  Новички часто используют ChatGPT для написания кода и при этом абсолютно не понимая, что этот код делает. Однако это не значит, что вы не можете использовать его во время обучения, самое главное спрашивайте у него все, что вам не понятно. И перепроверяйте информацию, так как ChatGPT часто врет.&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;ZPZe&quot;&gt;Теперь, когда всё готово, перейдём к написанию и запуску скрипта. Написать его ты можешь вместе с ChatGPT (придерживайся памятки выше!).&lt;/p&gt;
  &lt;p id=&quot;atrG&quot;&gt;1. Создай папку с осмысленным названием&lt;/p&gt;
  &lt;p id=&quot;fYwH&quot;&gt;2. Открой её через ПКМ → &amp;quot;Open with Code&amp;quot; в VS Code&lt;/p&gt;
  &lt;p id=&quot;HY8q&quot;&gt;3. Слева создай файл main.py&lt;/p&gt;
  &lt;p id=&quot;yd0u&quot;&gt;4. Создай и активируй &lt;em&gt;виртуальное окружение&lt;/em&gt;:&lt;/p&gt;
  &lt;p id=&quot;yLMR&quot;&gt;&lt;strong&gt;Виртуальное окружение&lt;/strong&gt; - изолированная среда Python, чтобы зависимости не мешали друг другу.&lt;/p&gt;
  &lt;p id=&quot;3rvD&quot;&gt;Для создания виртуального окружение открой терминал (Ctrl + &amp;#x60;) и введи:&lt;/p&gt;
  &lt;pre id=&quot;K8C9&quot; data-lang=&quot;shell&quot;&gt;python -m venv .venv&lt;/pre&gt;
  &lt;p id=&quot;CzbQ&quot;&gt;Каждый раз после перезапуска терминала или если не видно (.venv) слева, вводи команду ниже, чтобы активировать виртуальное окружение. &lt;u&gt;Без нее будет использоваться глобальное окружение.&lt;/u&gt;&lt;/p&gt;
  &lt;figure id=&quot;3vA0&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/5d/00/5d00f071-45cc-4822-9e60-ea8e8a9125a4.png&quot; width=&quot;359&quot; /&gt;
    &lt;figcaption&gt;Пример надписи (.venv) перед приглашением терминала&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Z5iN&quot;&gt;Для активации созданного .venv открой терминал (Ctrl + &amp;#x60;) и введи:&lt;/p&gt;
  &lt;pre id=&quot;R8y5&quot; data-lang=&quot;python&quot;&gt;.venv\Scripts\activate&lt;/pre&gt;
  &lt;p id=&quot;jJQh&quot;&gt;5. Установи зависимости:&lt;/p&gt;
  &lt;p id=&quot;DTwK&quot;&gt;Открой терминал и введи:&lt;/p&gt;
  &lt;pre id=&quot;wiya&quot; data-lang=&quot;shell&quot;&gt;pip install web3&lt;/pre&gt;
  &lt;p id=&quot;p9Gb&quot;&gt;Список устанавливаемых зависимостей может отличаться от нашего примера, но если ты пишешь для EVM, то скорее всего ты будешь использовать именно эту библиотеку. Узнать что тебе нужно установить ты можешь также через ChatGPT или погуглив.&lt;/p&gt;
  &lt;p id=&quot;34ba&quot;&gt;6. Теперь открой ранее созданный &lt;strong&gt;main.py&lt;/strong&gt; и вставь написанный код:&lt;/p&gt;
  &lt;pre id=&quot;fv8v&quot; data-lang=&quot;python&quot;&gt;from web3 import Web3&lt;/pre&gt;
  &lt;pre id=&quot;Mlph&quot; data-lang=&quot;python&quot;&gt;# URL RPC для подключения к Ethereum-ноде
rpc_url = &amp;quot;https://eth.llamarpc.com&amp;quot;  # можно взять публичный RPC на https://chainlist.org/
web3 = Web3(Web3.HTTPProvider(rpc_url))&lt;/pre&gt;
  &lt;pre id=&quot;x8u3&quot; data-lang=&quot;python&quot;&gt;# Проверяем подключение
if web3.is_connected():
    print(&amp;quot;Подключение к Ethereum-ноде успешно!&amp;quot;)
else:
    print(&amp;quot;Ошибка подключения к Ethereum-ноде.&amp;quot;)
    exit()&lt;/pre&gt;
  &lt;pre id=&quot;MoXY&quot; data-lang=&quot;python&quot;&gt;# Адрес кошелька
wallet_address = web3.to_checksum_address(&amp;quot;0xYOUR_EVM_ADDRESS&amp;quot;)  # изменяем на свой адрес&lt;/pre&gt;
  &lt;pre id=&quot;peOJ&quot; data-lang=&quot;python&quot;&gt;# Получаем баланс в Wei
balance_wei = web3.eth.get_balance(wallet_address)&lt;/pre&gt;
  &lt;pre id=&quot;xmnU&quot; data-lang=&quot;python&quot;&gt;# Переводим баланс в ETH
balance_eth = web3.from_wei(balance_wei, &amp;#x27;ether&amp;#x27;)&lt;/pre&gt;
  &lt;pre id=&quot;P10c&quot; data-lang=&quot;python&quot;&gt;print(f&amp;quot;Баланс кошелька {wallet_address}: {balance_eth} ETH&amp;quot;)&lt;/pre&gt;
  &lt;p id=&quot;TCkF&quot;&gt;В этом примере тебе нужно заменить в данной строке фейк адрес на свой&lt;/p&gt;
  &lt;pre id=&quot;QEbN&quot; data-lang=&quot;python&quot;&gt;wallet_address = web3.to_checksum_address(&amp;quot;0xYOUR_EVM_ADDRESS&amp;quot;)&lt;/pre&gt;
  &lt;p id=&quot;syBQ&quot;&gt;А также, если ты хочешь, то можешь заменить RPC. Найти публичные RPC ты можешь &lt;a href=&quot;https://chainlist.org/&quot; target=&quot;_blank&quot;&gt;тут&lt;/a&gt;&lt;/p&gt;
  &lt;pre id=&quot;1RBC&quot; data-lang=&quot;python&quot;&gt;rpc_url = &amp;quot;https://eth.llamarpc.com&amp;quot;&lt;/pre&gt;
  &lt;h3 id=&quot;9QWI&quot;&gt;Шаг 3. Запуск скрипта ▶️💻&lt;/h3&gt;
  &lt;p id=&quot;Q1VF&quot;&gt;Для запуска нужно открыть терминал (не забываем про активацию виртуального окружение, если оно не активировано) и ввести команду:&lt;/p&gt;
  &lt;pre id=&quot;wDOE&quot; data-lang=&quot;shell&quot;&gt;python main.py&lt;/pre&gt;
  &lt;p id=&quot;FBGJ&quot;&gt;Если все правильно, то у тебя будет сообщение в терминале с твоим балансом ✔️&lt;/p&gt;
  &lt;figure id=&quot;WITy&quot; class=&quot;m_original&quot; data-caption-align=&quot;center&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/44/1e/441e0ef1-5df3-409a-900b-642438783f78.png&quot; width=&quot;469&quot; /&gt;
    &lt;figcaption&gt;Пример вывода в терминал при успешном выполнении&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;XGrx&quot;&gt;&lt;strong&gt;Домашка:&lt;/strong&gt;&lt;br /&gt;Попробуй сделать так, чтобы скрипт получал баланс не одного кошелька, а сразу нескольких.&lt;/p&gt;
  &lt;p id=&quot;syMy&quot;&gt;&lt;strong&gt;Подсказка:&lt;/strong&gt;&lt;br /&gt;Для этого ты можешь использовать циклы и списки/файл.&lt;/p&gt;
  &lt;p id=&quot;I8q1&quot;&gt;&lt;a href=&quot;https://t.me/aio_study&quot; target=&quot;_blank&quot;&gt;AIO Study&lt;/a&gt; | &lt;a href=&quot;https://aiostudy.com/&quot; target=&quot;_blank&quot;&gt;Site&lt;/a&gt;&lt;/p&gt;

</content></entry><entry><id>aiostudy:ZK571edaV1c</id><link rel="alternate" type="text/html" href="https://teletype.in/@aiostudy/ZK571edaV1c?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=aiostudy"></link><title>🔥 Cursor Editor: ваш новый лучший друг в кодинге 🖥️</title><published>2024-12-08T20:13:06.214Z</published><updated>2024-12-08T20:13:06.214Z</updated><summary type="html">Вы когда-нибудь мечтали писать код быстрее и с меньшим количеством ошибок? 😏 Тогда познакомьтесь с Cursor Editor — инструментом, который реально прокачает вашу разработку! 🚀</summary><content type="html">
  &lt;p id=&quot;zdPt&quot;&gt;Вы когда-нибудь мечтали писать код быстрее и с меньшим количеством ошибок? 😏 Тогда познакомьтесь с &lt;strong&gt;Cursor Editor&lt;/strong&gt; — инструментом, который реально прокачает вашу разработку! 🚀&lt;/p&gt;
  &lt;p id=&quot;6xE7&quot;&gt;&lt;strong&gt;Что такое Cursor Editor?&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;YgrE&quot;&gt;Это не просто очередной редактор кода. Cursor — ваш персональный помощник, основанный на AI (да-да, тот самый GPT-4 и другие последние модели). Он не просто подсказывает, что написать дальше, а помогает думать над кодом, генерируя фрагменты и предлагая решения. 🎯&lt;/p&gt;
  &lt;p id=&quot;RSZa&quot;&gt;&lt;strong&gt;Почему Cursor — это круто?&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;KWNN&quot;&gt;• &lt;strong&gt;Экономия времени&lt;/strong&gt;: Забудьте о рутинных задачах. Cursor может сгенерировать код по вашему описанию. Просто опишите, что нужно, и вуаля! ✨&lt;/p&gt;
  &lt;figure id=&quot;JKog&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/76/22/7622c04c-b3de-4ac8-b55b-5f85b09c21bd.png&quot; /&gt;
    &lt;figcaption&gt;Использование функции &amp;quot;Chat&amp;quot; и &amp;quot;Composer&amp;quot;, которые позволяют генерировать код по описанию.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;7Fs4&quot;&gt;• &lt;strong&gt;Меньше багов&lt;/strong&gt;: Благодаря умным подсказкам, вы реже делаете опечатки и логические ошибки. Код становится чище и стабильнее. 🧹&lt;/p&gt;
  &lt;figure id=&quot;sTbr&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/76/35/7635eb7e-0880-437e-ba75-89c2b582b20e.png&quot; width=&quot;1152&quot; /&gt;
    &lt;figcaption&gt;&amp;quot;Fix with AI&amp;quot; позволяет исправить ошибку/баг с помощью ИИ, экономя вам не один десяток минут на поиск корня проблемы и решения ее самостоятельно.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;woud&quot;&gt;• &lt;strong&gt;Быстрое прототипирование&lt;/strong&gt;: Хотите проверить идею? Cursor поможет накидать рабочий прототип &lt;u&gt;&lt;em&gt;полностью готового и рабочего продукта&lt;/em&gt;&lt;/u&gt; за считанные часы. ⏱️&lt;/p&gt;
  &lt;p id=&quot;3ljc&quot;&gt;• &lt;strong&gt;Освоение новых технологий&lt;/strong&gt;: Нет времени разбираться с новым фреймворком? Cursor подскажет, как начать. 📚&lt;/p&gt;
  &lt;p id=&quot;ri3w&quot;&gt;💼 Реальные примеры использования:&lt;/p&gt;
  &lt;p id=&quot;JLE9&quot;&gt;Пример 1:&lt;/p&gt;
  &lt;p id=&quot;5N3X&quot;&gt;&lt;a href=&quot;https://x.com/Tristan0x&quot; target=&quot;_blank&quot;&gt;@Tristan0x&lt;/a&gt; поделился &lt;a href=&quot;https://x.com/Tristan0x/status/1830102400872693985&quot; target=&quot;_blank&quot;&gt;в своем твите&lt;/a&gt;, как &lt;em&gt;Cursor Editor&lt;/em&gt; (в связке с другими AI инструментами) помог ему разработать DEX биржу без каких-либо знаний в fornt-end &amp;quot;за 1 день&amp;quot;.&lt;/p&gt;
  &lt;section&gt;
    &lt;p id=&quot;nPAi&quot;&gt;&lt;em&gt;“Сегодня днем мне удалось создать полноценный интерфейс биржи на @nextjs практически без опыта работы с фронтендом, используя сочетание cursor_ai + Claude + v0. Он даже поддерживает кошельки solana без костылей и получает данные RPC через наш собственный SDK.”&lt;/em&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;W9e3&quot;&gt;Пример 2:&lt;/p&gt;
  &lt;p id=&quot;pRul&quot;&gt;Другой пользователь, &lt;a href=&quot;https://x.com/AlexFinnX&quot; target=&quot;_blank&quot;&gt;@AlexFinnX&lt;/a&gt;, рассказал &lt;a href=&quot;https://x.com/AlexFinnX/status/1834369690275381577&quot; target=&quot;_blank&quot;&gt;в своем твите&lt;/a&gt;, как Cursor Editor помог ему быстро реализовать аналог старого доброго Марио ‼️ &lt;strong&gt;БЕЗ КАКОГО ЛИБО ОПЫТА В КОДИНГЕ&lt;/strong&gt; ‼️.&lt;/p&gt;
  &lt;section&gt;
    &lt;p id=&quot;R9r3&quot;&gt;&lt;em&gt;“Я создал полноценную игру в стиле Mario, используя всего лишь СКРИНШОТ с помощью ИИ. Я загрузил скриншот в Cursor, попросил сделать мне такую игру — и он это сделал. Посмотрите, как это происходило, в видео ниже. Теперь буквально каждый может превращать свои идеи в игры и приложения.”&lt;/em&gt;&lt;/p&gt;
  &lt;/section&gt;
  &lt;p id=&quot;GVpf&quot;&gt;&lt;strong&gt;‼️ Но есть нюанс…&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;Wnqf&quot;&gt;Важно понимать, что использование таких инструментов во время обучения (например, на &lt;strong&gt;AIO Study&lt;/strong&gt;) может сыграть злую шутку. 🤔&lt;/p&gt;
  &lt;p id=&quot;Dhha&quot;&gt;❓ &lt;strong&gt;Почему не стоит использовать AI во время обучения:&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;QNwD&quot;&gt;• &lt;strong&gt;Глубокое понимание&lt;/strong&gt;: Если за вас пишет код AI, можно упустить важные концепции и нюансы языка.&lt;/p&gt;
  &lt;p id=&quot;WgN6&quot;&gt;• &lt;strong&gt;Навык решения проблем&lt;/strong&gt;: Самостоятельное решение задач укрепляет навыки и развивает мышление.&lt;/p&gt;
  &lt;p id=&quot;L1wl&quot;&gt;• &lt;strong&gt;Критическое мышление&lt;/strong&gt;: Важно уметь находить и исправлять ошибки без помощи AI.&lt;/p&gt;
  &lt;p id=&quot;a1Wh&quot;&gt;&lt;strong&gt;👉 Рекомендация:&lt;/strong&gt; Используйте Cursor после того, как освоите основы, чтобы не навредить своему обучению.&lt;/p&gt;
  &lt;p id=&quot;SfQa&quot;&gt;&lt;strong&gt;Когда Cursor реально спасает&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;Qbdj&quot;&gt;• &lt;strong&gt;Сжатые сроки&lt;/strong&gt;: Когда дедлайн уже завтра, а работы — непочатый край. 😅&lt;/p&gt;
  &lt;p id=&quot;W7Bu&quot;&gt;• &lt;strong&gt;Прототипирование&lt;/strong&gt;: Быстро накидать идею и посмотреть, как она работает.&lt;/p&gt;
  &lt;p id=&quot;c2Pd&quot;&gt;• &lt;strong&gt;Исследование новых идей&lt;/strong&gt;: Хотите попробовать что-то новое без глубокого погружения? Cursor поможет стартовать.&lt;/p&gt;
  &lt;p id=&quot;0LX0&quot;&gt;&lt;strong&gt;💡Несколько лайфхаков по использованию Cursor&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;ij3u&quot;&gt;• &lt;strong&gt;Описание задач на естественном языке&lt;/strong&gt;: Просто пишите, что вам нужно, обычными словами, и Cursor преобразует это в код.&lt;/p&gt;
  &lt;p id=&quot;LV8L&quot;&gt;• &lt;strong&gt;Исправление ошибок&lt;/strong&gt;: Если что-то не работает, попросите Cursor найти и исправить ошибку.&lt;/p&gt;
  &lt;p id=&quot;gO0F&quot;&gt;• &lt;strong&gt;Оптимизация кода&lt;/strong&gt;: Хотите сделать код быстрее или чище? Cursor даст советы по улучшению.&lt;/p&gt;
  &lt;p id=&quot;pRzt&quot;&gt;🤓 Заключение&lt;/p&gt;
  &lt;p id=&quot;A2cS&quot;&gt;Cursor Editor — мощный инструмент, который может значительно облегчить жизнь разработчика. Но, как и с любым инструментом, важно использовать его с умом. 🧠&lt;/p&gt;
  &lt;p id=&quot;bR8N&quot;&gt;🔥 &lt;strong&gt;Хотите сами стать профи и писать код легко и быстро даже без помощи ИИ ?&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;ktPJ&quot;&gt;Присоединяйтесь к нашему курсу «Python для Web3-разработки» и получите глубокие знания и практические навыки! 🚀&lt;/p&gt;
  &lt;p id=&quot;9S8C&quot;&gt;👉 &lt;a href=&quot;https://t.me/aio_study&quot; target=&quot;_blank&quot;&gt;Присоединиться к каналу&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;pc4X&quot;&gt;👉 &lt;a href=&quot;/@hodlmod.eth/aiostudy&quot;&gt;Узнать больше о курсе&lt;/a&gt;&lt;/p&gt;

</content></entry></feed>