CoderCastrov logo
CoderCastrov
Парсинг

Парсинг и скрапинг: сбор информации для целей машинного обучения.

Парсинг и скрапинг: сбор информации для целей машинного обучения.
просмотров
9 мин чтение
#Парсинг

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

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

HTML "сообщает" веб-браузерам, когда, где и какой элемент показывать на веб-странице. Мы можем представить это как карту, которая указывает водителям маршрут: когда начинать, где поворачивать налево или направо и куда идти. Вот почему структура HTML-страниц так удобна для извлечения информации. Вот простой фрагмент HTML-кода:

Два тега 'h1' и 'p' указывают браузеру, что и как показывать на странице, и поэтому эти маркеры являются ключами для нас, которые помогают получить информацию, которую мы именно нужна. Существует множество информации о HTML и его основных тегах (‘h1’, ‘p’, ‘html’ и т. д. - это все теги), поэтому вы можете изучить это более подробно, потому что мы сосредоточимся на процессе парсинга. И для этой цели мы будем использовать библиотеку Python BeautifulSoup.

Прежде чем узнать, как извлекать информацию непосредственно онлайн, давайте загрузим небольшую HTML-страницу в виде текстового файла из нашей папки. (нажмите ссылку и загрузите файл в папку с блокнотом Yupiter), так как иногда мы можем работать уже скачанными файлами.

Наш файл состоит из нескольких тегов, и нужная информация содержится во втором теге 'p'. Чтобы получить ее, мы должны "подать" модулю BeautifulSoup весь HTML-код, чтобы он мог парсить его и найти то, что нам нужно.

Функция ‘.find_all’ собирает все блоки 'p' из нашего файла. Мы просто выбираем нужный элемент 'p' из списка по определенному индексу и оставляем только текст внутри этого тега.

Но когда в коде много однородных тегов (например, 'p') или когда с одной страницы на другую изменяется номер нужного абзаца, такой подход не сработает. В настоящее время почти каждый тег содержит специальные атрибуты, такие как 'id', 'class', 'title' и т. д. Чтобы узнать больше об этом, вы можете искать информацию о CSS и SSL. Для нас эти атрибуты являются дополнительными якорями для извлечения именно нужного абзаца (в нашем случае). Используя функцию ‘.find’, мы получим не список, а только 1 элемент (убедитесь, что такой элемент есть только один на странице, потому что в противном случае вы можете упустить какую-то информацию.)

В эпоху динамических страниц, которые имеют различные CSS-стили для разных типов устройств, вы часто столкнетесь с проблемой изменения имен атрибутов тегов. Или они могут немного изменяться с одной страницы на другую в зависимости от другого содержимого на ней. В случае, когда имена нужных блоков тегов полностью различаются, нам придется настроить сложную "архитектуру" парсинга. Но обычно в этих отличающихся именах есть общие слова. В нашем игрушечном случае у нас есть два абзаца с словом "main" в атрибуте 'class' в обоих случаях.

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

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

Представьте, что у нас есть задача анализировать, есть ли связь между заголовками основных новостей и ценой на Биткоин? С одной стороны, нам нужно собрать новости о Биткоине за определенный период, а с другой стороны - цену. Для этого нам нужно подключить несколько дополнительных библиотек, включая "selenium". Затем скачайте chromedriver и поместите его в папку с блокнотом Jupyter. Selenium связывает скрипт на Python с браузером Chrome и позволяет нам отправлять команды и получать HTML-код загруженных страниц.

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

https://www.google.com/search?q=bitcoin&num=100&biw=1920&bih=938&source=lnt&tbs=cdr%3A1%2Ccd_min%3A12%2F11%2F2018%2Ccd_max%3A12%2F11%2F2018&tbm=nws

“search?q=bitcoin” - слово или фраза, которую мы ищем “num=100” - количество заголовков “cd_min%3A12%2F11%2F2018” - начальная дата “cd_max%3A12%2F11%2F2018” - конечная дата

Давайте попробуем загрузить новости с ключевым словом "bitcoin" за 15 января 2018 года.

Мы везучие): правильная страница, правильное ключевое слово и правильная дата. Чтобы продолжить, нам нужно изучить HTML-код и найти теги (якоря), которые позволят нам получить необходимую информацию. Самым удобным способом является использование кнопки "inspect" в контекстном меню правой кнопки мыши веб-браузера Google Chrome (или аналогичной в других браузерах). См. скриншот.

Как видим, тег 'h3' отвечает за блок с заголовками новостей. У этого тега есть атрибут class="r dO0Ag". Но в данном случае мы можем использовать только тег 'h3' в качестве якоря, потому что он используется только для выделения заголовков.

**Внутри блоков 'h3' есть много **дополнительных тегов, поэтому мы используем цикл ниже, чтобы очистить их, оставив только текст.

Вот и все. Мы получили 44 заголовка новостей за 15 января 2018 года. Также мы можем получить несколько начальных предложений из этих новостей и использовать их в будущем анализе.

Но 1 день в истории - это недостаточно для обнаружения корреляции. Поэтому мы создадим список из 10 дат (для образовательных целей) и настроим цикл парсинга, чтобы получить новости для всех этих дат. Совет: если вы хотите изменить язык новостей, когда первая страница загружается во время выполнения скрипта, измените язык в настройках вручную или через несколько минут вы узнаете, как это сделать с помощью алгоритма.

Но если бы это было так просто, то это не было бы так интересно.

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

Давайте откроем пример страницы на "Yahoo! Finance": https://finance.yahoo.com/quote/SNA/history?p=SNA. Если вы прокрутите страницу вниз, вы увидите, что контент загружается периодически, и в конце концов он достигает последней строки "Dec 13, 2017". Но когда страница только открыта, и мы просматриваем исходный код (Ctrl+U для Google Chrome), мы не найдем там "Dec 13, 2017". Поэтому, чтобы получить данные со всеми датами для этого символа, сначала мы должны прокрутить страницу до конца, а затем разобрать страницу. Такой код поможет нам решить эту проблему (чтобы узнать различные способы прокрутки, посмотрите здесь https://goo.gl/JdSvR4)::)

Есть много веб-сайтов, которые предпочитают разделять одну статью на две и более части, поэтому вам приходится нажимать кнопки "следующая" или "предыдущая". Наша задача - открыть все эти страницы и собрать их). Та же задача стоит перед многостраничными каталогами. Вот пример: мы откроем несколько страниц в каталоге тегов stackoverflow.com и соберем топ-слова тегов с их частотой через портал. Для этого мы будем использовать метод find_element_by_css_selector() для нахождения определенного элемента на странице и нажатия на него с помощью метода click(). Чтобы узнать больше о нахождении элементов, откройте это: https://goo.gl/PyzbBN

Или вот еще один пример: на сайте medium.com часть комментариев под статьями скрыта. Но если нам нужно проанализировать "причины" популярности страницы, комментарии могут сыграть большую роль в этом анализе, и лучше собрать их все. Откройте эту страницу и прокрутите вниз - вы увидите, что там есть кнопка "Показать все ответы" в виде элемента "div". Давайте нажмем на нее и откроем все комментарии.

Авторизация и поля ввода

Много информации доступно только после авторизации. Итак, давайте научимся входить в Facebook. Алгоритм такой же: найти поля ввода для логина и пароля, вставить текст в них, а затем отправить. Для отправки текста в поля мы будем использовать метод .send_keys(), а для отправки: метод .submit().

Но эти методы также очень полезны, когда нам нужно изменить даты или вставить значения в поля ввода, чтобы получить определенную информацию. Например, вот "инструмент на одной странице" для получения информации о потоках фондов ETF: Etf Fund Flows. Здесь нет специальных страниц для каждого ETF (как у Yahoo!), чтобы просматривать или загружать нужные значения. Все, что вы можете сделать: ввести символ ETF, начальную и конечную даты и нажать кнопку "Отправить". Но если ваш босс поставит задачу получить исторические данные для 500 ETF и 10 последних лет (120 месяцев), вам придется нажать 60000 раз кнопку "Отправить". Какая скучная забава... Итак, давайте создадим алгоритм, который может собрать эту информацию, пока вы будете бесноваться где-то на вечеринке в Ибице.

Существует огромное количество сайтов, и каждый из них имеет свой собственный дизайн, доступ к информации, защиту от роботов и т. д. Поэтому этот учебник может быть как небольшой книгой. Но по крайней мере, мы откроем еще один подход к парсингу информации. Он связан с анализом динамических графиков, как, например, использует www.google/trends. Интересно, что программисты Google не разрешают анализировать код графиков трендов (тег div, содержащий код графика, скрыт), но позволяют вам загружать csv-файл с информацией (так что мы можем использовать один из вышеуказанных алгоритмов, чтобы найти эту кнопку, нажать и загрузить файл).

Давайте возьмем другой сайт, где мы можем анализировать подобные графики: Portfolio Visualizer. Прокрутите эту страницу вниз, и вы найдете график, как на скриншоте. Ценность этого графика заключается в том, что исторические цены на американские казначейские облигации не являются бесплатными - их нужно покупать. Но здесь мы можем их получить либо вручную (переписывая даты и значения соответственно), либо написать код, который "перепишет" значения для нас, и не только с этой страницы...

В заключение

Важно признать, что парсинг активности может легко быть определен как активность робота, и вам будет предложено пройти "антиробот" капчу. С одной стороны, вы можете найти решения, как дать правильные ответы на нее, но с другой стороны (я думаю, более естественным), вы можете настроить такие алгоритмы, которые будут похожи на человеческую активность при использовании веб-сайтов. Вам повезло, если веб-сайт не имеет защиты от парсинга. Но в случае с Google News - после 10 или 20 загрузок страницы вы столкнетесь с капчей Google. Поэтому попытайтесь сделать свой алгоритм более похожим на человека: прокручивайте вверх и вниз, нажимайте ссылки или кнопки, находитесь на странице как минимум 10-15 секунд или больше, особенно когда вам нужно загрузить несколько тысяч страниц, делайте перерывы на час и на ночь и т. д.

Здесь вы можете скачать jupyter notebook.

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

И удачи!


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