Разработка программного обеспечения для сбора и анализа данных с Web-сайтов строительных магазинов

Выбор типовой архитектуры. Схема работы Shell-скрипта. Вывод информации на сайт. Обеспечение его безопасности. Внедрение проекта на сервер. Построение заключительного запроса. Оценка времени работы приложения. Настройка авторизации по открытому ключу.

Рубрика Программирование, компьютеры и кибернетика
Вид курсовая работа
Язык русский
Дата добавления 22.03.2018
Размер файла 950,6 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

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

Размещено на http://www.allbest.ru/

Размещено на http://www.allbest.ru/

Содержание

Введение

1. Анализ предметной области и постановка задачи

1.1 Анализ предметной области

1.2 Постановка задачи

2. Проектирование

2.1 Выбор архитектуры

2.2 Выбор базового ПО

3. Реализация

3.1 Особенности программной реализации

3.2 Обеспечение безопасности

3.3 Руководство оператора

4. Тестирование и апробация

4.1 Выбор метода тестирования

4.2 Результаты тестирования

4.3 Расчет и экспериментальная проверка параметров производительности

4.4 Внедрение

Заключение

Список используемой литературы

Введение

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

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

Когда-то Интернет был маленькой американской сетью для нескольких сотен человек, где почти все друг друга знали. Теперь это гигантская информационная структура. Здесь практически невозможно контролировать потоки информации. То, что называется «контент, генерируемый пользователями» составляет колоссальный объем данных. Этот объем уже даже невозможно точно измерить. Точно так же как мы когда-то перестали измерять расстояние до звезд в километрах, применяемых на Земле, и стали использовать понятие «световой год», то есть характеристику скорости, также и об интернет-данных теперь пишут в терминах скорости прироста информации, а не ее объема. Так, за одну минуту в Интернете появляются, например, более 3 миллионов новых постов в сети Facebook, более 300 тысяч сообщений в Twitter, более 30 тысяч отзывов о книгах и покупках, не говоря уже об описаниях новых фильмов, товаров и т. д., и т. п.

Все это многообразие информации сейчас активно используется не только людьми, но и организациями для повышения эффективности своей деятельности. Жизнь людей сейчас настолько быстро меняется, что традиционных анкетных данных просто недостаточно для оценки поведения заемщика (если это банк), покупателя (если это розничная сеть). В стремительно меняющемся мире они банально устаревают. И тогда нужно обратиться к «внешним» данным. Произвести обогащение текстовыми данными. Банкам важно анализировать, что пользователи пишут в социальных сетях, на сайтах. Оценить их уровень грамотности, словарный запас, тематику публикуемых сообщений. Магазинам, производителям важно собирать отзывы покупателей об их товарах, анализировать их тональность, чтобы лучше спланировать рекламную компанию, использовать в ней текстовые формулировки, максимально близкие покупателю. И таких примеров большое количество и перечислять их можно бесконечно.

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

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

Разработка и реализация качественных механизмов сбора информации является залогом успешной ее обработки и в данном проекты попробуем ее реализовать с помощью популярного языка программирования Python.

Сейчас Python - стремительно развивающийся язык. В первую очередь его популярность связана с простотой и легкостью освоения. Также развитию популярности способствует и то, что он поставляется под открытой лицензией и является свободно распространяемым. Это обеспечивает наличие огромного количества библиотек, расширений и готовых компонентов, которые можно свободно использовать в своих проектах, что сильно экономит время разработчика. Python - язык с большой и богатой историей. Он появился более 25 лет назад как высокоуровневый язык программирования - альтернатива Java и C++, на котором всего в несколько строчек можно описать то, что на этих низкоуровневых языках программирования занимает по несколько блоков кода. Python в первую очередь предназначен для написания прикладных приложений, но за годы существования он развился в очень гибкий инструмент, на котором сейчас уже пишутся и очень большие, серьезные и высоконагруженные проекты.

скрипт сайт запрос сервер

1. Анализ предметной области и постановка задачи

1.1 Анализ предметной области

Относительно недавно мной была приобретена квартира. И соответственно встал вопрос приобретения строительных материалов. В первую очередь необходимо было выровнять стены с помощью штукатурки фирмы Knauf rotband. По расчетам необходимо было приобрести 20 мешков. И каково же было мое удивление, при покупке заданного количества штукатурки в разных магазинах города разница составляла порядка 900 рублей. И ведь это только начало ремонта, дальше необходимо было приобрести финишную шпатлевку, плиточный клей, гипсокартон, смеси для выравнивания пола, само напольное покрытие и многое другое.

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

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

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

На рынке представлены уже готовые решения, для примера приведем несколько:

Datacol (http://web-data-extractor.net/) - универсальный парсер, который собирает данный с множества интернет ресурсов, таких как: интернет-магазины, сайты недвижимостей, социальные сети, вакансий и т. д. Собранные данные можно сохранить в удобном формате, таком как: базе данных MySQL, CSV, xlsx, xml, для конструктора Joomla или Bitrix и другие. Также содержит множество уже предустановленных настроек и бесплатную поддержку. Стоимость 1200 руб. при покупке на месяц или 5500 руб. за подписку на год.

Content Downloader X1 (http://parsing-service.ru/) - аналогичный универсальный парсер, отличия только в базовых настройках. В моем случае, чтобы собрать информацию с 7 магазинов, потребуется прибрести версию за 1200 руб. и 350 руб. за настройку каждого сайта. Итого - 3650 руб.

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

FlowCrawler (http://flowcrawler.com/) - универсальный конструктор ботов для парсинга, т. е. это программа внешне похожая на окно браузера, где мы самостоятельно ей показываем каким путем хотим пройти по сайту и какие части страниц из него извлечь. Стоимость 5900 руб. за год и продление 590 руб. в год.

Как видно, сбор информации с сайтов не бесплатен и это основной критерий от отказа. Таким образом следует, что разработка будет выполнятся в порядке личной инициативы.

1.2 Постановка задачи

В данном подразделе будет четко сформулировано назначение программного продукта и определены основные требования к нему.

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

Соответственно основные требования будут исходить из формулировки назначения программного продукта:

Ш Перечень сайтов строительных магазинов г. Вологда:

o Торговый дом стройОПТторг;

o Строймакет ЛИДЕР;

o ЦентрСМ;

o Континент;

o Аксон;

o Еврострой;

o АПлайн;

Ш Перечень данных для сбора о товаре:

o Название магазина;

o Наименование товара;

o Цена;

o Наличие;

o Ссылка на товар;

Ш Время отклика системы не более 5 сек.;

Ш Нормальный режим суточной посещаемости не менее 1000 чел. в сутки.

2. Проектирование

Проектирование осуществим на основе анализа требований к системе.

2.1 Выбор архитектуры

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

2.2. Выбор базового ПО

Так как разработка ведется по личной инициативе, то и базовое ПО это домашний ПК с установленным дистрибутивом.

Основные параметры ПК это процессор AMD x2 250 3000Ghz, DDR3 4Gb и HDD 1Tb.

В качестве ОС установлена Ubuntu 16.04 LTS -- операционная система, основанная на Debian GNU/Linux. Рассмотри главные особенности дистрибутива:

Ш Стабильность работы -- часто используется на высоко нагруженных серверах, не требует частых перезагрузок, даже в случае обновлений;

Ш Безопасность -- нет необходимости в антивирусах;

Ш Бесплатность;

Ш Дружественный интерфейс;

Ш Работа из коробки -- нет необходимости искать и устанавливать драйвера и ПО;

Ш Периодичность выхода свежей ОС составляет 6 мес;

Ш Отлично уживается на одном ПК с другими ОС, например, Windows.

В качестве СУБД установлена MySQL -- реляционная база данных, поддерживающая SQL (структурированный язык запросов) и может применятся в качестве SQL-сервера. В качестве достоинств можно отнести:

Ш Быстродействие, благодаря внутреннему механизму много поточности;

Ш Безопасность;

Ш Лицензия, для некоммерческих целей распространяется бесплатно;

Ш Открытый код;

Ш Стабильность;

Ш Не требует много ресурсов;

Ш Сообщество.

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

Так как практически весь проект написан с использованием Python, то остановимся немного подробнее. Python - это язык программирования общего назначения, т. е. на нем можно написать практически что угодно, например, веб-приложения, настольные приложения, игры, скрипты по автоматизации и многие другие системы без ощутимых проблем. За счет простоты кода, дальнейшее сопровождение программ, становится легче и приятнее чем, например, С++ или Java. Может показаться, что это панацея от всех бед, но не все так прекрасно. Одним из главных недостатков это относительно низкая скорость выполнения, может значительно проигрывать С++, Java, Go. Но за счет предварительной компиляции в байт-код и значительной части стандартной библиотеки, написанной на Си, превосходит PHP, Ruby, JavaScript.

Для написания кода, воспользуемся PyCharm -- интеллектуальная Python IDE. Очень мощный и функциональный редактор кода с подсветкой синтаксиса, авто-форматированием и т.д. Из ключевых особенностей отметим:

Ш Полная поддержка свежих версий фреймворка Django;

Ш Редактор HTML/CSS;

Ш Интерактивные консоли для Python, Django, SSH, MySQL и др.;

Ш Кросс-платформенность.

Для работы с простыми сайтами (без использования JQuery или JavaScript), т. е. обработку запросов HTTP будем использовать библиотеку requests, а для для синтаксического разбора файлов HTML/XML -- Beautiful Soup.

Requests - это своеобразная обертка над urllib3 (стандартная библиотека Python), которая дает удобство написания кода, а это в основном главное достоинство. Но есть и другие возможности:

Ш Множество методов http аутентификации;

Ш Сессии с куками;

Ш Полноценная поддержка SSL;

Ш Проксирование;

Ш Грамотная работа с исключениями.

Beautiful Soup - это парсер для синтаксического разбора HTML/XML файлов. Он поддерживает простые и естественные способы поиска дерева синтаксического разбора.

Для работы с динамическими сайтами использующими JQuery или JavaScript будем использовать библиотеку Selenium.

Selenium - это комплект из нескольких инструментов, которые предоставляют богатый набор возможностей, для тестирования всех веб-приложений. Для нашего случая будем использовать Selenium Webdriver - это инструмент для управления браузером. Список поддерживающих браузеров достаточно обширен (Google Chrome, Microsoft Internet Explorer, Mozilla Firefox, Opera, PhantomJS и др.).

Для сбора данных в формате CSV будем использовать стандартную библиотеку.

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

Для хранения данных будем использовать базу данных MySQL, а для доступа к ней с помощью Python, будем использовать библиотеку-клиент PyMySQL connector. Основная ее функция - это подключение к базе данных.

Для вывода информации создадим сайт (HTML и CSS), а для динамического обновления информации используем свободный фреймворк Django.

HTML - это язык разметки гипертекста, применяется для создания веб-страниц. Он обрабатывается браузером и отображается в виде документа, в удобной форме. Это основа любой веб-страницы. Содержит множество тэгов (специальные маркеры, которые определённым образом определяются браузером) которые и определяют логическую разметку страницы.

CSS - это язык описания внешнего вида документа (каскадные таблицы стилей).

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

3. Реализация

Схематически изобразим принцип работы и дадим некоторые объяснения.

Рисунок 3.1 - Схема работы Shell-скрипта

Основой выступает Shell-скрипт, в котором содержаться команды для запуска отдельных программ для обхода web-сайтов, сбора данных и обновления базы данных MySQL.

Для примера, покажем наш скрипт. В самой первой строчке указывается путь к bash-интерпретатору.

#!/bin/bash

# Вывод текстовой информации в окно терминала, о начале работы приложения.

echo "Сбор данных начался"

# Запуск семи отдельных окон терминала, в каждом из которых для начала удаляется уже загруженный файл CSV ранее в базу и запускается программа для обхода web-сайта магазина.

xterm -hold -e 'rm apline.csv; python3 apline35.py' &

xterm -hold -e 'rm dom35.csv; python3 dom35.py' &

xterm -hold -e 'rm evrostroy.csv; python3 evrostroy.py' &

xterm -hold -e 'rm kontinent.csv; python3 kontinent.py' &

xterm -hold -e 'rm lider.csv; python3 lider35.py' &

xterm -hold -e 'rm tdsot.csv; python3 tdsot.py' &

xterm -hold -e 'rm akson.csv; python3 akson.py'

# После того как все магазины закончили собирать данные, произойдет вывод текстовой информации по собранным магазинам. По которым можно оценить качество работы программы. Для этого запуститься еще один небольшой скрипт. Рассмотрение его последует сразу за Shell-скриптом.

echo "Сбор данных успешно завершен"

echo "Собранные данные по магазинам:"

python3 len_items.py

# Данной командой мы скопируем CSV файлы с данными магазинов на удаленный сервер.

scp akson.csv apline.csv dom35.csv evrostroy.csv kontinent.csv lider.csv tdsot.csv sharkk@188.225.57.45:/home/sharkk/django_project/parser35/Shops

# На сервере, для обновления базы данных запустим еще один, последний, скрипт.

$ sudo python3 SQL.py

Как и обещалось ранее рассмотрим программный код программы len_items.py.

# Импортируем необходимую библиотеку.

import csv

# Список всех файлов магазинов.

shops = [

'akson.csv',

'apline.csv',

'dom35.csv',

'evrostroy.csv',

'kontinent.csv',

'lider.csv',

'tdsot.csv'

]

# Задание начального значения отсчета.

s = 0

# Открываем файлы и считаем количество строк в файле, с выводом в окно терминала.

for i in shops:

with open(i) as file:

reader = csv.reader(file)

p = [x for x in reader]

s += len(p)

print(i, ' - ', len(p))

# Вывод общей суммы собранных данных.

print('Total', s)

Для полной картины, осталось рассмотреть программный код обновления базы данных на сервере. За это отвечает программа SQL.py.

# Импорт необходимых библиотек

import pymysql

import csv

import time

# Константы - список имен CSV-файлов и параметры подключения к базе данных MySQL.

FILE = ['akson.csv', 'apline.csv', 'dom35.csv', 'evrostroy.csv', 'kontinent.csv', 'lider.csv', 'tdsot.csv']

CONNECTION = pymysql.connect(host='localhost', user='root', password='password', db='parser35', charset="utf8")

# Константы списка «плохих» названий.

BAD_AVAILABLE_YES = ['в наличии', 'НаличиеЕсть', 'Наличие : Есть', 'Наличие : Мало', 'В корзину', 'НаличиеМало']

BAD_AVAILABLE_NO = ['Наличие : Нет', 'Отсутствует']

BAD_AVAILABLE_ORDER = ['', 'Заказать']

BAD_PRICE = ['руб', 'руб.', 'Р']

# Функция для подключения к базе данных с аргументированным параметром.

def len_base(sql):

cur = CONNECTION.cursor()

cur.execute(sql)

row = cur.fetchall()

return row

# Функция для стандартизации строки о наличии товара.

def fix_available(prod):

if prod[3] in BAD_AVAILABLE_YES:

new_3 = 'В наличии'

return [prod[0], prod[1], prod[2], new_3, prod[4]]

elif prod[3] in BAD_AVAILABLE_NO:

new_3 = 'Нет в наличии'

return [prod[0], prod[1], prod[2], new_3, prod[4]]

elif prod[3] in BAD_AVAILABLE_ORDER:

new_3 = 'Под заказ'

return [prod[0], prod[1], prod[2], new_3, prod[4]]

else:

return [prod[0], prod[1], prod[2], prod[3], prod[4]]

# Аналогичная функция - для цены товара.

def fix_price(prod):

price_drob = prod[2].split(' ')

price_drob[0] = price_drob[0].replace(u'от', '')

price_drob[0] = price_drob[0].replace(',', '.')

if price_drob[-1] in BAD_PRICE:

price_drob.pop()

new_price = ''.join(price_drob)

return [prod[0], prod[1], '{:.2f}'.format(float(new_price)), prod[3], prod[4]]

elif price_drob[-1] == '':

new_price = '-'

return [prod[0], prod[1], new_price, prod[3], prod[4]]

else:

new_price = ''.join(price_drob)

return [prod[0], prod[1], '{:.2f}'.format(float(new_price)), prod[3], prod[4]]

# В данном блоке происходит вывод информации о количестве товаров в действующей базе данных.

ob = len_base("SELECT * FROM main;")

print('Total old: ', len(ob))

time.sleep(3)

# На данном этапе происходит полная очистка базы данных с проверкой вывода о количестве товаров.

clean_b = len_base("TRUNCATE TABLE main")

print('Clean base.')

print('Total cleaning base: ', len(clean_b))

time.sleep(3)

# Основной блок. Здесь происходит заполнение базы данных и исправление «не стандартных» параметров товара.

print('Filling base:')

for shop in FILE:

print(shop)

with open(shop, 'r', encoding='utf-8') as data:

reader = csv.reader(data)

for i in reader:

new_prod = fix_available(i)

new_price = fix_price(i)

sql = "INSERT INTO `main` (`title`, `name`, `price`, `available`, `url`) VALUES (%s, %s, %s, %s, %s)"

CONNECTION.cursor().execute(sql, (new_prod[0], new_prod[1], new_price[2], new_prod[3], new_prod[4]))

CONNECTION.commit()

# Снова проверим, сколько значений занесли в базу и закроем подключение.

ob_new = len_base("SELECT * FROM main;")

CONNECTION.close()

print('Total new base: ', len(ob_new))

Для автоматизации выполнения этого скрипта через определенные промежутки времени используем программу-демон cron. В нашем случае, необходимо запускать go.sh каждый день в полночь, команда будет выглядеть так:

00 00 * * * /home/sharkk/PythonProjects/Diplom/go.sh

Данную команду необходимо записать в файл конфигурации cron, которой по умолчанию находится в разделе /etc/crontab.

Дополнение.

В связи с тем, что web-сайт магазина «Аксон» очень тяжеловесный, т. е. содержит JavaScript и на загрузку отдельных страниц выделяется значительное количество оперативной памяти и вычислительной мощности процессора, то Shell-скрипт будем запускать на домашнем ПК. А сам скрипт подправим командами подключения к серверу с помощью SSH-протокола и обновления базы на сервере.

3.1 Особенности программной реализации

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

# Здесь мы импортируем основные библиотеки, которые нам нужны для работы

import requests

import csv

import time

from bs4 import BeautifulSoup

# Функция для получение HTML текста, в качестве аргумента в которую передаем url-адрес. В случает не получения ответа от страницы в течении 60 секунд происходит вывод сообщения об отсутствии подключения и щасыпании программы на 60 секунд.

def get_html(url):

while True:

try:

html = requests.get(url, timeout=60)

except Exception:

print('Нету подключения к сети, ожидание 60 секунд')

time.sleep(60)

continue

break

return html.text

# Функции обработки HTML библиотекой BeautifulSoup, в качестве внутреннего парсера используем lxml, т. к. он наиболее скоростной.

def get_soup(html):

soup = BeautifulSoup(html, 'lxml')

return soup

# Функции открытия файла (если файла не существует, он создаст) на до запись (аргумент «а») и записи необходимых данных в столбцы файла.

def write_csv(name, data):

with open(name, 'a') as file:

writer = csv.writer(file)

writer.writerow((data['title'], data['name'], data['price'], data['available'], data['url']))

Для примера, рассмотрим программный код одного из магазина.

# Импортируем наш модуль.

import module

# В качестве констант укажем: основной адрес, загрузка каталога с выводом 120 товаров и битые страницы.

URL = 'http://www.kontinent.ru/'

SHOW_120 = '?price_min=&price_max=&photo=N&sort=price_up&page=1&countonpage=120'

PAGE = '&page='

BAD_URL = ['http://www.kontinent.ru/catalog/germetiki-peny/']

# Для проверки, что сбор информации происходит с г. Вологда, выводим к примеру телефон магазина.

def get_tel(url):

soup = module.get_soup(module.get_html(URL))

tel = soup.find('div', class_='contacts').text.strip()

return tel

# В этой функции мы получаем основной список каталога магазина, т. е. захватываем HTML и парсим его в соответствии с необходимой нам информацией (url адресов).

def get_main_url(url):

soup = module.get_soup(module.get_html(url))

pages = soup.find('div', class_='catlog_menu_block_mobile').find('ul', class_='catalog_menu').find_all('li')

links = []

for i in pages:

page = i.find('a').get('href')

add_link = url[:-1] + page

if add_link in BAD_URL:

print('Delete this URL', add_link)

continue

links.append(add_link)

return links

# В этой функции мы получаем количество страниц, которое необходимо посетить для сбора информации. Аналогично разбираем страницу и из нужного нам блока извлекаем количество страниц.

def get_total_page(url):

soup = module.get_soup(module.get_html(url))

pages = soup.find('div', class_='pagination').find_all('li')[-1].text

return int(pages)

# Функция для сбора необходимой информации, в случает отсутствия информации -- ничего не записываем, в случает отсутствия продуктов в каталоге, выводим информацию об ее отсутствии. И с использованием модульной функции создаем файл csv и записываем в него всю информацию о продукте.

def get_data(url):

soup = module.get_soup(module.get_html(url))

try:

data = soup.find('div', class_='products_block').find_all('div', class_='cart')

except:

return print('Нет данных на странице')

for i in data:

try:

name = i.find('div').find('a').text.split()

name = ' '.join(name)

except:

name = ''

try:

url = URL[:-1] + i.find('div').find('a').get('href').strip()

except:

url = ''

try:

price = i.find('span', class_='price_one').text.strip()

except:

price = i.find('span', class_='price_new').text.strip()

try:

available = i.find('button', class_='buy_button')

if available:

available = 'В наличии'

else:

available = 'Нет в наличии'

except:

available = ''

title = 'Континент'

data = {'title': title, 'name': name, 'price': price, 'available': available, 'url': url}

module.write_csv('kontinent.csv', data)

# Основная функция, которая содержит в себе все функции. Для начала просто выводим информации о работе с сайтом. Далее создаем список и каждую ссылку допишем адресом о выводе 120 товаров на странице и выведем название этой страницы с количеством страниц товаров. В заключительном цикле пробегаем по страницам и записываем информацию в csv файл и выводим сообщение о завершении работы с этой страницей.

def main():

print('Континент')

print(get_tel(URL))

for i in get_main_url(URL):

link = i + SHOW_120

print(link)

total_page = get_total_page(link)

print(i, total_page)

for j in range(1, total_page+1):

page = link + PAGE + str(j)

get_data(page)

print(j, 'checked')

# Эта конструкция завершает программу и она нужна в случае импортирования этого файла, как модуля. Таким образом основной блок функции запущен не будет.

if __name__ == '__main__':

main()

Так как в списке магазинов оказались web-сайты написанные с использованием JavaScript по технологии AJAX (подход к построению веб-приложений, заключающийся в фоновом обмене данными, таким образом при обновлении данных страница не перезагружается полностью), то простым запросом страницы здесь не обойтись. На этот случай воспользуемся Selenium Webdriver. Он эмулирует работу обычного браузера с нажатием на ссылки и переходом между страниц. Рассмотрим основные только основные функции.

# Импортируем основные модули для работы программы. Это сам драйвер, модуль предопределенных условий и неявных ожиданий.

import module

from selenium import webdriver

from selenium.webdriver.common.by import By

from selenium.webdriver.support.ui import WebDriverWait

from selenium.webdriver.support import expected_conditions as EC

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

def get_data(url):

while True:

# В данном блоке обработки исключений, пытаемся загрузить браузер и получить страницу в течении 30 секунд, в противном случае - будем ждать подключение к интернету.

try:

driver = webdriver.PhantomJS()

driver.set_page_load_timeout(30)

print('Good!')

driver.get(url)

# В данном блоке, когда браузер загрузил страницу, происходит ожидание появление элемента «'item-list-next-page», т.е. переход на следующую страницу товаров, в течение 20 секунд. Как только элемент появится, браузер загрузит HTML-код и отдаст его на распарсинг BeautifulSoup, который в свою очередь извлечёт всю необходимую информацию о товарах. Затем произойдет нажатие на этот элемент, в нашем случае - это переход на следующую страницу. И так до тех пор пока не дойдет до конца.

try:

f = True

while f:

WebDriverWait(driver, 20).until(EC.presence_of_element_located((By.CLASS_NAME, 'item-list-next-page')))

html = driver.page_source

soup = module.get_soup(html)

page = soup.find('div', class_='pages').find('a', class_='page active').text

print(url, f, page)

data = soup.find('div', class_='catalog-items-list').find_all('div', class_='item-list-block')

for i in data:

try:

name = i.find('div', class_='name').text.split()

name = ' '.join(name)

except:

name = ''

try:

data_url = i.find('div', class_='name').find('a').get('href')

data_url = 'http://evrostroy.biz' + data_url

except:

data_url = ''

try:

price = i.find('div', class_='price').find('em').next_element.strip()

except:

price = ''

try:

available = i.find('div', class_='to-basket').find('span', class_='add-to-basket-popup').previous_element

except:

available = ''

title = 'Еврострой'

write_data = {'title': title, 'name': name, 'price': price, 'available': available, 'url': data_url}

module.write_csv('evrostroy.csv', write_data)

f = driver.find_element_by_class_name('item-list-next-page').is_displayed()

d = driver.find_element_by_xpath("//div[@class='item-list-next-page']/a")

d.click()

except:

print('No')

break

except:

driver.quit()

print('TimeOut 60 sec')

module.time.sleep(60)

Так как в данном проекте вывод информации происходит на сайт, то рассмотрим и этот момент отдельно.

На странице есть форма запроса. И при вводе сообщения она отправляет его на сервер, тот в свою очередь перенаправляет его к Django.

<form action="/search/" method="GET">

<input type="text" name="q"/>

<input type="submit" value="Показать"/>

</form>

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

# В данной функции происходит разбиение текстового сообщения и формирования из него запроса для базы данных.

def get_query(s):

l = s.split()

search = {}

if 'or' in s:

for i in range(len(l)):

if l[i] == 'or' or l[i] in search.values():

continue

elif i == len(l) - 1:

search[l[i]] = None

break

elif l[i + 1] != 'or':

search[l[i]] = None

else:

search[l[i]] = l[i + 2]

else:

for i in l:

search[i] = None

s_l = "name LIKE '%"

s_or = ' OR '

s_and = ' AND '

itog = 'SELECT * from main WHERE '

for i, v in search.items():

if v == None:

itog += "(" + s_l + i + r"%'" + ")" + s_and

elif v != None:

itog += "(" + s_l + i + r"%'" + s_or + s_l + v + r"%'" + ")" + s_and

if itog[-1] == ')':

return itog + 'LIMIT 3000;'

else:

return itog[:-5] + 'LIMIT 3000;'

# В данной функции происходит уже сам запрос к базе данных и извлечение данных в виде списка списков.

def get_name(request):

q = request.GET['q']

connection = pymysql.connect(host='localhost',

user='root',

password='password',

db='parser35',

charset="utf8")

cur = connection.cursor()

sql = get_query(q)

cur.execute(sql)

# data['title'], data['name'], data['price'], data['available'], data['url']

data = [row for row in cur.fetchall()]

return render(request, 'page/search.html', {'data': data, 'query': q})

Вернемся обратно к html-файлу. В этом блоке и происходит проход по списку и составлению html-тегов.

{% else %}

<ol>

{% for i in data %}

<li><a href="{{i.4}}"><span><b>{{i.0}}</b> - {{i.1}}<span class="available">{{i.3}}</span></span><em>{{i.2}}</em></a></li>

{% endfor %}

</ol>

{% endif %}

На данном этапе рассмотрели все интересные моменты программного содержания проекта.

3.2 Обеспечение безопасности

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

Ш Хостинг (серверная часть);

Ш Программная часть (CMS, движок сайта, скрипты и т.д.);

Ш Администрирование.

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

Для безопасности программной части приведем наиболее распространенные случаи:

Ш Регулярное обновление программного обеспечения.

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

Ш SQL инъекции.

В нашем случае Django практически не подвержен такому виду атаки, но в любом случае стоит использовать параметризованные запросы.

Ш XSS (Cross Site Scripting).

Использование шаблонов Django защитит от большинства XSS атак, но тем не менее следует проверять данные, кодировать, обрезать или удалять сторонние HTML вставки.

Ш Средства безопасности.

Необходимо регулярно выполнять поиск уязвимостей с помощью специально подготовленных инструментов, например, дистрибутив Kali Linux. Он содержит множество инструментов для тестирования, так как nmap, Burn Suite, SQLMap, Metasploit и других.

Целесообразно остановиться на этом и рассмотреть немного подробнее. Kali Linux - это GNU/Linux-LiveCD проект, предназначенных прежде всего для проведения тестов на безопасность. С его помощью можно обнаружить уязвимости и ошибки, которые могут использовать злоумышленники. Тестирование на безопасность включает очень много разнообразных инструментов и задач, но так как в нашем проекте используется сайт, то рассмотрим поиск уязвимостей для него.

Поиск уязвимостей на сайте состоит из нескольких этапов:

Ш Разведка - сбор информации о сети и сервере;

То, что это наш сайт, это ничего не значит, нам все равно нужно знать, что о нем могут узнать другие люди.

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

Ш Сканирование - проверка сайта на уязвимость в соответствии с собранной информацией;

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

Burn Suite - очень мощная программа для поиска уязвимостей на сайтах или других веб-приложениях, но работает только через браузер. Она позволяет проверить все формы на сайте, посмотреть ответы и запросы, выполнить активное сканирование URL, анализ кода JavaScript, поиск XSS и многие другие возможности.

SQLMap - специализированная программа для поиска SQL уязвимостей на сайте. Позволяет найти все возможные места, где могут быть выполнены SQL-инъекции. Работает с различными типами баз данных.

Ш Эксплуатация - этот этап не обязательный. Нужен для показа реальной опасности уязвимости;

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

Metasploit - это целая среда для проведения тестов, которая содержит множество готовых эксплойтов.

Ш Исправление - необходимо, по возможности, исправить все найденные уязвимости на сайте.

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

3.3 Руководство оператора

На web-сайте находится все 1 текстовое поле в которое можно вести необходимый запрос. Принцип вывода информации осуществляется по совпадению слова и наименованию товара без учета регистра. Например по запросу «Клей», «КЛЕЙ» или «клей» будет выведена информация по всем клеям: клей плиточный, клей сварочный, клей эпоксидный и т. д.

При вводе длинного запроса, т. е. состоящего из несколько слов, перестановка слов в запросе на результат не влияет, т. е. «клей плиточный» и «плиточный клей» равнозначны.

Дополнение.

После тестирования сайта, была замечена особенность -- некоторые магазины наименование марки товара указывают по разному, например «кнауф» и «knauf». Эта особенность была устранена путем добавления зарезервированного слова «or», таким образом, чтобы получить все товары фирмы «кнауф» необходимо запрос построить, например, так: «плиточный клей кнауф or knauf.

С учетом дополнения, продемонстрируем работу данного приложения в поиске товара: «шпаклевка полимерная финишная белая Weber.Vetonit LR+ 25ru». Следует заметить, что наиболее полный поиск следует осуществлять от большего к меньшему, т. е. для начала необходимо осуществить запрос более общий, например: «шпатлевка or шпаклевка финишная». В данном запросе результат будет достаточно большой.

Рисунок 3.2 - Общий запрос

И просмотрев интересующий нас товар, замечаем что магазины один и тот же продукт называют по-разному:

АПлайн - Шпатлевка «Ветонит VEBER LR+»

ЦентрСМ - Шпаклевка «WEBER.Vetonit LR+»

На основании этих данных и строим заключительный запрос «vetonit or ветонит lr+ 25». Результат виден на рисунке 3.3.

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

Рисунок 3.3 - Заключительный запрос

4. Тестирование и апробация

4.1 Выбор метода тестирования

В качестве тестирования выбираем White/Black/Grey Box-тестирование, как основной тип тестирования.

4.2 Результаты тестирования

В результате тестирования были выявлены следующие погрешности:

Ш Несоответствие вывода информации в ячейках: наличия и стоимость продукта. Данные с магазинов выводились по разному (в ячейке наличия: в наличии, НаличиеЕсть, НаличиеМало, Наличие : Есть, В корзину; в ячейке стоимости: 0 руб, 0 руб., 0, 0.00, 0 Р).

Подгоним информацию под единый стандарт: в ячейке наличия -- В наличии, Нет в наличии и Под заказ; в ячейке стоимости -- 0.00, а если нет цены, будем ставить -.

Ш В разных магазинах марка товара может быть написана, как латиницей, так и кириллицей.

Доработан программный код обработки запроса SQL.

Ш При вводе пустого запроса или запроса заведомо имеющего большое число выводных данных, например запрос вида «а», происходило слишком долгая обработка запроса (250000 строк) в лучшем случае, в худшем -- зависание сервера MySQL.

Доработан программный код. В частности добавлен LIMIT 3000. Таким образом выводимая информация не превысит 3000 строк.

4.3 Расчет и экспериментальная проверка параметров производительности

Так как в нашем проекте сбор информации осуществляется с web-сайтов интернет магазинов, то производительность еще зависит и от скорости интернет соединения, и от производительности сервера магазина.

Для определения размера страницы и времени будем пользовался стандартным приложением браузера Google, при этом учитывалась работа скрипта проекта, т.к. при запросе через библиотеку requests берется «голый» HTML, а при работе через Selenium Webdriver с использованием «безголового» браузера PhantomJS загружается целая страница.

При оценке нагрузки на процессор и выделенной памяти будем пользоваться стандартной командой top в терминале Ubuntu.

Для оценки времени работы приложения напишем дополнительную функцию и обернем им основную функцию.

def timer(func):

start = time.time()

func()

end = time.time()

print(end -- start)

Все полученные сведения сведем в таблицу.

Таблица 4.1 - Сводная таблица производительности

Магазин

Тип

Размер, Kb

Время загрузки, сек

CPU, %

Mem, %

Кол-во записей

Время работы, сек

АПлайн

HTML

146

0.9

20

1.5

11035

774.2

Центр СМ

HTML

961

2

35

2.5

111224

28140.99

Еврострой

HTML,

155

1.88

20

1.5

24878

3515.99

JS

40

5

Континент

HTML

115

1.63

20

1.5

24143

700.6

Лидер

HTML

295

1.37

30

1.5

27836

768.9

СтройОПТторг

HTML

283

1.9

20

1.5

12824

1034.59

Аксон

HTML,

485

3.12

20

1.5

31196

11780.05

JS

50

7

Из сводной таблицы видно, что размер страницы всех магазинов примерно одинаковый, за исключением Центр СМ - размер его страницы почти 1 Мегабайт. По скорости загрузки страницы сайта в аутсайдерах оказался Аксон - больше 3ех секунд. Нагрузка на процессор и расход оперативной памяти возрастает с использованием Selenium Webdriver, что и закономерно, т. к. происходит запуск браузера PhantomJS, хоть он и не имеет GUI, но требует дополнительных ресурсов и времени. Таким образом можно сказать, что время работы скрипта в основном зависит от скорости работы сервера и содержания страницы и в последнюю очередь от количества записей товаров.

4.4 Внедрение

Для внедрения данного проекта был выбран ресурс timeweb [https://timeweb.com/ru/]. В качестве хостинга был выбран vps/vds хостинг (виртуальный сервер Junior) с параметрами: CPU 2x2,7 ГГц, RAM 0.5 Гб, SSD 5 Гб за 190 руб. в месяц. В качестве предустановленной операционной системы выбираем Ubuntu 16.04.

На том же ресурсе был зарегистрирован домен stroy-parser35.ru, годовая стоимость составила 179 руб.

Начальная настройка сервера

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

Ш Добавление нового пользователя с root-правами

Для входа на сервер нам предоставили пароль root-пользователя. Пользователь root является администратор в среде Linux и имеет широкий набор привилегий. Из-за повышенных привилегий не рекомендуется пользоваться на постоянной основе. Причиной этого является возможность случайно внести нежелательные изменения.

$ adduser <user>

$ usermod -aG sudo <user>

Ш Настройка авторизации по открытому ключу

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

$ ssh-keygen

В результате, в поддиректории .ssh домашней директории пользователя создались ключи: id_rsa (закрытый) и id_rsa.pub (открытый). Открытый необходимо хранить на сервере. Скопируем его на наш сервер.

# ssh-copy-id <user>@<IP server>

В результате открытый ключ добавится в файл .ssh/authorized_keys на сервере.

Ш Отключение входа по паролю

Мы можем еще больше защитить сервер путем отключения входа по паролю, т.к. аутентификацию будем осуществлять по SSH. Для этого в конфигурационном файле (/etc/ssh/sshd_config) изменим значение параметра PasswordAutentification с yes на no.

Ш Настройка базового файрвола

Серверы на Ubuntu 16.04 могут использовать файрвол UFW для разрешения тех или иных сервисов. Для соединения с серверов мы используем сервис OpenSSH. Разрешим соединение.

$ sudo ufw allow OpenSSH

И включим сам файрвол.

$ sudo ufw enable

Тем самым мы получили настроенный сервер и можем устанавливать на него необходимое программное обеспечение.

Установка необходимого ПО

Для начала установим систему управления пакетами, которая используется для установки и управления программными пакетами, которые написаны на Python. Так как в проекте используется Python3, установим менеджер пакетов Pip3.

$ sudo apt install python-pip3

И обновим его до последней версии.

$ sudo -H pip3 install --upgrade pip

Для разделения проектов на сервере установим virtualenv -- программа для создания и управления окружениями Python и создадим это окружение. Среда создается в рамках каталога и позволяет использовать свои модули, настройки и т. д.

$ sudo -H pip3 install virtualenv

$ virtualenv env

Активируем виртуальную среду и установим фреймфорк django (джанго), затем создадим проект и перенесем в него уже готовый проект.

$ source env/bin/activate

(env) $ sudo pip install django

(env) $ django-admin.py startproject parser35 .

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

$ sudo apt-get install mysql-server

$ mysql_secure_installation

$ pip install PyMySQL

Для проверки работоспособности проекта добавим разрешение подключения через 8080 порт и запустим сервер разработки.

$ sudo ufw allow 8080

$ (env) $ python manage.py runserver 0.0.0.0:8080

В браузере перейдем по данному адресу и убедимся, что проект работает. Но это сервер для разработки, так оставлять нельзя, поэтому следующим шагом настроим uWSGI.

Дадим объяснение некоторым терминам.

WSGI -- спецификация Python, которая определяет стандартный интерфейс для связи между приложением и веб-сервером. Это было создано для упрощения и стандартизации связи между этими компонентами для обеспечения согласованности и взаимозаменяемости.

uWSGI -- контейнер сервера приложений, целью которого является предоставление полного стека для разработки и развертывания веб-приложений и сервисов. Основным компонентом является сервер приложений, который может обрабатывать приложения разных языков. Он взаимодействует с приложением, используя методы, определенные спецификацией WSGI, и с другими веб-серверами по множеству других протоколов. Это части, которая переводим запросы с обычного веб-сервера в формат, который может обрабатывать приложение.

uwsgi -- быстрый, двоичный протокол, реализованный сервером uWSGI для связи с более полнофункциональным веб-сервером. Это проводной протокол, а не транспортный. Это предпочтительный способ поговорить с веб-серверами, которые отправляют запросы на uWSGI.

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

$ sudo apt install python3-dev

$ sudo -H pip3 install uwsgi

Для проверки запустим uWSGI.

$ uwsgi --http :8080 --module parser35.wsgi

$ uwsgi --http :8080

--home /home/sharkk/django_project/env

--chdir /home/sharkk/django_project/parser35

-w parser35.wsgi

Это не очень хорошо, т.к. пользователь напрямую обращается к uWSGI, между ними должен находится веб-сервер.

Выполнение uWSGI из командной строки полезно для тестирования, но не очень полезно для фактического развертывания. Вместо это будем запускать в режиме «Император» («Emperor mode»), что позволяет мастер-процессу автоматически управлять отдельными приложениями с учетом файлов конфигурации.

Файлы конфигурации будем хранить в одном месте /etc/uwsgi/sites. Внутри создадим конфигурационный файл parser35.ini с определенными параметрами. И пробуем запустить.

$ uwsgi --ini parser35.ini

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

$ sudo apt install nginx

В файрволе разрешим доступ к нашему серверу.

$ sudo ufw allow 'Nginx Full'

Создадим файл конфигурации блока сервера для проекта в директории /etc/nginx/sites-available/parser35, который будет содержать параметры сервера: порт, доменное имя, расположение статики, а так же параметры uWSGI.

Затем свяжем файл конфигурации с каталогом сайтов с поддержкой Nginx и перезапустим его.

$ sudo ln -s /etc/nginx/sites-available/parser35 /etc/nginx/sites-enabled

$ sudo systemctl restart nginx

И запустим uWSGI в качестве демона.

$ sudo uwsgi -d --ini parser35.ini

На данном этапе внедрение закончилось.

Заключение

В заключительной части проекта осветим основные моменты, которые были реализованны:

Ш Программы для сбора информации с web-сайтов написаны на языке Python с использованием встроенных и внешних библиотек;

Ш Был разработан простой сайт на HTML/CSS в основном для вывода информации для динамической его составляющей применили CMS Django;

Ш Для внедрения был куплен VDS (выделенный облачный сервер) с ОС Ubuntu 16.04;

Ш На сервере было настроено соответствующее программное обеспечение для связки: Пользователь -- Nginx -- Socket -- uWSGI -- Django;

Ш Для автоматизации запуска скриптов применили Shell.

На этом проект не заканчивает свое развитие и стоит упомянуть о дальнейшем развитии:

Ш На сайте добавить такие моменты, как карта, отзывы, контакты и т.д.;

Ш Добавить сортировку по цене, возможность применить скидку магазина, отключение товаров, которых нет в наличии и т.д.;

Ш По возможности добавить магазинов, таких как электрику, сантехнику и т.д.;

Ш Применить SEO оптимизацию.

Список используемой литературы

1. Райан Митчелл Скрапинг веб-сайтов с помощью Python // 2016.

2. А. Милосердов, Д. Гриднев Тестирование на проникновение с помощью Kali Linux 2.0

Размещено на Allbest.ru


Подобные документы

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.