Рубрики
Без рубрики

Создание приложения SaaS: за пределы оснований

Это первый пост в серии по созданию собственного заявления SaaS. Мы пойдем шаг за шагом … Теги с JavaScript, Python, Docker.

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

Так какой продукт мы собираемся построить?

Мы собираемся построить полностью функционирование (если минимально) Google Rank Tracker.

Введите домен, некоторые ключевые слова и приложение отслеживают производительность в поисках Google со временем. Эта идея имеет деловой смысл? Возможно нет! Но это забавная идея, которая делает что-то полезное, это задача, которую мы можем выполнить, и вы можете занять ее, насколько вам нравится. Мы охватим все основы построения приложения SaaS по пути.

Вы можете найти полный код на GitHub.

Оглавление

  • Часть I: Создание скребка поиска Google
    • Настройка куклора на экземпляре AWS
    • Создание простого запроса поиска Google
    • Использование прокси-сети для запросов скребка
    • Сбор результатов поиска
    • Обработка скребка ошибок
  • Часть II: Производство готовое развертывание с nginx, колбой и postgres
    • Настройка докера и докера составляют
    • Развертывание версии развития
    • Понимание того, как Nginx и Flask работают вместе
    • Тестирование Nginx и колба конфигурация
    • Конфигурация Postgres.
    • Настройка SSL с помощью шифрования
    • Развертывание производственной версии
  • Часть III: Колба, SQLALCHEMY и POSTGRES
    • Настройка sqlalchemy и postgres
    • SQLalchemy Performance Dispalls.
    • Настройка нашего первого обработчика маршрута API
  • Часть IV: аутентификация пользователя с колбой и реагировать
    • Защита API для отдыха колбы с помощью JSON WEB TOKENS
    • Обработка регистрации пользователя в колбе
    • Проверка электронной почты и активация счета
    • Создание пользователя и отправка электронного письма активации
    • Защита страниц в рамках приложения RACT
    • Добавление Google Oauth в качестве опции регистрации

Создание скребка поиска Google

Скрепление результатов поиска Google – это ядро этого приложения. Хотя мы могли бы начать здание всего в любом месте, я думаю, что начиная с сама скребка имеет смысл.

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

Настройка куклора на экземпляре AWS

Мы будем использовать Кукла сделать соскоб. Puppeteer предоставляет API JavaScript для удаленного управления сеансом браузера хрома. Лучше всего, браузер может работать без среды настольных компьютеров (режим без головы), поэтому наш код может выполнять независимо на сервере в облаке. Для этого учебника мы начнем с экземпляра Ubuntu 18.04 на AWS, и поставим через установку всех зависимостей, необходимых для кукловода.

Я использую EC2 tc2.medium Экземпляр для этого проекта. Это поставляется с 2 VCPUS и 4 ГБ оперативной памяти, поэтому он достаточно мощный, чтобы запустить кукол, а также то, что мы собираемся добавить позже. Экземпляр Ubuntu 18.04 – хорошая отправная точка.

Хром наступает в комплекте с кукловом, но есть широкий массив необходимых системных библиотек «Необходимые системы», прежде чем мы сможем начать. К счастью, мы можем получить все, что установлено с этим на один вкладыш.

sudo apt-get install -y ca-certificates fonts-liberation libappindicator3-1 libasound2 libatk-bridge2.0-0 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgbm1 libgcc1 libglib2.0-0 libgtk-3-0 libnspr4 libnss3 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 lsb-release wget xdg-utils

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

curl -sL https://deb.nodesource.com/setup_14.x -o nodesource_setup.sh
bash nodesource_setup.sh
apt-get install -y nodejs

На данный момент у нас есть узел и хромиум. Затем мы создадим файл package.json, чтобы мы могли использовать NPM для установки проектных зависимостей (I.e. Cuppeteer).

{
    "name": "agent-function",
    "version": "0.0.1",
    "dependencies": {
        "axios": "^0.19.2", // For communicating with the app server.
        "puppeteer": "10.0.0",
        "puppeteer-extra": "3.1.8",
        "puppeteer-extra-plugin-stealth": "2.7.8"
    }
}

После запуска NPM установить Вы должны иметь все необходимые части на месте. Давайте использовать очень простой скрипт узла для проверки того, что uppleier установлен и работает.

const puppeteer = require("puppeteer-extra");

async function crawl() {
    console.log("It worked!!!");
}

puppeteer
    .launch({
        headless: true,
        executablePath:
            "./node_modules/puppeteer/.local-chromium/linux-884014/chrome-linux/chrome",
        ignoreHTTPSErrors: true,
        args: [
            "--start-fullscreen",
            "--no-sandbox",
            "--disable-setuid-sandbox"
        ]
    })
    .then(crawl)
    .catch(error => {
        console.error(error);
        process.exit();
    });

Обратите внимание на беговый ключ в объекте Config. Это означает, что Chromium запустится без графического интерфейса, который мы хотим при запуске на сервере в EC2. Надеюсь, если все пойдет хорошо, вы увидите Это сработало!!! Печать на консоль, когда вы выполняете этот скрипт.

Создание простого запроса поиска Google

Теперь, когда мы знаем, что все правильно установлено, мы должны начать с простого поиска Google. Мы не будем беспокоить любой фактический соскоб на этом этапе. Цель – это просто ввести поисковый запрос в панель поиска, загрузите результаты Google и возьмите скриншот, чтобы доказать, что он работал.

Это функция сканирования после обновления его, чтобы сделать то, что я только что описал.

async function crawl(browser) {
    const page = await browser.newPage();
    await page.goto("https://www.google.com/?hl=en");

    // Find an input with the name 'q' and type the search query into it, while 
    // pausing 100ms between keystrokes.
    const inputHandle = await page.waitForXPath("//input[@name = 'q']");
    await inputHandle.type("puppeteer", { delay: 100 });

    await page.keyboard.press("Enter");
    await page.waitForNavigation();

    await page.screenshot({ path: "./screenshot.png" });
    await browser.close();
}

CUPPETEER загружает страницу поиска Google (добавление HL = ru Запросить английскую версию), вводит поисковый запрос и нажмите Enter.

Отоительный вариант Метод приостанавливает скрипт, пока браузер не испускает событие нагрузки (то есть страницы и все его ресурсы, такие как CSS и изображения, загружены). Это важно, потому что мы хотели бы подождать, пока результаты не будут видны, прежде чем мы возьмем скриншот.

Надеюсь, вы увидите что-то похожее в screenshot.png После запуска скрипта.

Использование прокси-сети для запросов скребка

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

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

Есть много различных типов прокси, а огромное количество вариантов поставщиков. В первую очередь есть три варианта для скачка проекта, как это.

  • Покупка одного IP-адреса или пучок IP-адресов через службу, такую как ProxyAll. Это самый низкий вариант затрат. Я приобрел 5 IP-адресов около 5 долларов в месяц.
  • Прокси-центр-центр, которые обеспечивают широкий ассортимент IP-адресов, но заряда для пропускной способности. В качестве примера SmartProxy обеспечивает 100 ГБ за 100 долларов. Многие из этих IP-адресов, однако, уже заблокированы.
  • Жилые прокси также предоставляют широкий ассортимент IP-адресов, но адреса поступают из жилого или мобильного провайдера, и поэтому будет сталкиваться с CAPTCHA реже. Компромисс входит в цену. SmartProxy заряжает 75 долларов за 5 ГБ передачи данных.

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

Отправка запросов через прокси, вместо сети по умолчанию простую с кукловом. Список стартапов ARGS принимает Прокси-сервер ценность.

puppeteer
    .launch({
        headless: false,
        executablePath:
            "./node_modules/puppeteer/.local-chromium/linux-884014/chrome-linux/chrome",
        ignoreHTTPSErrors: true,
        args: [
            `--proxy-server=${proxyUrl}`, // Specifying a proxy URL.
            "--start-fullscreen",
            "--no-sandbox",
            "--disable-setuid-sandbox"
        ]
    })

Proxyurl может быть что-то вроде http://gate.dc.smartproxy.com:20000. . Большинство конфигураций прокси-серверов потребуют имя пользователя и пароль, если вы не используете IP-белый список в качестве метода аутентификации. Вам нужно будет пройти аутентификацию с этим комбинацией имени пользователя/пароля, прежде чем делать какие-либо запросы.

async function crawl(browser) {
    const page = await browser.newPage();
    await page.authenticate({ username, password });
    await page.goto("https://www.google.com/?hl=en");
}

Любой сильно используемый скребок по-прежнему идет на получение блокировки, но приличный прокси сделает процесс устойчивым, пока мы строим в хорошей обработке ошибок.

Сбор результатов поиска

Теперь мы превращаемся в фактическую соскобную часть процесса. Общая цель приложения – отслеживать рейтинги, но для простоты, скребок не заботится о каком-либо конкретном веб-сайте или домене. Вместо этого скребок просто возвращает список ссылок (в порядке, видимом на странице!) На сервер приложений.

Для этого мы собираемся полагаться на XPath, чтобы выбрать правильные элементы на странице. Селекторы CSS часто не достаточно хороши, когда дело доходит до комплексных соскобных сценариев. В этом случае Google не предлагает никакого простого идентификатора или имени класса, которое мы можем использовать для определения правильных ссылок. Мы должны полагаться на комбинацию названий классов, а также структуру тегов, чтобы извлечь правильный набор ссылок.

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

let rankData = [];
while (pages) {
    // Find the search result links -- they are children of div elements
    // that have a class of 'g', while the links themselves must also
    // have an H3 tag as a child.
    const results = await page.$x("//div[@class = 'g']//a[h3]");

    // Extract the links from the tags using a call to 'evaluate', which
    // will execute the function in the context of the browser (i.e. not
    // within the current Node process).
    const links = await page.evaluate(
        (...results) => results.map(link => link.href),
        ...results
    );

    const [next] = await page.$x(
        "//div[@role = 'navigation']//a[descendant::span[contains(text(), 'Next')]]"
    );

    rankData = rankData.concat(links);

    if (!next) {
        break;
    }

    await next.click();
    await page.waitForNavigation();

    pages--;
}

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

Есть много способов сделать это, но я решил приложение сделать API для скребка, чтобы он мог отправлять результаты в качестве запроса на почту. Библиотека Axios делает это довольно легко, поэтому я поделюсь тем, что выглядит здесь.

    axios
        .post(`http://172.17.0.1/api/keywords/${keywordID}/callback/`, {
            secret_key: secretKey,
            proxy_id: proxyID,
            results: rankData,
            blocked: blocked,
            error: ""
        })
        .then(() => {
            console.log("Successfully returned ranking data.");
        });

Не беспокойтесь о заблокирован или Ошибка . Переменные здесь. Мы приступим к обработке ошибок в на мгновение. Самое главное здесь Randdata Переменная, которая относится к списку, содержащему все ссылки на результат поиска.

Обработка скребка ошибок

Обработка неожиданного важна в любом виде программирования, но особенно так с помощью скребка. Есть много, что может пойти не так: бежать в капчу, сбои прокси-сервера, наше XPath становится устаревшим, общая сетевая вспышка и многое другое.

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

Если вы вспомните с ранее, скребок возвращает заблокирован ценность. Давайте посмотрим, как мы определяем, был ли скребок заблокирован.

    let blocked = false;

    try {
        const [captcha] = await page.$x("//form[@id = 'captcha-form']");
        if (captcha) {
            console.log("Agent encountered a CAPTCHA");
            blocked = true;
        }
    } catch (e) {}

Этот код просто ищет наличие формы с идентификатором CAPTCHA-ФОРМА и устанавливает заблокирован значение для правды, если так. Как мы увидим позже, если прокси-IP сообщается как заблокирован слишком много раз, приложение больше не будет использовать этот IP-адрес.

Что дальше?

Надеюсь, вам понравилась эта первая часть серии SaaS App! Далее я пройду через настройку Nginx, Flask и Postgres, используя Docker, чтобы наш скребок есть API для вызова. Вы всегда можете найти Полный код для проекта на Github.

Оригинал: “https://dev.to/zchtodd_79/building-a-saas-app-beyond-the-basics-1jh”