CoderCastrov logo
CoderCastrov
Python

Использование Python с Selenium для парсинга веб-сайтов с использованием JavaScript

Использование Python с Selenium для парсинга веб-сайтов с использованием JavaScript
просмотров
4 мин чтение
#Python

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

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

Поиск информации на веб-сайте

Давайте сразу перейдем к сегодняшнему проекту. Мы собираемся узнать, какой список фигурок Сона Гоку из Dragon Ball с их ценами на веб-сайте, который я создал для эксперимента, описанного здесь.

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

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Optionsimport csv
import timedef setCSV(output_file, headers):
    writer = csv.DictWriter(output_file, fieldnames=headers)
    writer.writeheader()
    return writerdef writeRowsCSV(writer, data):
    print(data)
    for row in data:
        print("Write row")
        print(row)
        writer.writerow(row)

Мы импортировали несколько функций из Selenium, которые будут использоваться в нашем скрипте:

  • webdriver: конструктор webdriver, то есть инициализация Selenium с драйвером
  • Options: помогает установить параметры веб-драйвера.
  • Keys: набор клавиш клавиатуры.
  • By: набор методов для поиска элементов.
  • WebDriverWait: явное ожидание, позволяющее драйверу ожидать выполнения условия, например, с помощью функции "until()" можно указать, чтобы ожидание прекратилось, когда условие станет истинным.
  • expected_conditions: набор условий, которые можно использовать с вышеупомянутой функцией "until()".

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

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

chrome_options = Options()
chrome_options.add_argument("--headless")
driver = webdriver.Chrome(options=chrome_options)

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

После инициализации Selenium мы получаем веб-страницу, вводим ключевое слово в строку поиска и нажимаем клавишу "Enter". Вы можете заметить, что я использую функции time.sleep(), чтобы явно подождать некоторое время, чтобы сценарий выглядел более естественным и чтобы веб-страница успела обработать ввод, на случай, если есть какое-то событие "onChange".

driver.get("[https://www.figurines-maniac.com/](https://www.figurines-maniac.com/)")
time.sleep(2)
elem = WebDriverWait(driver, 30).until(
   EC.presence_of_element_located((By.XPATH,'//input[[@class](http://twitter.com/class)="header-search-input"]'))
)
elem.send_keys("Goku")
time.sleep(1)
elem.send_keys(Keys.RETURN)
time.sleep(4)

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

Названия, которые я выбрал для этих информаций, довольно простые. Я назвал их "product_name", "price" и "url".

# Поиск списка продуктов
products_ul = driver.find_elements(By.XPATH, '//ul[contains([@class](http://twitter.com/class), "products")]')
print(products_ul)
if len(products_ul) > 0:
    product_list = []
    # Получение данных для каждого продукта в списке
    for product in products_ul[0].find_elements(By.XPATH, './/li'):
        product_title = product.find_elements(By.XPATH, './/h2')
        if len(product_title) > 0:
            product_name = product.find_element(By.XPATH, './/h2').text if len(product.find_elements(By.XPATH, './/h2')) > 0 else "Product not found"
            price = product.find_element(By.XPATH, './/bdi').text if len(product.find_elements(By.XPATH, './/bdi')) > 0 else "Price not found"
            url = product.find_elements(By.XPATH, './/a')[0].get_attribute("href") if len(product.find_elements(By.XPATH, './/a')) > 0 else "URL not found"
            product_list.append({
                "product_name": product_name, # a job-card-list__title
                "price": price, # a job-card-container__company-name
                "url": url
            })
    print(product_list)
    # Вывод полученных данных в CSV-файл
    with open("products_output.csv","w", encoding="utf-8") as output_file:
        headers = ["product_name", "price", "url"]
        writer = setCSV(output_file, headers)
        writeRowsCSV(writer, product_list)

Не забудьте очистить и закрыть браузер по завершении.

if driver is not None:
    driver.close()

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


Если вам понравилась статья или она оказалась полезной, будьте добры поддержать меня, подписавшись на меня здесь (Jonathan Mondaut). Скоро появятся еще статьи!


from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Optionsimport csv
import timedef setCSV(output_file, headers):
    writer = csv.DictWriter(output_file, fieldnames=headers)
    writer.writeheader()
    return writerdef writeRowsCSV(writer, data):
    print(data)
    for row in data:
        print("Write row")
        print(row)
        writer.writerow(row)try:
    chrome_options = Options()
    chrome_options.add_argument("--headless")
    driver = webdriver.Chrome(options=chrome_options)
    driver.get("[https://www.figurines-maniac.com/](https://www.figurines-maniac.com/)")
    time.sleep(2)
    elem = WebDriverWait(driver, 30).until(
                EC.presence_of_element_located((By.XPATH, '//input[[@class](http://twitter.com/class)="header-search-input"]'))
            )
    elem.send_keys("Goku")
    time.sleep(1)
    elem.send_keys(Keys.RETURN)
    time.sleep(4)products_ul = driver.find_elements(By.XPATH, '//ul[contains([@class](http://twitter.com/class), "products")]')
    print(products_ul)
    if len(products_ul) > 0:
        product_list = []
        for product in products_ul[0].find_elements(By.XPATH, './/li'):
            product_title = product.find_elements(By.XPATH, './/h2')
            if len(product_title) > 0:
                product_name = product.find_element(By.XPATH, './/h2').text if len(product.find_elements(By.XPATH, './/h2')) > 0 else "Product not found"
                price = product.find_element(By.XPATH, './/bdi').text if len(product.find_elements(By.XPATH, './/bdi')) > 0 else "Price not found"
                url = product.find_elements(By.XPATH, './/a')[0].get_attribute("href") if len(product.find_elements(By.XPATH, './/a')) > 0 else "URL not found"
                product_list.append({
                    "product_name": product_name, # a job-card-list__title
                    "price": price, # a job-card-container__company-name
                    "url": url
                })
        print(product_list)
        with open("products_output.csv","w", encoding="utf-8") as output_file:
            headers = ["product_name", "price", "url"]
            writer = setCSV(output_file, headers)
            writeRowsCSV(writer, product_list)
    if driver is not None:
        driver.close()
except Exception as error:
    print(error)
    driver.close()