Пишем собственный лапшесниматель

Инструмент для защиты ума от пропаганды, контрпропаганды, инфобизнеса и лжепсихологов.

Пишем собственный лапшесниматель

В интернете много информации, которая может навредить вам и вашим близким: пропаганда и контрпропаганда, курсы волшебного инвестирования и бинарные опционы; теории заговора и психонавтика. Вы умные и видите манипуляции насквозь, но как насчёт ваших друзей, знакомых и особенно — детей? 

Сегодня мы заложим основу для продукта, который поможет если не положить конец манипуляциям, то хотя бы усложнить работу манипуляторов. Дальше будем развивать продукт — подписывайтесь на нас в Телеграме, чтобы не пропустить. 

Что делаем

Мы отберём слова, которые наиболее характерны для мошенников, провокаторов, пропагандистов и манипуляторов. Далее напишем скрипт, который подсветит на странице эти слова в разных формах. Когда вы будете запускать этот скрипт на других страницах, он будет подсвечивать все опасные слова и обращать на них внимание. Читатель будет видеть, что им манипулируют, и примет взвешенное решение, что делать дальше. 

Чтобы было проще тестировать и отлаживать скрипт, мы заранее напишем текст и будем вызывать скрипт на этой же странице. Дальше мы придумаем, как перенести это на любую другую страницу в интернете.

Инструменты

Правило хорошего программиста — используй свой рабочий код в других проектах, чтобы сэкономить время. 

У нас есть проект, в котором мы делали поиск по странице с подсветкой. Работает так: вводим слово, а скрипт подсвечивает все найденные слова. Минус такого подхода в том, что поиск работает только по одному слову, а нам нужно искать несколько слов одновременно.

С другой стороны, мы уже умеем работать с регулярными выражениями. С их помощью мы можем найти любое количество слов и словосочетаний на странице, даже с учётом склонений.

Логика работы

  1. Берём готовую страницу из проекта с поиском на jQuery.
  2. Удаляем из неё всё то, что мы не будем использовать.
  3. Берём регулярные выражения и прописываем в них слова-триггеры, которые нужно будет найти.
  4. Перебираем весь текст на странице с помощью регулярных выражений и подсвечиваем совпадения.
  5. Для подсветки используем наработки из проекта с API и сервисом «Главред» — там мы тоже выделяли целые слова в тексте.

Готовим страницу

Берём готовую страницу из проекта с поиском и оставляем на ней только текст, стиль подсветки и начало скрипта. Заодно немного поменяем текст, чтобы было на чём потренироваться.

<html>
<!-- служебная часть -->

<head>
  <!-- заголовок страницы -->
  <title>Поиск на странице</title>
  <!-- настраиваем служебную информацию для браузеров -->
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- задаём CSS-стили прямо здесь же, чтобы всё было в одном файле -->
  <style type="text/css">

    /* выбираем цвет подсветки — светло-зелёный*/
    .highlight {
      background: #4CFF00;
    }

  </style>
  <!-- закрываем служебную часть страницы -->
</head>
<!-- началось содержимое страницы -->

<body>
 
  <!-- подключаем библиотеку jQuery -->
  <script src="https://thecode.media/wp-content/uploads/2019/06/jquery.js" type="text/javascript"></script>
  <!-- подключаем к ней плагин highlight.js -->
  <script src='https://thecode.media/wp-content/uploads/2019/06/jqueryhighlight.js' />
  </script>
  <!-- говорим браузеру, что сейчас начнётся скрипт -->
  <script type="text/javascript">

    // когда документ загрузился — начинаем работу
    $(document).ready(function () {

  });
  </script>
  
  <!-- в этом блоке разместим наш основной текст -->
  <div class="content">
    <p>
      Достаточно всего 5 минут в день, чтобы лучше понять, как работают библиотеки и плагины в веб-программировании. Вместо того, чтобы работать «на дядю», давайте с их помощью сделаем удобный
      поиск по странице прямо сейчас. Мы знаем, что современные браузеры тоже умеют это делать, но мы сделаем свою версию, которая
      работает не хуже, чем в Хроме или Сафари. Это поможет вам работать где хотите.
    <p>
    <h2>Общая идея</h2>
    </p>
    <p>
      У нас есть сайт с неким текстом, и нам нужно быстро находить в нём нужные слова или части слов. Для этого мы в
      самом начале страницы делаем поле ввода, куда будем писать наши слова для поиска, и кнопку, которая этот поиск
      запускает. Это поможет нам быстро заработать большие деньги, когда мы подключим криптографию и уедем на Бали или на Таиланд. Это и будет ваш пассивный доход.
    </p>
    <p>
      Дальше скрипт берёт весь текст, находит в нём нужные фрагменты и подсвечивает их, заставляя нас горбатиться сверх меры. Если он ничего не находит —
      пишет сообщение о том, что таких слов в тексте нет. Но системе выгодно, чтобы поиск ничего не находил, потому что иначе вы бы смогли в любое время работать в декрете.
    </p>
  </div>
  <!-- закончилось содержимое страницы -->
</body>
<!-- конец всего HTML-документа -->

</html>
Пишем собственный лапшесниматель
Пока ничего не происходит, виден только текст

Пишем регулярные выражения

Давайте найдём в тексте все «продающие» слова, которые, как думает автор, делают текст более цепляющим и заставляют верить в происходящее. 

Для начала составим небольшой список манипуляторских выражений:

  • большие деньги
  • работаю где хочу
  • прямо сейчас
  • работать «на дядю»
  • горбатиться
  • в любое время
  • всего Х минут в день
  • крипто-
  • пассивный доход / заработок
  • лучшая жизнь
  • на Бали
  • Таиланд
  • системе выгодно
  • работа в декрете

Его можно продолжать ещё долго, сейчас главное понять принцип. 

👉 На самом деле в таких словах нет ничего плохого — это просто слова. В другом контексте они бы не вызывали таких эмоций, потому что выражали бы правильную мысль. 

Например, когда племянник на каникулах идёт работать к маминому брату, он в буквальном смысле работает на дядю. Но как только мы встречаем «работать „на дядю“» в негативном контексте, а рядом предлагается стать финансово независимым с помощью бинарных опционов — скорее всего, это манипуляция. 

Теперь каждое выражение превращаем в регулярное на JavaScript и вставляем в самое начало скрипта на странице.

Регулярные выражения

Регулярные выражения — это особый язык, с помощью которого программы умеют находить в тексте какие-то сочетания букв. Регулярки нужны для обработки и проверки текста — например, правильно ли набран номер телефона или похож ли текст на почтовый адрес.

У регулярок есть две принципиальные части: сами буквы, по которым ищем, и токены. Например, если мы хотим найти в тексте слово «свобода», то регулярка будет выглядеть так:

свобода

Но если мы хотим, чтобы в тексте нашлись слова «свобода» и «свободы», мы должны будем заменить одну из букв на токен, который обозначает букву. Это токен \w:

свобод\w

Если мы хотим разрешить находить слова в других падежах типа «свобода», «свобод» «свободами», мы должны разрешить токену \w повторяться от 0 до 3 раз:

свобод\w{0,3}

А если мы не хотим, чтобы поиск находил слово «несвобода», нужно сказать, что «свобод» должно начинаться в начале слова. Для этого есть токен \b, который означает границу слова. Поставим его с двух сторон, чтобы поиск не находил слова типа «свободолюбивый» и «свободоненавистничество».

\bсвобод\w{0,3}\b

Это заклинание переводится так: «В начале слова найти буквы с-в-о-б-о-д, а потом от нуля до трёх любых букв, и потом должен сразу быть конец слова». 

Это заклинание сработает в любом языке, кроме JavaScript, потому что JS не считает русские буквы за словообразующие символы. Придётся использовать другие токены, которые решают эту проблему:

\Bсвобод\W{0,3}\B

Токены \B и \W — это уже другие токены: в регулярках регистр важен. Такой вот костыль JavaScript. В Python или InDesign этой проблемы нет.

Также в JavaScript регулярку нужно обхватывать косыми чертами /…/.

// массив с регулярными выражениями
var r = [];
// заполняем элементы массива нашими выражениями
r[0] = /\B[бБ]ольш\W{2,4} +деньг\W{1,3}\B/;
r[1] = /\Bработа\W{1,4}где хо\W{2,7}\B/;
r[2] = /\B[пП]рямо сейчас\B/;
r[3] = /\B[рР]абота\W{0,3} ["«]на дядю["»]\B/;
r[4] = /\B[Гг]орба\W{2,6}с[яь]\B/;
r[5] = /\B[вВ] любое время\B/;
r[6] = /\Bвсего +\d{1,3} +(минут|час)\D{0,3} в (день|неделю)\B/;
r[7] = /\B[кК]рипто\W\B/;
r[8] = /\B[пП]ассивн\W{1,3}\B/;
r[9] = /\B[нН]а +Бали\B/;
r[10] = /\BТа[ий]ланд\W{0,2}\B/;
r[11] = /\B[сС]истем\W{1,3} выгодно\B/;
r[12] = /\B[рР]абот\W{1,3} в декрете\B/;

Находим совпадения на странице

Так как у нас весь текст находится внутри абзацев, помеченных тегом <p>, то с помощью jQuery мы переберём все элементы на странице с таким тегом и обработаем их содержимое.

Чтобы подсветить нужный текст, используем тег <span> — мы так уже делали, когда подключали API сервиса «Главред» к орфокорректору.

Каждый абзац будем обрабатывать так:

  1. Берём содержимое абзаца.
  2. Смотрим, сколько регулярных выражений записано у нас в массиве.
  3. По очереди находим в тексте абзаца совпадения по каждой регулярке и оборачиваем совпадение тегом <span>.

Запишем это на языке JavaScript. Обратите внимание на последнюю строчку — мы используем вызов функции highlightText(), которой у нас ещё нет. В следующем разделе мы это исправим.

// функция, которая подсвечивает текст в содержимом какого-то элемента на странице
      function lst(txt) {
    
        // перебираем по очереди все абзацы, которые есть на странице, используя возможности jQuery
        $(txt).each(function () {

          // по очереди проходим по массиву с регулярными выражениями
          for ( var z = 0; z < r.length; z++) {
            // на каждом шаге цикла берём содержимое очередного абзаца 
            var par = this.innerHTML;
            // и прогоняем его через подсветку каждого найденного регулярного выражения
            this.innerHTML = highlightText(r[z],par);
          }
        });
    };
   // подсвечиваем все слова внутри абзацев на странице
    lst('p');

Подсвечиваем текст

Последнее, что нам осталось добавить в скрипт, — функцию подсветки highlightText(), которую мы использовали в предыдущем фрагменте кода.

Мы будем передавать функции два аргумента на вход: регулярное выражение и текст, который нужно обработать. Текст у нас уже есть, а регулярные выражения мы получаем из массива на каждом шаге цикла.

Главная сложность — выцепить из сработавшей регулярки конкретный текст, по которому было совпадение. Это нам нужно для того, чтобы заменить найденный фрагмент на фрагмент с тегами вокруг текста. Для этого пойдём на хитрость.

  1. У нас есть стандартная функция JavaScript под названием replace(). Именно она находит нам текст по шаблону и заменяет на какой-то другой. 
  2. replace() требует двух параметров: что найти и на что заменить. Находить мы будем по регулярным выражениям. А вот с заменой проблема: мы же не знаем, какую именно словоформу нашла наша регулярка. А сказать, на что заменить, нужно однозначно. 
  3. Чтобы обойти это ограничение, мы снова вызовем эту же функцию replace(), но со встроенным параметром match. Если перевести на русский, то получится так:

ФункцияЧто найтиНа что заменить
replace(new RegExp(regular, “gi”)function replace(match {
        return ‘<span class=”highlight”>’ + match + ‘</span>’;

    }
);
замени(То, что ты найдёшь по нашей регулярке, которую ты получила на вход. gi означает, что искать нужно все встречающиеся слова и игнорировать регистр.Найденная строка будет храниться в переменной match. Возьми то, что в этой переменной, оберни в <span> и верни обратно в функцию replace как второй параметр «на что заменить»);

Честно скажем: этот трюк с двойным вызовом мы стащили у коллег. Как и все нормальные программисты. 

// функция, которая оборачивает найденное регулярное выражение в тег с подсветкой
// в качестве аргументов мы передаём регулярное выражение и текст, который нужно обработать
function highlightText(regular, originalHtml) {
    // переменная, в которую мы поместим итоговое значение
    var newHtml;
    // оборачиваем найденное значение в тег <span>
    // решение подсмотрели здесь: https://www.telerik.com/support/kb/aspnet-ajax/details/highlight-text-inside-html-elements-and-templates
    newHtml = originalHtml.replace(new RegExp(regular, "gi"), function replace(match) {
        return '<span class="highlight">' + match + '</span>';
    })
    // возвращаем результат обработки
    return newHtml;
}

Собираем всё в один файл и смотрим результат:

<html>
<!-- служебная часть -->

<head>
  <!-- заголовок страницы -->
  <title>Поиск на странице</title>
  <!-- настраиваем служебную информацию для браузеров -->
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- задаём CSS-стили прямо здесь же, чтобы всё было в одном файле -->
  <style type="text/css">

    /* выбираем цвет подсветки — светло-зелёный*/
    .highlight {
      background: #4CFF00;
    }


  </style>
  <!-- закрываем служебную часть страницы -->
</head>
<!-- началось содержимое страницы -->

<body>
 
  <!-- подключаем библиотеку jQuery -->
  <script src="https://thecode.media/wp-content/uploads/2019/06/jquery.js" type="text/javascript"></script>
  <!-- подключаем к ней плагин highlight.js -->
  <script src='https://thecode.media/wp-content/uploads/2019/06/jqueryhighlight.js' />
  </script>
  <!-- говорим браузеру, что сейчас начнётся скрипт -->
  <script type="text/javascript">

    // массив с регулярными выражениями
    var r = [];
    // заполняем элементы массива нашими выражениями
    r[0] = /\B[бБ]ольш\W{2,4} +деньг\W{1,3}\B/;
    r[1] = /\Bработа\W{1,4}где хо\W{2,7}\B/;
    r[2] = /\B[пП]рямо сейчас\B/;
    r[3] = /\B[рР]абота\W{0,3} ["«]на дядю["»]\B/;
    r[4] = /\Bгорба\W{2,6}с[яь]\B/;
    r[5] = /\B[вВ] любое время\B/;
    r[6] = /\Bвсего +\d{1,3} +(минут|час)\D{0,3} в (день|неделю)\B/;
    r[7] = /\B[кК]рипто\W\B/;
    r[8] = /\B[пП]ассивн\W{1,3}\B/;
    r[9] = /\B[нН]а +Бали\B/;
    r[10] = /\BТаиланд\W{0,2}\B/;
    r[11] = /\B[сС]истем\W{1,3} выгодно\B/;
    r[12] = /\B[рР]абот\W{1,3} в декрете\B/;
  
    

    // когда документ загрузился — начинаем работу
    $(document).ready(function () {

      // функция, которая оборачивает найденное регулярное выражение в тег с подсветкой
      // в качестве аргументов мы передаём регулярное выражение и текст, который нужно обработать
      function highlightText(regular, originalHtml) {
          // переменная, в которую мы поместим итоговое значение
          var newHtml;
          // оборачиваем найденное значение в тег <span>
          // решение подсмотрели здесь: https://www.telerik.com/support/kb/aspnet-ajax/details/highlight-text-inside-html-elements-and-templates
          newHtml = originalHtml.replace(new RegExp(regular, "gi"), function replace(match) {
              return '<span class="highlight">' + match + '</span>';
          })
          // возвращаем результат обработки
          return newHtml;
      }

     // функция, которая подсвечивает текст в содержимом какого-то элемента на странице
      function lst(txt) {
    
        // перебираем по очереди все абзацы, которые есть на странице, используя возможности jQuery
        $(txt).each(function () {

          // по очереди проходим по массиву с регулярными выражениями
          for ( var z = 0; z < r.length; z++) {
            // на каждом шаге цикла берём содержимое очередного абзаца 
            var par = this.innerHTML;
            // и прогоняем его через подсветку каждого найденного регулярного выражения
            this.innerHTML = highlightText(r[z],par);
          }
        });
    };
    // подсвечиваем все слова внутри абзацев на странице
    lst('p');


  });
  </script>
  
  <!-- в этом блоке разместим наш основной текст -->
  <div class="content">
    <p>
      Достаточно всего 5 минут в день, чтобы лучше понять, как работают библиотеки и плагины в веб-программировании. Вместо того, чтобы работать «на дядю», давайте с их помощью сделаем удобный
      поиск по странице прямо сейчас. Мы знаем, что современные браузеры тоже умеют это делать, но мы сделаем свою версию, которая
      работает не хуже, чем в Хроме или Сафари. Это поможет вам работать где хотите.
    <p>
    <h2>Общая идея</h2>
    </p>
    <p>
      У нас есть сайт с неким текстом, и нам нужно быстро находить в нём нужные слова или части слов. Для этого мы в
      самом начале страницы делаем поле ввода, куда будем писать наши слова для поиска, и кнопку, которая этот поиск
      запускает. Это поможет нам быстро заработать большие деньги, когда мы подключим криптографию и уедем на Бали или на Таиланд. Это и будет ваш пассивный доход.
    </p>
    <p>
      Дальше скрипт берёт весь текст, находит в нём нужные фрагменты и подсвечивает их, заставляя нас горбатиться сверх меры. Если он ничего не находит —
      пишет сообщение о том, что таких слов в тексте нет. Но системе выгодно, чтобы поиск ничего не находил, потому что иначе вы бы смогли в любое время работать в декрете.
    </p>
  </div>
  <!-- закончилось содержимое страницы -->
</body>
<!-- конец всего HTML-документа -->

</html>

Сразу видно, что автор сильно хочет нам что-то продать, поэтому использует такие слова.

Что дальше

Дальше будем развивать мысль: сделаем так, чтобы этим было удобно пользоваться на любой странице, а также дополним боевой список слов.

Текст и код:

Михаил Полянин

Художник:

Даня Берковский

Корректор:

Ирина Михеева

Вёрстка:

Мария Дронова

Соцсети:

Олег Вешкурцев

Получите ИТ-профессию
В «Яндекс Практикуме» можно стать разработчиком, тестировщиком, аналитиком и менеджером цифровых продуктов. Первая часть обучения всегда бесплатная, чтобы попробовать и найти то, что вам по душе. Дальше — программы трудоустройства.
Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию
А вы читали это?
Одной строкой: новые CSS-команды для фронтендов
Одной строкой: новые CSS-команды для фронтендов

Что можно сделать в современном вебе.

medium
Как сохранить JSON на сервере
Как сохранить JSON на сервере

И отдать его обратно по запросу.

medium
Делаем свой таймер на Python
Делаем свой таймер на Python

Код — проще, возможностей — больше.

easy
Что означает ошибка: TypeError: ‘undefined’ is not an object
Что означает ошибка: TypeError: ‘undefined’ is not an object

Это значит, что браузер не может найти нужный объект.

easy
Как быстро найти нужное место в списке
Как быстро найти нужное место в списке

Приём, которым пользуются многие программисты

Какие ошибки делают программисты в реализации ООП в JavaScript
Какие ошибки делают программисты в реализации ООП в JavaScript

Статья для опытных

hard
Что означает ошибка Uncaught RangeError: Maximum call stack size exceeded
Что означает ошибка Uncaught RangeError: Maximum call stack size exceeded

Это когда вызывается слишком много вложенных функций

easy
Играем со шрифтами на главной странице
Играем со шрифтами на главной странице

Делаем красивый эффект на случайном фоне

easy
Чёртовы психи: как добавить снежинок на любой сайт одной строкой
Чёртовы психи: как добавить снежинок на любой сайт одной строкой

Ну ладно, тремя строками. Это, считай, одна.

medium
easy