Почему стоит научиться «парсить» сайты, или как написать свой первый парсер на Python -10


AliExpress RU&CIS

В этой статье я постараюсь понятно рассказать о парсинге данных и его нюансах.



image

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

Перейдем к этапам парсинга.

  • Поиск данных
  • Извлечение информации
  • Сохранение данных

И так, рассмотрим первый этап парсинга — Поиск данных.


Так как нужно парсить что-то полезное и интересное давайте попробуем спарсить информацию с сайта work.ua.
Для начала работы, установим 3 библиотеки Python.

pip install beautifulsoup4

Без цифры 4 вы ставите старый BS3, который работает только под Python(2.х).

pip install requests
pip install pandas


Теперь с помощью этих трех библиотек Python, можно проанализировать нашу веб-страницу.

Второй этап парсинга — Извлечение информации.


Попробуем получить структуру html-кода нашего сайта.
Давайте подключим наши новые библиотеки.

import requests
from bs4 import BeautifulSoup as bs
import pandas as pd

И сделаем наш первый get-запрос.

URL_TEMPLATE = "https://www.work.ua/ru/jobs-odesa/?page=2"
r = requests.get(URL_TEMPLATE)
print(r.status_code)

Статус 200 состояния HTTP — означает, что мы получили положительный ответ от сервера. Прекрасно, теперь получим код странички.

print(r.text)

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

<h2 class="add-bottom-sm"><a href="/ru/jobs/3682040/" title="Комірник, вакансия от 5 ноября 2019">Комірник</a></h2>


У нас есть тег h2 с классом «add-bottom-sm», внутри которого содержится тег a. Отлично, теперь получим title элемента a.

soup = bs(r.text, "html.parser")
vacancies_names = soup.find_all('h2', class_='add-bottom-sm')
for name in vacancies_names:
    print(name.a['title'])

Хорошо, мы получили названия вакансий. Давайте спарсим теперь каждую ссылку на вакансию и ее описание. Описание находится в теге p с классом overflow. Ссылка находится все в том же элементе a.

<p class="overflow">Some information about vacancy.</p>


Получаем такой код.

vacancies_info = soup.find_all('p', class_='overflow')
for name in vacancies_names:
    print('https://www.work.ua'+name.a['href'])
for info in vacancies_info:
    print(info.text)

И последний этап парсинга — Сохранение данных.


Давайте соберем всю полученную информацию по страничке и запишем в удобный формат — csv.

import requests
from bs4 import BeautifulSoup as bs
import pandas as pd

URL_TEMPLATE = "https://www.work.ua/ru/jobs-odesa/?page=2"
FILE_NAME = "test.csv"


def parse(url = URL_TEMPLATE):
    result_list = {'href': [], 'title': [], 'about': []}
    r = requests.get(url)
    soup = bs(r.text, "html.parser")
    vacancies_names = soup.find_all('h2', class_='add-bottom-sm')
    vacancies_info = soup.find_all('p', class_='overflow')
    for name in vacancies_names:
        result_list['href'].append('https://www.work.ua'+name.a['href'])
        result_list['title'].append(name.a['title'])
    for info in vacancies_info:
        result_list['about'].append(info.text)
    return result_list


df = pd.DataFrame(data=parse())
df.to_csv(FILE_NAME)


После запуска появится файл test.csv — с результатами поиска.

«Кто владеет информацией, тот владеет миром» (Н. Ротшильд).




Комментарии (23):

  1. mSnus
    /#23272154

    следующая статья будет про "что такое скрэпинг"))

  2. KorP
    /#23272190

    Пока писалась статья, уже классы на work.ua все поменяли :)

    • kasigor
      /#23273608

      У меня парсер на work.ua с ноября 2019 работает. Сейчас проверил, все работает. Зачем пугаете? :)

  3. dimuska139
    /#23272252 / -1

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

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

    Статус 200 состояния HTTP — означает, что мы получили положительный ответ от сервера

    Увы, не всегда так. Некоторые сайты и на несуществующую страницу отдают код 200 и пишут "Страница не найдена".

    P.s. зачем тут Pandas я вообще не понял, если честно

    • zazar
      /#23272286

      зачем тут Pandas я вообще не понял, если честно

      Видимо, чтобы записать CSV.........

      • dimuska139
        /#23272310

        Тогда логичный вопрос: чем модуль csv не угодил?)

    • koreychenko
      /#23272352

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

    • vectorplus
      /#23272436

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

      Панды нужны для того, чтобы датафрейм сделать.

      • dimuska139
        /#23272466

        Однако таким способом большие сайты (да и не очень большие) вы будете парсить очень долго, потому что библиотека requests не подходит для асинхронных запросов - и все страницы будут скачиваться строго последовательно. То есть этот пример в статье вообще не годится для использования в большинстве случаев.

        • vectorplus
          /#23272516

          Спасибо, буду знать. Я года три назад проходил курс по скрапингу и парсингу от университета Мичигана, там именно requests использовали. Я потом написал своего паука, но сильно разгуляться не смог, меня быстро забанили в гугле за частые запросы, так что, опытанакопить не получилось.

          А какие библиотеки вы бы посоветовали?

          • dimuska139
            /#23272550

            Ну, во-первых, есть библиотека (можно даже сказать фреймворк) для парсинга, явно достойный внимания - это Scrapy. Во-вторых, если уж хочется руками писать побольше, то есть aiohttp или httpx. С помощью этих библиотек можно делать асинхронные запросы к сайту (т.е. делать запросы к следующим страницам, не дожидаясь, пока загрузятся предыдущие, грубо говоря). Единственное, бездумно лупить кучами асинхронных запросов тоже не стоит - надо ограничивать RPS, конечно, с помощью того же семафора из Asyncio. Соответственно, чтобы не банили, так же нужно менять UserAgent (например, с помощью fake-useragent), а также использовать прокси. Ну а для разбора html библиотека beautifulsoup4, упомянутая автором статьи, годится.

          • zazar
            /#23273160

             проходил курс по скрапингу

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

            Логично, что курс не очень - не учитывает некоторые тонкости.

            • vectorplus
              /#23273902

              Учитывая то, что специализация называется Python for Beginners, а на скрапинг был выделен 1 (один) урок, то некоторые тонкости наверняка были упущены :)

          • Tihon_V
            /#23274854

            httpx для получения контента. Он гораздо проще чем aiohttp, неплохо масштабируется и поддерживает работу с прокси.

            lxml для парсинга. Изучение XMLPath/JSONPath сильно упрощает жизнь с разнородными источниками сериализованных данных независимо от языка программирования. Не стоит писать код привязаный к beautifulsoup в случаях, когда можно ограничится одним запросом.

            Наверняка пригодится fake_useragent и умение обращатся с каким-нибудь http/socks-прокси. Для сайтов с динамическим содержимым нужно ещё уметь работать с headless версией браузера.

  4. zazar
    /#23272280 / +1

    Как обойти последнюю версию CloudFlare? Не даёт себя парсить в упор.

    • victoriously
      /#23272642 / +1

      cloudscraper. Когда я его использовал с месяц-два назад, он в 4/5 случаев выдавал страницу вместо заглушки. С учетом того, что работает аналогично requests, и заменять ничего не нужно было, меня такой результат устроил.

      • zazar
        /#23273162

        Пользовал все библиотеки, какие на Питоне есть. только на заглушку смотрел...

    • Tihon_V
      /#23274878

      1. Не спрашивать больше 2 конкурентных запросов в секунду, для большего количества – использовать прокси.

      2. Добавлять referrer с ссылкой на корневую страницу домена, а так же accept-language.

      3. Использовать актуальный и популярный user-agent

  5. Barbaresk
    /#23272568 / +1

    Если на сайте особой защиты нет, то самый простой способ парсинга - userscripts, сохранение в local storage + rucpatcha. Код парсера - чистый js с селекторами и всё по сути. И обходим потихоньку сайт. Если нужно - добавляем вызовы api решателя капч, добавляем внешние api если нужно хранить не в local storage.

  6. debagger
    /#23272894

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

  7. shaman4d
    /#23273174

    Так и не увидел ответ на "почему стоит научиться".