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

Как кодировать соскоб бот с селеном и Python

Автор оригинала: Otávio Simões Silveira.

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

Хотя это не его главная цель, Selenium также используется в Python для веб-соскабливания, потому что он может получить доступ к JavaScript-представленному контенту (который обычные инструменты соскабливания, как BeautificSoup, не могут сделать).

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

В качестве примера мы будем соскрести Investing.com для извлечения исторических данных курсов долларовых курсов против одной или нескольких валют.

Если вы ищете в Интернете, вы можете найти пакеты API и Python, которые делают его намного проще сбора финансовых данных (вместо того, чтобы соскоб его вручную). Тем не менее, идея здесь состоит в том, чтобы исследовать, как Selenium может помочь вам с общими добычей данных.

Сайт, который мы собираемся соскребать

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

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

Чтобы увидеть данные для других валют по отношению к доллару, просто замените « EUR » с другим кодом валют в URL.

Кроме того, это предполагает, что вы хотите только обменный курс валюты по отношению к доллару. Если это не так, просто замените «USD» в URL.

Код скребка

Мы начнем с импорта, и нам больше не нужно. Давайте импортируем полезные предметы из селена: Спать Функция, чтобы вставить некоторые паузы в код и панды для манипулирования датой при необходимости.

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from time import sleep
import pandas as pd

Далее мы напишем функцию, чтобы соскрести данные. Функция получит:

  • Список кодов валют
  • Дата начала
  • Дата окончания
  • Булевая информирование, если мы хотим экспортировать данные как .csv файл. Я буду использовать false как по умолчанию.

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

def get_currencies(currencies, start, end, export_csv=False):
    frames = []

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

Таким образом, для каждой валюты в списке валют мы создадим URL, создать объект драйвера и использовать его, чтобы получить страницу. Тогда мы максимизируем окно, но это только видно, если вы сохраните Опция. Бокан ... как ложь. В противном случае Selenium сделает всю работу, не показывая вам ничего.

for currency in currencies:
    my_url = f'https://br.investing.com/currencies/usd-{currency.lower()}-historical-data'
    option = Options()
    option.headless = False
    driver = webdriver.Chrome(options=option)
    driver.get(my_url)
    driver.maximize_window()

Мы уже смотрим на исторические данные на данный момент, и мы могли бы просто получить таблицу с данными. Однако по умолчанию мы видим только данные о последних 20 дней. Мы хотим получить эти данные за любой период времени.

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

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

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

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

Время ожидания будет двадцать секунд, но решать вам, чтобы установить его, как вы находите подходящие. Во-первых, давайте выберем кнопку Дата на XPath, а затем нажмите на нее.

date_button = WebDriverWait(driver, 20).until(
              EC.element_to_be_clickable((By.XPATH,
              "/html/body/div[5]/section/div[8]/div[3]/div/div[2]/span")))

date_button.click()

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

start_bar = WebDriverWait(driver, 20).until(
            EC.element_to_be_clickable((By.XPATH, 
	        "/html/body/div[7]/div[1]/input[1]")))

start_bar.clear()
start_bar.send_keys(start) 

И теперь мы повторяем процесс поля окончания даты.

end_bar = WebDriverWait(driver, 20).until(
          EC.element_to_be_clickable((By.XPATH, 
          "/html/body/div[7]/div[1]/input[2]")))

end_bar.clear()
end_bar.send_keys(end)

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

apply_button = WebDriverWait(driver, 20).until(
	           EC.element_to_be_clickable((By.XPATH,  
               "/html/body/div[7]/div[5]/a")))

apply_button.click()
sleep(5)

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

Теперь мы используем Pandas.read_html Функция, чтобы выбрать все таблицы на странице. Эта функция получит исходный код страницы. Наконец, мы можем бросить водитель.

dataframes = pd.read_html(driver.page_source)
driver.quit()
print(f'{currency} scraped.')

Как обрабатывать исключения в селении

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

Чтобы предотвратить это, у нас будет весь код внутри попробуйте пункт, который будет внутри петли Infinity. Как только Selenium удается собирать данные, как я описал выше, цикл будет нарушен. Но каждый раз он находит проблему, ожидать пункт будет активирован.

В этом сценарии код будет:

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

Этот процесс будет повторяться до тех пор, пока данные для каждой валюты не будут правильно. И это код для всего этого:

 for currency in currencies:
        while True:
            try:
                # Opening the connection and grabbing the page
                my_url = f'https://br.investing.com/currencies/usd-{currency.lower()}-historical-data'
                option = Options()
                option.headless = False
                driver = webdriver.Chrome(options=option)
                driver.get(my_url)
                driver.maximize_window()
                   
                # Clicking on the date button
                date_button = WebDriverWait(driver, 20).until(
                            EC.element_to_be_clickable((By.XPATH,
                            "/html/body/div[5]/section/div[8]/div[3]/div/div[2]/span")))
                
                date_button.click()
                
                # Sending the start date
                start_bar = WebDriverWait(driver, 20).until(
                            EC.element_to_be_clickable((By.XPATH,
                            "/html/body/div[7]/div[1]/input[1]")))
                            
                start_bar.clear()
                start_bar.send_keys(start)

                # Sending the end date
                end_bar = WebDriverWait(driver, 20).until(
                            EC.element_to_be_clickable((By.XPATH,
                            "/html/body/div[7]/div[1]/input[2]")))
                            
                end_bar.clear()
                end_bar.send_keys(end)
               
                # Clicking on the apply button
                apply_button = WebDriverWait(driver,20).until(
                		EC.element_to_be_clickable((By.XPATH,
                		"/html/body/div[7]/div[5]/a")))
                
                apply_button.click()
                sleep(5)
                
                # Getting the tables on the page and quiting
                dataframes = pd.read_html(driver.page_source)
                driver.quit()
                print(f'{currency} scraped.')
                break
            
            except:
                driver.quit()
                print(f'Failed to scrape {currency}. Trying again in 30 seconds.')
                sleep(30)
                continue

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

Для каждого DataFrame в этом списке DataFrames мы проверим, соответствует ли название его столбцов, соответствует тому, что мы ожидаем. Если они сделают, то это наш кадр, и мы разбиваем петлю. И теперь мы наконец готовы добавить этот файл DataFrame в список, который был инициализирован в начале.

for dataframe in dataframes:
    if dataframe.columns.tolist() == ['Date', 'Price', 'Open', 'High', 'Low', 'Change%']:
        df = dataframe
        break

frames.append(df)

И да, если export_csv Параметр был установлен на true, нам нужно будет экспортировать .csv файл. Но это далеко не проблема, как Dataframe.to_csv Метод может легко получить это.

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

if export_csv:
        df.to_csv('currency.csv', index=False)
        print(f'{currency}.csv exported.')

# Outside of the loop
return frames

Вот и все! Вот полный код для этих двух последних шагов в сочетании:

		# Selecting the correct table            
        for dataframe in dataframes:
            if dataframe.columns.tolist() == ['Date', 'Price', 'Open', 'High', 'Low', 'Change%']:
                df = dataframe
                break
        frames.append(df)

        # Exporting the .csv file
        if export_csv:
            df.to_csv('currency.csv', index=False)
            print(f'{currency}.csv exported.')
                  
  return frames

Следующие шаги и упаковка

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

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

Еще одно предложение – написать Обновить Функция, использующая те же функции селена, которые получают существующее dataframe и обновлять исторические данные на настоящую дату.

Кроме того, то же самое, такую же логику, используемую для царапания валют, можно использовать для скрепления запасов, индексов, товаров, фьючерсов и многого другого. Есть так много страниц, которые вы можете соскребать.

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

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

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