Я создал расширение для Chrome, чтобы мгновенно находить акции eToro в инструменте проверки акций FINVIZ
Вам больше не нужно переключаться между вкладками, чтобы увидеть, существуют ли определенные акции на eToro.
Находясь взаперти во время пандемии (как и все остальные), я создал учетную запись eToro и начал свой путь владения Rolex, Rolls Royce и Rover.
Ясно, что этого не произошло. Вот почему вы читаете мои статьи на Medium.com, а не смотрите, как я флексю в IG.
Я не только не тону в холодных наличных деньгах, но я еще и ужасный трейдер. И это то, что я пытался исправить (ужасная часть трейдера), наблюдая за гуру (Райнер Тео и Шон Декмар — мои любимые) на YouTube.
Запоем просматривая их видео, я наткнулся на FINVIZ’s Stock Screener. Это довольно крутая платформа, где вы можете отфильтровать более 8000 акций на основе различных технических факторов, что поможет вам лучше планировать свои сделки.
Но проблема в том, что некоторых из них нет на eToro, и вы этого не заметите с первого взгляда.
Таким образом, мой обычный рабочий процесс всегда будет заключаться в том, чтобы скопировать тикер, перейти к поиску eToro и вставить тикер, чтобы увидеть, доступен ли он. Если Finviz предоставит мне список из 100 акций, то мне нужно будет выполнить это действие 100 раз.
Веселье. Веселье.
Конечно, должен быть лучший способ.
Вместо того, чтобы искать инструмент, который уже делает то, что я хочу, или жаловаться на то, что его нет.
Я решил создать свой собственный инструмент с нуля.
Объем
- Создайте расширение для Chrome, которое считывает биржевые котировки из FINVIZ и передает их серверной части.
- Используйте Laravel на бэкенде для проверки значений в базе данных и возвращайте логическое значение для каждого тикера.
- Вероятно, мне нужно найти способ получить данные от eToro. Похоже, у них нет официального API. Так что найдите обходной путь для этого.
План игры
- Пишите беспорядочный код. Чем грязнее, тем лучше. Я создаю это за короткое время, и это для меня, поэтому код не должен быть должным образом структурирован. Просто нужно работать. Кроме того, держитесь подальше от сборщиков модулей, у меня нет целого дня, чтобы разобраться, как настроить Webpack.
- Ограничьте перенос тикеров на вкладку «Обзор» в FINVIZ для проверки концепции.
- Если у меня есть время, я найду способ включить в расширение функцию оплаты/выставления счетов. Сломанному мне нужно заплатить.
- Возможно, позже я смогу расширить функциональность и на CoinGecko. Рассказ на другой день. Не увлекайтесь и работайте над этим сейчас.
- Придумайте название для расширения, и найдите иконку и т.д. Сохраните это в конец. Не теряйте время заранее.
Да начнется кодирование
- Установка/настройка проекта
У Google есть очень подробное руководство по началу работы, к которому вы можете обратиться, чтобы начать работу.
Руководство - https://developer.chrome.com/docs/extensions/mv3/getstarted/
В руководстве также есть ссылка на готовый пример (кодовую базу). Я просто скачаю это и начну возиться с кодом, чтобы работать быстрее.
О, еще кое-что. Как только вы загрузите кодовую базу, вы можете загрузить ее как распакованное расширение через Chrome. Шаги описаны в том же руководстве, поэтому вы можете обратиться к нему, если хотите попробовать.
2. Выяснение кодовой базы
Согласно документации, основными файлами являются:
- manifest.json — сюда помещаются все метаданные, разрешения и т. д.
- background.js — обрабатывает события, которые действительно важны для самого расширения. Подумайте о событиях жизненного цикла. Здесь используется логика для обработки различных событий жизненного цикла.
- popup.html — в основном слой пользовательского интерфейса. Вся логика HTML и CSS для элементов пользовательского интерфейса находятся здесь. Popup.html также имеет соответствующий файл JS, и он обрабатывает логику для управления слоем пользовательского интерфейса.
- и popup.js — JS-файл для обработки событий из popup.html, а также вы можете вставлять скрипты контента и т. д.
Первый порядок действий — перейдите в manifest.json и измените имя и описание.
manifest.json
{
"name": "Finviz X eToro extension",
"description": "Show if the ticker exists on eToro",
//
}
Обратите внимание, что каждый раз, когда вы вносите изменения в manifest.json, вам нужно перейти на chrome://extensions и перезагрузить расширение.
Следующее, что я сделал, это перешел к popup.html, добавил некоторые стили к телу и добавил элемент h2. Я просто хотел посмотреть, отразятся ли изменения мгновенно — и они отразятся.
Кроме того, popup.html имеет зеленую кнопку и соответствующее событие click в файле popup.js, которое делегирует метод setPageBackgroundColor.
Я не собираюсь много менять, но добавлю console.log в каждый метод и посмотрю, как это выглядит в Chrome DevTools.
popup.js
let changeColor = document.getElementById("changeColor");
// When the button is clicked, inject setPageBackgroundColor into current page changeColor.addEventListener("click", async () => { let [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
// line that I added in console.log('button clicked');
chrome.scripting.executeScript({ target: { tabId: tab.id }, function: setPageBackgroundColor, }); });
// The body of this function will be execuetd as a content script inside the // current page function setPageBackgroundColor() {
// line that I added in console.log('setPageBackgroundColor method called.');
chrome.storage.sync.get("color", ({ color }) => { document.body.style.backgroundColor = color; }); }
Результат:
Похоже, что любой код, который я пишу внутри прослушивателя событий кнопки, отображается в инструментах разработки для расширения, а код в методе setPageBackgroundColor выполняется в инструментах разработки для браузера (страница FINVIZ).
Обе среды должны быть изолированы.
Вот что я собираюсь сделать — каждый раз, когда нажимается зеленая кнопка, я буду получать тикеры со страницы FINVIZ и выводить их в console.log в setPageBackgroundColor. А пока я собираюсь вложить в этот метод как можно больше логики.
Я даже не собираюсь переименовывать метод на этом этапе, я очистю это в конце.
3. Удаление тикеров из FINVIZ
Наверное, самая легкая часть.
Все, что мне нужно было сделать, это проверить элемент таблицы в HTML и получить класс. Оттуда выполните querySelectorAll и сопоставьте внутренний HTML.
Бум! Сделанный!
let tickers = Array.from(document.querySelectorAll('.screener-link-primary')) .map(function (tickerHtml) { return tickerHtml.innerHTML; })
console.log(tickers);
Идем дальше.
4. Отображение бегущих строк в виде списка в расширении, известном как popup.html
Это было не совсем просто.
Чтобы это сделать, мне нужно было понять, как устроены расширения Chrome.
Я прошел по следующим ссылкам:
Обзор архитектуры — https://developer.chrome.com/docs/extensions/mv3/architecture-overview/
Передача сообщений — https://developer.chrome.com/docs/extensions/mv3/messaging/
chrome.storage — https://developer.chrome.com/docs/extensions/reference/storage/
Суть его в том, что код, который вы пишете непосредственно для самого расширения, и код, который вы «вставляете» на текущую страницу, полностью изолированы. Поэтому вам нужно использовать их API обмена сообщениями для обмена данными между ними.
Вы можете прочитать ссылки выше, чтобы лучше понять, как все работает.
Вот что я сделал:
Я скопировал часть chrome.runtime.sendMessage из приведенного выше руководства по передаче сообщений и добавил ее в часть сценария контента (метод setPageBackgroundColor).
Я добавил соответствующую часть chrome.runtime.onMessage.addListener в нижней части popup.js. Также скопировано из руководства по передаче сообщений выше.
И все это работало как шарм.
метод setPageBackgroundColor, также известный как часть скрипта контента
function setPageBackgroundColor() { let tickers = Array.from(document.querySelectorAll('.screener-link-primary')) .map(function (tickerHtml) { return tickerHtml.innerHTML; })
console.log(tickers);
chrome.runtime.sendMessage({ identifier: "finvizOverviewTab", tickers: tickers }, function (response) { console.log(response.farewell); });
}
popup.js (внизу файла)
chrome.runtime.onMessage.addListener( function (request, sender, sendResponse) { console.log(sender.tab ? "from a content script:" + sender.tab.url : "from the extension"); if (request.identifier === "finvizOverviewTab") { console.log('tickers', request.tickers);
// manipulate the DOM
}
sendResponse({ farewell: "goodbye" }); } );
Результат
5. Отображение тикеров на расширении (Ошибка)
Я чувствовал, что все работает, я сделал перерыв, и я хотел отобразить бегущие строки на самом расширении и инструментах разработчика, и бац выскочила эта ошибка.
На первый взгляд это озадачило, потому что файл manifest.json имеет разрешение activeTab, поэтому я подумал, что все будет хорошо, но оказалось, что программирование так не работает.
Ошибка
Uncaught (in promise) Error: Cannot access contents of the page. Extension manifest must request permission to access the respective host.
Решение
Оказывается, вам нужен ключ host_permissions в файле manifest.json, чтобы все заработало.
"host_permissions": [
"*://finviz.com/"
],
Кажется, это делает работу.
Результат
Первая половина барьера пройдена. Теперь мне нужно разобраться с бэкендом. В этой статье я не буду подробно рассказывать о том, как работает бэкэнд. Я расскажу об этом в другом.
6. Получить данные из серверной части
На данный момент все, что мне нужно было сделать, это передать список тикеров со страницы на сервер через HTTP-вызов, получить ответ JSON и обработать его соответствующим образом.
Для простоты я преобразовал массив тикеров в строку следующим образом:
let tickerString = tickers.join('|');
а затем добавил это к URL-адресу. Я использовал API-интерфейс fetch для выполнения HTTP-вызова серверной части:
let results = await fetch('<https://example-backend.test/check-tickers-status?tickers=>' + tickerString) .then(response => response.json()) .then(response => response.data);
console.log(results);
Затем серверная часть вернет объект со всеми тикерами и соответствующим логическим значением. Я просто отобразил эти значения во всплывающем окне.
Результат
7. Выделение текста на экране
Теперь здорово, что я могу четко видеть тикеры, которые есть на eToro, во всплывающем окне самого расширения, но я также хотел выделить элементы на странице FINVIZ.
Вот как я это сделал — я скопировал этот фрагмент кода из Руководства по обмену сообщениями выше.
И я отредактировал это так:
chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
chrome.tabs.sendMessage(tabs[0].id, {
'identifier': 'tickerResults',
'results': results
}, function (response) {
console.log(response.farewell);
});
});
И в методе setPageBackgroundColor (скрипт содержимого) я добавил прослушиватель для обработки сообщения:
chrome.runtime.onMessage.addListener( function (request, sender, sendResponse) { console.log(sender.tab ? "from a content script:" + sender.tab.url : "from the extension"); if (request.identifier === "tickerResults") { console.log('received the ticker results from the extension', request.results);
// update the dom } sendResponse({ 'farewell': "goodbye" }); } );
Результат
Последнее, что нужно сделать, чтобы закрыть это, — это взять результаты, которые были переданы из расширения в скрипт содержимого, а затем обновить DOM.
Вот как я это сделал:
let tickerResultsFromEtoro = request.results;
let tickersHtmlElements = Array.from(document.querySelectorAll('.screener-link-primary'));
let tickers = tickersHtmlElements.map(function (tickerHtml) { return tickerHtml.innerHTML; })
for (let key in tickerResultsFromEtoro) { if (tickerResultsFromEtoro[key]) { let element = tickersHtmlElements[tickers.indexOf(key)]; element.parentElement.parentElement.style.background = '#c6ddc6';
let thirdCol = element.parentElement.parentElement.children[2];
thirdCol.innerHTML = thirdCol.innerHTML + `<a href="<https://www.etoro.com/markets/${key}>" target="__blank" class="screener-link-primary" style="float:right;">Open on eToro</a>` } }
Результат
Позвольте мне добавить немного базового CSS и сделать popup.js немного лучше.
Большой! Оно работает.
Теперь я могу быстро увидеть, какие тикеры доступны на eToro, а какие нет. Я просто сэкономил себе много времени и сил.
Впечатленный.
Опыт разработчиков
Если вы знаете ванильный JS, это должно быть легко.
В противном случае у вас могут возникнуть проблемы с пониманием вещей. Но хорошо здесь то, что документация на месте. Просто следуйте руководству по началу работы, и вы сможете начать работу без проблем.
Еще мне понравилось то, что мне не нужно было устанавливать кучу разных инструментов или пакетов. Я мог бы просто загрузить кодовую базу и запустить расширение Chrome в браузере.
Я обязательно создам больше расширений для Chrome, которые смогу использовать сам. Вам тоже стоит попробовать!
Что дальше?
Текущая версия расширения Finviz X eToro довольно проста. Я могу сделать его лучше, и вот над чем я буду работать на этой неделе, чтобы сделать его лучше:
- Добавьте проверку разрешений на background.js, чтобы сделать расширение активным только тогда, когда пользователь находится на Finviz.com.
- Используйте API хранилища для хранения предыдущих результатов, чтобы расширение не было пустым при каждом нажатии на него.
- Поработайте над CSS и сделайте расширение доступным для отправки.
- Можно подумать о включении бизнес-модели в расширение. Думая Х нет. бесплатных сканирований, а затем они должны заплатить, чтобы использовать его для дополнительных сканирований. Давайте посмотрим.
Как насчет бэкенда?
Ну, большая часть логики для этого расширения Chrome обрабатывается на бэкэнде. У eToro нет официального API, поэтому мне пришлось искать обходной путь, чтобы получить данные от eToro. Как только я получил эти данные, я просто использовал Laravel для обработки входящих HTTP-запросов от расширения Chrome.
Хотите узнать больше о том, как я построил бэкенд?
Следуйте за мной на Medium.com, и как только мы наберем 100 подписчиков, я опубликую подробное руководство о том, как я настроил и запустил серверную часть.
Также читайте: я впервые попытался автоматизировать свои файлы и папки с помощью PHP
Дополнительные материалы на PlainEnglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter и LinkedIn. Посетите наш Community Discord и присоединитесь к нашему Коллективу талантов.