Предыстория


Честно говоря, никогда ранее не покупал б/у вещи на досках объявлений. Но когда случился очередной экономический кризис и нужда заставила, пришлось обратить свое внимание на Авито.

При осмотре предложений сразу бросилось в глаза, что часть объявлений выглядит сомнительными по ряду признаков: заниженная цена, неточное описание и т.п., по которым складывалось впечатление, что или продают не то, что предлагают, или сами не знают что продают. В памяти сразу возник образ из прошлого — барахолки 90-х годов, с которых можно было вернуться как с покупками, так и с пустыми карманами или порезанной сумкой.

Как известно, Авито не дает информацию о других объявлениях продавца, поэтому в тексте объявления часто используют ключевые слова или хэштеги, которые покупатель может использовать для поиска. Но надо заметить, что администрация Авито не приветствует наличие в тексте объявления любой информации, не относящейся к предмету продажи, о чем говорится в правилах размещения. При нарушении правил размещения Авито может заблокировать как объявление, так и аккаунт продавца.

Поисковик выдал мне несколько сайтов, паразитирующих на Авито и других досках объявлений, преимущественно связанных с подержанными автомобилями. В большинстве своем они предлагают поиск объявлений по номеру телефона продавца в базе предварительно скачанных объявлений. Все они имеют недостатки, немаловажные для меня: замысловатый интерфейс, платность услуги, обновление данных с определенным лагом.

Разделяя мнение Стивена Леви о свободном доступе к информации, было решено проанализировать Авито на предмет разработки собственного сервиса sravnito.ru с блэкджеком и всеми делами, а именно: с простым интерфейсом и бесплатным доступом.

На основании проведенного анализа были определены основные атрибуты объявления:

  • название
  • дата публикации
  • цена
  • местонахождение
  • телефонный номер (либо изображение номера, либо хэш от него, либо распознанное OCR значение)

Архитектура


Теперь непосредственно об архитектуре программного комплекса, на котором основан сервис поиска всех объявлений продавца:



Хранилище


В качестве хранилища для хранения объявлений и их скриншотов используется MySQL (Maria DB) с движком InnoDB.

В DB1 хранятся объявления с основными атрибутами. Для сокращения объема памяти, занимаемого данными, для текстовых полей используется тип VARCHAR, так как их длина разнится от объявления к объявлению. Ежедневно добавляется примерно полмиллиона строк, среди которых как сами объявления, так и логи и служебная информация. При такой динамике хранилище по праву можно будет относить к Big Data. Из особенностей настройки можно выделить следующие параметры:

max_heap_table_size = 512M
innodb_buffer_pool_size = 3G

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

CREATE TEMPORARY TABLE _temp_table ENGINE=MEMORY AS (
SELECT field
FROM table
WHERE key = i_key
LIMIT i_limit);

которая потом соединяется с другой:

SELECT table.*
FROM table
JOIN _temp_table
ON table.field = _temp_table.field;

В DB2 хранятся скриншоты объявлений как они выглядят для пользователя браузера. Перед записью скриншоты сжимаются в JPEG с quality = 5, что обеспечивает размер файла с изображением равный примерно 20Кб. Принято считать, что при размере BLOB не более 200Кб, производительность хранения файлов в MySQL ничем не уступает NoSQL-хранилищам, что позволяет оставаться в зоне комфорта реляционной СУБД со всеми ее преимуществами. Настолько сжатый скриншот, несмотря на минимальное качество изображения, позволяет пользователю убедиться, что заданное объявление действительно существовало, и разглядеть хотя бы схематично изображение товара.

Вся логика реализована в хранимых процедурах, чтобы инкапсулировать зависимый от структуры данных код в самой СУБД. Таким образом, клиенты СУБД имеют полномочия только для доступа к хранимым процедурам, которые являются идемпотентными. Как дополнительный плюс получаем отсутствие возможности осуществления SQL-инъекций.

API к хранилищу


Сервер M1 реализован как микросервис на golang и предоставляет RESTful API для сохранения объявлений, скриншотов, а также для чтения данных выводимых на странице сервиса поиска объявлений. Нет причин использовать какие-либо фреймворки или внешние библиотеки для реализации RESTful на golang, поэтому используются только стандартные библиотеки, кроме одной:

import (
"database/sql"
"encoding/json"
"net/http"
_ "github.com/go-sql-driver/mysql"
)

Обрабатываются GET и POST запросы от клиентов и вызываются соответствующие хранимые процедуры БД DB1, DB2.

Загрузчики объявлений


Объявления загружаются с сайта Авито загрузчиками S(1)-S(N), написанными на Java с использованием библиотеки Selenium WebDriver. Получив с Авито атрибуты объявления и скриншот, загрузчик обращается к серверу M1 для передачи данных. Также реализована обратная связь для управления загрузчиками, которые периодически опрашивают сервер M1 на предмет команд, например «стоп», «старт».

Captcha


Для разгадывания капчи, которую иногда запрашивает Авито, существует сервер C1, по аналогии с сервером M1 реализованный на golang и предоставляющий RESTful API. Разгадывание капчи осуществляется двумя способами:

  • с помощью сервиса rucaptcha.com
  • вручную в приложении для Android

Для связи с rucaptcha.com используется их API. Для ручного разгадывания используется написанное на Java приложение Android, которое выводит изображение и принимает ответ. Сервер C1 принимает решение о перенаправлении капчи на rucaptcha.com или в приложение Android в зависимости от количества запросов, накопившихся в очереди. Получив разгадку капчи, сервер C1 отправляет ответ запросившему его загрузчику.

Мониторинг


По аналогии с приложением Android для разгадывания капчи, существует приложение для мониторинга. Приложение Android для мониторинга обращается к серверу M1, который в свою очередь обращается к БД где агрегируются логи, на основе которых можно судить о количестве загруженных объявлений, сбоях в работе и т.п.

Заключение


Дальнейшее развитие сервиса может быть таким:

  • Создание загрузчиков для других досок объявлений, что позволит делать кросс-поиск всех объявлений одного продавца
  • Использование комплекса для обработки других данных, например загрузка из соцсетей для поиска всех постов по имени аккаунта

И в том и в другом случае разработке подлежат только загрузчики, которые легко интегрируются с серверами M1 и C1. Доработка других частей системы не потребуется.

Если сделать API серверов M1, C1 публичным с авторизацией и добавить в структуру БД ключевое поле для разделения по клиентам, то можно предоставлять услугу по хранению данных и обработке капчи как SaaS. Данные клиента можно хранить в BLOB в виде JSON, доработав при этом БД с хранимыми процедурами и интерфейс API.

Что можно сказать о выбранных технологиях:

  • MySQL — классика жанра, без комментариев
  • Java — загрузчики можно запускать на кофеварках и холодильниках
  • golang — очень быстро разрабатываются микросервисы, легко деплоится путем копирования единственного бинарника на сервер

Буду признателен за комментарии и обсуждение.
Поделиться с друзьями
-->

Комментарии (45)


  1. rikert
    14.12.2016 15:47
    +7

    > собственного сервиса sravnito.ru

    Вы хотели сказать «собственного паразитирующего на авито сервиса sravnito.ru».

    > с простым интерфейсом и бесплатным доступом

    и бесплатной рекламой Google Adwords


    1. smplpro
      14.12.2016 22:23
      +4

      Паразитируют, когда просят 300 рублей за «пробивку».
      Когда все бесплатно с рекламой для поддержки оплаты vps — не считаю что это так


    1. LeReve
      14.12.2016 22:31

      И чем же он вас паразитировал? Комментарий вида: лишь бы придраться к чему нибудь.


    1. Aionoff
      14.12.2016 22:31
      +1

      Что плохого в бесплатной рекламе Google Adwords?


  1. KlimovDm
    14.12.2016 17:51

    При такой динамике хранилище по праву можно будет относить к Big Data.
    innodb_buffer_pool_size = 3G

    Как то не стыкуется.


    1. smplpro
      14.12.2016 22:17

      Разве Big Data определяется именно размером кучи под данные, а не в целом объемами?


      1. KlimovDm
        14.12.2016 22:41

        Я не об определении Big Data, а о настройках mysql сервера, которые вы отдельно выделили. Думаю, что эта старая статья Петра Зайцева более точно пояснит мою мысль. Объем всех ваших данных в innodb таблицах явно больше 3Gb. И оперативной памяти на вашем DB сервере явно больше 4Gb.


        1. smplpro
          14.12.2016 22:47

          Спасибо за ссылку, почитаю и подумаю что ответить.
          Данных именно по объявлениям без учета скриншотов в данный момент >50Gb, а оперативки 4 Gb. Понятно, что хранить все данные в оперативке нереально в данный момент.


        1. smplpro
          14.12.2016 23:15

          В части использования пула, такие данные, то есть видно, что

          You need buffer pool a bit (say 10%) larger than your data (total size of Innodb TableSpaces) because it does not only contain data pages – it also contain adaptive hash indexes, insert buffer, locks which also take some time.
          указанные данные вмещаются в пул с большим запасом
          image


          1. KlimovDm
            15.12.2016 08:29

            В принципе 4Gb оперативной памяти на сервере DB всё объясняет.

            Что касается данных, то в пул они как раз не умещаются (при условии, что у вас данные >50Gb). На график особо не глядите, при такой нагрузке использование буфера может увеличиваться очень медленно. Проведите нагрузочное тестирование — получите другую картину.


            1. smplpro
              15.12.2016 22:23

              имел в виду эти данные:

              You need buffer pool a bit (say 10%) larger than your data (total size of Innodb TableSpaces) because it does not only contain data pages – it also contain adaptive hash indexes, insert buffer, locks which also take some time.


              1. KlimovDm
                16.12.2016 00:38

                Теперь вообще не понимаю, о чем вы. Ну, допустим, индексы/блокировки по размеру помещаются в пул. И что? Вы умеете класть их в пул отдельно от данных? В тексте ясно написано, что размер пула желательно задавать немного больше общего размера данных, так как туда попадают еще индексы и т.д… То, что эти данные по размеру умещаются в пул — вам ничего не дает, кроме теоретической констатации самого факта.


                1. smplpro
                  16.12.2016 11:32

                  В любом случае не понимаю, где можно взять 100, 200,… 500,… 1000Гб оперативной памяти для размещения всех данных в пуле с учетом их непрерывного поступления. Так что рекомендацию автора также можно считать чисто теоретической в данном случае


                  1. KlimovDm
                    16.12.2016 11:49

                    В данном случае (когда у вас 4 Гб оперативки и отсутствие нагрузки) — конечно. А общем случае — такие задачи решаются не в лоб (добавляя оперативку), а архитектурно. Кластеризация, распределенные данные и т.д. и т.п.


  1. marenkov
    14.12.2016 18:43
    +1

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


    1. smplpro
      14.12.2016 22:19

      Смысл в том, что если по ссылке на объявление либо номеру телефона нашлось, допустим 5 топовых видеокарт в разных регионах, то очевидно, что здесь что то не чисто. Если же нашлось много объявлений, например про коллекционирование или детскую одежду,- то похоже на правду


  1. fatum2996
    14.12.2016 22:19

    Вбил ссылку на объявление, ничего не нашлось. Хотя с этим номером телефона есть еще объявления. По номеру телефона нашлось несколько объявлений, но не все.


    1. smplpro
      14.12.2016 22:20

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


  1. smplpro
    14.12.2016 22:24

    Хотелось бы услышать комментарии по архитектуре и технологиям, а не насчет того, что кто-то не нашел все объявления


  1. HellMaster_HaiL
    14.12.2016 22:31
    +1

    Если честно, ожидал что речь пойдет об каком либо плагине для браузера, который при открытии страницы с объявлением рядом с именем или аватаркой автора большими красными буквами пишет слово «мошенник» и ссылку на пруфы…


    1. smplpro
      14.12.2016 22:40

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


  1. azsx
    15.12.2016 02:14

    Java приложение Android, которое выводит изображение и принимает ответ.

    Это вы сами набиваете?


    1. smplpro
      15.12.2016 10:41

      Да, на телефоне выводится картинка, которую я разгадываю.
      Когда много капчей, то они уходят на rucaptcha.com.
      Это позволяет экономить на разгадывании


      1. avallac
        15.12.2016 12:57

        распарсить лям записей * 18 рублей/тысячу = 18000 как-то много


        1. smplpro
          15.12.2016 13:12

          Это при условии, что капчу у вас будет спрашивать на каждом объявлении.
          На практике пару раз в час


  1. hard_sign
    15.12.2016 10:45

    Неудобно, что при выдаче объявлений нет пометки о том, что объявление снято с продажи. Если у человека 80 объявлений, это подозрительно. Но если из них 5 активных — то это нормально :)


    1. smplpro
      15.12.2016 10:50

      Анализировать объявления повторно на предмет снятия с продажи требует дополнительных мощностей.
      В настоящий момент загрузка однократная — берутся аттрибуты и картинка и больше к этому объявлению не возвращаемся


  1. avallac
    15.12.2016 10:46

    А где картинки то?


    1. smplpro
      15.12.2016 10:48

      Картинки есть, но не все.
      Это связано с тем, что загрузка картинок писалась после намного позже после запуска загрузчика, а также время от времени останавливалась из-за превышения объема диска. Опытным путем был получен подходящий размер картинок, так что со временем картинки будут для каждого объявления


  1. Hush
    15.12.2016 11:15

    Насколько знаю, авито банит айпишники за особый и массовый интерес к телефонам. Как обходили этот момент? Закупили проксей?


    1. smplpro
      15.12.2016 12:37

      Это тема для отдельной статьи как с помощью API VPS-провайдера (DigitalOcean) удалять и создавать новые сервера взамен старых с забаненными адресами.
      В целом вы правы — забаненные адреса уже нельзя использовать.
      Прокси не использовал, слишком сложно для меня


      1. hakastein
        15.12.2016 13:45

        А поднять тор? Поднимается и настраивается на раз два, а потом юзается как обычная прокся.


        1. smplpro
          15.12.2016 13:46

          Надо попробовать, спасибо


        1. mapatka
          15.12.2016 16:59

          Авито, вроде, через тор забанено? Нет?


          1. roversochi
            27.03.2017 09:51

            Достал 28BYJ, запустил. Шумность действительно у него изумительная. Однако маловата скорость и крутящий момент. Попробую переделать его в биполярник, возможно тогда мотора хватит.


      1. rikert
        15.12.2016 19:20

        image

        > как с помощью API VPS-провайдера (DigitalOcean) удалять и создавать новые сервера взамен старых с забаненными адресами

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


        1. smplpro
          15.12.2016 21:25

          А зачем хорошему человеку типа вас понадобилось открывать авито из VPS?


        1. smplpro
          15.12.2016 21:53

          А вы писали им, если считаете что ваш адрес заблокирован по ошибке?


        1. smplpro
          15.12.2016 22:20

          Сообщите, пожалуйста:
          * ваш IP-адрес (его можно посмотреть на yandex.ru/internet);
          * название интернет-провайдера;
          * город проживания

          и мы с хабра-сообществом подумаем, чем вам можно помочь


  1. smplpro
    15.12.2016 17:00

    .


  1. nachit
    15.12.2016 23:36

    Код не планируете открывать?


    1. smplpro
      16.12.2016 11:10

      там особо и открывать нечего


  1. capitannemo
    16.12.2016 11:09

    Еще один парсер авито.
    Телефон кстати легко получить в текстовом виде.
    На 1С такое делал )
    ИМХО делать копию авито с более удобным поиском — не потянет движок.
    А вот локальную базу выборки объявлений по интересующей области — самое то.
    Так что делайте на денвере с открытым кодом и будет вам щастя


    1. smplpro
      16.12.2016 11:29

      Как я уже писал, найденные мной парсеры авито, предлагают какие-то нереальные цены (цитаты с их сайтов):

      • -25% на первые 3 месяца, 2400 руб. 1800 руб.
      • Стоимость одной лицензии программы XXX: 550 1350 рублей, лицензия безсрочная!
      • Цена на подключение к API 3000 руб. в месяц (30 дней)
      • Продаю навороченный парсер (граббер) объявлений с avito.ru (авито.ру) Цена 1 лицензии — 2500 рублей + комиссия за перевод.
      • Автоматическая выгрузка объявлений авито.
        Стоимость программы 700р.


      Отсюда становится понятен баттхёрт недовольных комментаторов: «как же так? бесплатный конкурент, чёрт бы его побрал»
      Также доставляют незатейливые просьбы от открытии, казалось бы тривиального, кода


  1. Alexufo
    16.12.2016 16:42

    Кое что про авито. Я не понимаю, почему они банят, при указании телефона как копии оригинала.
    Получается они поощряют мошенников.
    Так что имейте ввиду, с обьявами еще немного сложнее.