CoderCastrov logo
CoderCastrov
Парсер

Парсинг данных в реальном времени с использованием Python

Парсинг данных в реальном времени с использованием Python
просмотров
6 мин чтение
#Парсер

Используем Selenium и Beautifulsoup для получения актуальных данных

Контекст

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

Эта статья наиболее подходит для программистов, знакомых с Python.

Парсинг

pip install bs4
pip install selenium

Чтобы сделать простое различие, нам понадобится Selenium, чтобы перейти на веб-сайт, взаимодействовать с браузером, нажимать кнопки и ждать появления элементов. Затем BeautifulSoup используется для итерации по HTML и извлечения фактических данных (того, что вы видите).

  1. Теперь мы изучаем веб-сайт. Как вы можете видеть на картинке ниже, требуется примерно 5 секунд ожидания, чтобы данные были правильно загружены.
Идет загрузка данных (иконка) Загруженные данные в HTML

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

Щелкнув правой кнопкой мыши и нажав кнопку "Инспектировать элемент" на веб-сайте, мы видим в интерфейсе инспекции, что элемент, который нам нужно ждать, это <div> с классом dataTables_scrollBody.

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

Для парсинга веб-сайта библиотека Selenium требует, чтобы у нас был браузер Google Chrome (вы также можете использовать другой браузер). Поэтому мы говорим Selenium запустить Google Chrome

from selenium import webdriver
driver = webdriver.Chrome(ChromeDriverManager().install())

и говорим драйверу, где находится наш веб-сайт, передавая его URL

driver.get("https://severeweather.wmo.int/v2/list.html")

Теперь мы можем установить вышеупомянутый прослушиватель, чтобы драйвер ждал появления элемента <div> с классом dataTables_scrollBody в HTML

try:        
  **elem = WebDriverWait(driver, 30).until(    EC.presence_of_element_located((By.CLASS_NAME, "dataTables_scrollBody")))**
 finally:        
  print('loaded')

Мы определяем нашу функцию парсинга как parseWeather и наш код на этом этапе должен выглядеть примерно так:

### импорты
import pandas as pd
from bs4 import BeautifulSoup
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
from webdriver_manager.chrome import ChromeDriverManager###def scrapeWeather(): # Наша функция для парсинга   
driver = webdriver.Chrome(ChromeDriverManager().install()) # запрос URL
driver.get("https://severeweather.wmo.int/v2/list.html")  try:        
  elem = WebDriverWait(driver, 30).until(    EC.presence_of_element_located((By.CLASS_NAME, "dataTables_scrollBody")))
 finally:        
  print('loaded')
  1. Теперь, когда данные находятся в HTML, мы можем выбрать записи, которые хотим спарсить с помощью BeautifulSoup.

Как мы видим из инспекции, все данные находятся в теге <tbody>. Каждый тег <tr> содержит одну запись (строку) в таблице. Поэтому мы должны найти правильный <tbody> и начать перебирать все его теги <tr>. Мы делаем это с помощью функции findAll, которая находит все записи HTML-тега.

soup = BeautifulSoup(driver.page_source, 'html.parser')    """Парсер получает каждую строку"""    
all = soup.**findAll**("tbody")[2] #третий <tbody> - тот, который нам нужен
row = all.**findAll**('tr')

Поскольку мы сохраним записи в CSV-файл, мы:

  • создадим пустой массив, который мы заполним данными каждой строки таблицы,
  • переберем каждую строку (i), переберем каждый столбец (j) строки (i) и
  • сохраним информацию в соответствующую переменную.

Код будет выглядеть следующим образом:

rest_info = [] # пустой массив, заполняемый информацией каждой строкиfor i in rows: #i - это строка
        infos_row = i.findAll('td')   # получаем информацию о одной строке
        for index, j in enumerate(infos_row): #j - это столбец строки i 
            info = None
            if index == 0: #в этом случае первый столбец содержит информацию о событии
                info = j.find('span') #информация находится внутри _span_
                event = info.text #извлекаем текст из _span_            if index == 4:
                info = j.find('span')
                areas = info.text            if index == 1:
                issued_time = j.text
            if index == 3:
                country = j.text            if index == 5:
                regions = j.text            if index == 2:
                continue
        #наконец, мы добавляем информацию в список (для каждой строки) 
        rest_info.append([event,issued_time,country,areas,regions)])

Теперь, когда мы сохранили информацию в списке, давайте запишем ее в CSV.

df = pd.DataFrame(rest_info, columns=
 ['Тип_события','Время_выпуска','Страна','Области','Регионы','Дата'])**df.to_csv**("parsed_weather.csv",mode='a', index=False,header=False)

CSV-файл должен выглядеть следующим образом:

Данные, спарсенные с веб-сайта

Поздравляю! Вы спарсили веб-сайт. Теперь давайте посмотрим, как автоматизировать этот процесс.

2. Автоматизация в реальном времени

Для планирования парсинга каждые X минут (в зависимости от ваших потребностей) нам понадобится использовать планировщик. Вот два из множества доступных вариантов:

  • GitHub Actions
  • Google Cloud Scheduler

Для этого урока мы воспользуемся GitHub Actions, так как он, на мой взгляд, самый простой и доступный.

pip install PyVirtualDisplay

Затем нам нужно внести следующие изменения в существующий код:

import pandas as pd
from bs4 import BeautifulSoup
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
from webdriver_manager.chrome import ChromeDriverManager
**from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
import chromedriver_autoinstaller
from pyvirtualdisplay import Display**

**display = Display(visible=0, size=(800, 800))
display.start()**

chromedriver_autoinstaller.install()

chrome_options = webdriver.ChromeOptions()
options = [
  "--window-size=1200,1200",
  "--ignore-certificate-errors"
]

for option in options:
    chrome_options.add_argument(option)

driver = webdriver.Chrome(options=chrome_options)

и в классе scrapeWeather нам больше не нужно вызывать установщик ChromeDriver

def scrapeWeather():
    **#**driver = webdriver.Chrome(ChromeDriverManager().install()) **#больше не нужно!**
    driver.get("https://severeweather.wmo.int/v2/list.html")
    ...
  1. Мы готовы развернуть код на GitHub и запланировать его выполнение. Для этого нам нужно:
  • создать репозиторий
  • загрузить python-скрипт
  • создать и загрузить файл requirements.txt (pip install pipreqs и выполнить pipreqs в папке терминала, где находится ваш скрипт)
  • создать workflow: в вашем репозитории GitHub -> Actions -> "New workflow". В рабочем процессе нам нужно добавить следующий код (скопируйте его и измените в соответствии с вашей настройкой):
name: scrap3on:
  **schedule:
    - cron: '*/30 * * * *' #расписание, в данном случае каждые 30 минут, в формате cron (URL CRON)**
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - name: checkout repo content
        uses: actions/checkout@v2
    - name: setup python
        uses: actions/setup-python@v2
        with:
          python-version: '3.7.7' #установите необходимую версию Python
    - name: install python packages
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt
    - name: execute py script
        **run: python scrape.py #ИМЯ ВАШЕГО ФАЙЛА ЗДЕСЬ!!**
    - name: commit files
        run: |
          git config --local user.email "[action@github.com](mailto:action@github.com)"
          git config --local user.name "GitHub Action"
          git add -A
          git commit -m "update data" -a
    - name: push changes
        uses: ad-m/github-push-action@v0.6.0
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          branch: main

Отлично. Теперь ваш скрипт будет выполняться каждые 30 минут и добавлять данные в CSV-файл. Теперь вы можете вызвать этот CSV-файл, размещенный на GitHub, из другого эндпоинта и получать обновления погоды в режиме реального времени!


Это был пример парсинга данных с веб-страницы с использованием BeautifulSoup, Selenium и GitHub Actions. Я использовал этот скрипт в проекте, в котором участвовал на HackZurich на прошлых выходных. Это крупнейший хакатон в Европе, и за 48 часов мы создали приложение для предупреждения о поставках, которое принесло нам победу в челлендже. Вы можете посмотреть наше приложение и репозиторий GitHub со всем кодом здесь.

Спасибо за ваше драгоценное время, потраченное на чтение статьи. Не забудьте подписаться на меня в Medium и связаться со мной в LinkedIn, если у вас есть вопросы. Увидимся в следующий раз!