Автоматизация парсинга плейлистов YouTube с помощью Python и Selenium

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

Язык программирования: Python🐍
Среда парсинга/автоматизации: Selenium

Давайте начнем и пройдемся по каждому шагу. 😍

Импорт соответствующих библиотек

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

  1. из selenium import webdriver
    (библиотека selenium в Python предоставляет способ автоматизации взаимодействия с веб-браузером, а модуль webdriver специально позволяет вам программно управлять веб-браузером.)
  2. from selenium.webdriver.common.by import By
    (
    Класс By в модуле selenium.webdriver.common.by обеспечивает способ указать различные методы поиска элементов HTML на веб-странице, например, по идентификатору, имени класса или селектору CSS.)
  3. время импорта
    (
    предоставляет функции для работы с операциями, связанными со временем, такими как получение текущего времени, ожидание в течение определенного периода времени и форматирование значений времени.)
  4. из модуля записи импорта csv
    (
    это модуль Python, используемый для работы с файлами CSV (значения, разделенные запятыми), в частности для импорта записи strong>, который позволяет записывать данные в CSV-файлы с использованием разделителя-запятой.)
  5. import pandas as pd
    (
    это библиотека Python, используемая для обработки и анализа данных, предоставляющая структуры данных и функции для работы с табличными данными.)
  6. из selenium.webdriver.common.keys import Keys
    (
    это модуль из библиотеки Python Selenium, используемый для имитации клавиш клавиатуры, в частности импортирующий класс Keys, который предоставляет набор предопределенных клавиш, которые можно использовать для различных действий с клавиатурой.)

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

Выполнение

Для реализации я использовал язык программирования Python. Я использовал объектно-ориентированный подход, который, во-первых, является профессиональным подходом, а во-вторых, основой чистого кода.
Другой важный принцип, который я использовал, и этот принцип очень важен для всех разработчиков программного обеспечения и программистов, — это принцип SOLID. Но я не реализовал все SOLID, я сосредоточился на двух: S (принцип единой ответственности) и O (открыт для расширения, но закрыт для модификации).

Теперь я пройдусь по каждому классу, объясню работу и постараюсь быть кратким. 😉

  1. Инициализатор класса:
    (Класс инициализатора инициализирует пустой список, т. е. список ключевых слов. Этот список ключевых слов будет использоваться во всем коде, поэтому вместо того, чтобы определять его везде, я инициализировал его в начале.)
  2. Класс Browser:
    (класс браузера отвечает за создание сеанса браузера, т. е. за открытие браузера Chrome.)
  3. Класс Scraper:
    (Класс Scraper имеет 2 метода: поиск и сбор плейлиста. Метод поиска ищет ключевое слово на YouTube, а метод скрапинга плейлиста извлекает необходимые детали плейлиста.)
  4. Класс CSV:
    (Класс CSV отвечает за все методы, связанные с CSV-файлом. Он имеет 3 метода: read csv, который считывает входной csv, make csv, который создает выходной csv с заголовком столбца, и третий метод заполнить csv, который заполняет выходной csv данными плейлиста.)
  5. Класс Scraper Implementor:
    (класс реализации Scraper отвечает за реализацию всех вышеперечисленных классов с использованием наследования и вызовом всех методов из вышеуказанных классов.)

Итак, как на самом деле работает код? 🤷

Работающий

Остановимся на сути,

  1. Код считывает входной CSV-файл (вы можете назвать его как хотите) и добавляет ключевые слова из этого CSV-файла в список ключевых слов.
  2. Метод make csv создает файл CSV (вы можете назвать его как хотите) с заголовком столбца. Этот метод make csv вызывается перед циклом, потому что я не хочу создавать новый файл csv каждый раз, когда выполняется цикл for.
  3. Теперь выполните итерацию по каждому ключевому слову в списке ключевых слов.
  4. Объект класса браузера в классе реализации открывает браузер Chrome (вы можете изменить код класса браузера, чтобы открыть любой другой браузер по вашему выбору).
  5. Используя функцию get(), откройте целевой URL-адрес (в данном случае моим целевым URL-адресом была домашняя страница YouTube).
  6. Создайте объект метода поиска, определенный в классе Scraper. Это приведет к поиску ключевого слова на YouTube и отображению всех плейлистов, связанных с этим ключевым словом.
  7. Создайте еще один объект, но на этот раз для метода очистки плейлиста, определенного в классе Scraper. Этот метод сначала проверяет наличие текста на странице, т. е. «Больше результатов нет», пока этот текст не будет найден на странице, он продолжает прокручивать страницу с помощью клавиши «страница вниз». Selenium обрабатывает нажатия клавиш, вам не нужно нажимать их физически. При прокрутке он собирает информацию о плейлисте с помощью метода find_elements() (это встроенный метод селена, который используется, если какой-либо элемент встречается на странице более одного раза, и если вам нужны все эти элементы. Он возвращает список всех этих элементов). Как только текст найден, я перебираю каждый список деталей плейлиста и получаю его текст (изначально он хранит данные в виде объектов, нам нужно использовать текстовую функцию для преобразования этих объектов в текст. Вы также должны помнить, что вы можете используйте текстовую функцию только для одного объекта, поэтому, скажем, в моем случае у меня был список объектов, поэтому я перебирал список и преобразовывал каждый объект в текст один за другим через цикл).
  8. В конце метод populate csv помещает всю полученную информацию в выходной CSV.

КОД

from selenium import webdriver
from selenium.webdriver.common.by import By
import time
from csv import writer
import pandas as pd
from selenium.webdriver.common.keys import Keys


class Initializer:
    def __init__(self):
        self.keywords_lst = []

# A browser class which initializes browser
class Browser:
    def session(self):
        self.driver = webdriver.Chrome()


# a scraper class which performs search
# and scrapes the playlist details
class Scraper(Browser, Initializer):
    def search(self, keyword):
        search_field = self.driver.find_element(By.XPATH, "//input[@id='search']")
        search_field.click()
        time.sleep(2)
        search_field.send_keys(keyword)
        self.driver.find_element(By.XPATH, '//button[@class="style-scope ytd-searchbox"]').click()
        time.sleep(10)
        filters = self.driver.find_element(By.XPATH, '//ytd-toggle-button-renderer[@class="style-scope ytd-search-sub-menu-renderer"]')
        filters.click()
        time.sleep(2)
        set_filter = self.driver.find_element(By.XPATH, '//div[@title="Search for Playlist"]')
        self.driver.execute_script("arguments[0].click()",set_filter)
        time.sleep(5)

    def playlist_scraper(self):
        playlist_title = []
        playlist_link = []
        playlist_videos = []
        flag = False

        while not flag:
            body = self.driver.find_element(By.TAG_NAME, "body")
            body.send_keys(Keys.PAGE_DOWN)
            time.sleep(1)  # wait for the page to load new content
            playlist_title = self.driver.find_elements(By.XPATH, '//span[@id="video-title"]')
            playlist_link = self.driver.find_elements(By.XPATH, '//a[@class="yt-simple-endpoint style-scope ytd-playlist-thumbnail"]')
            playlist_videos = self.driver.find_elements(By.XPATH, '//yt-formatted-string[@class="style-scope ytd-thumbnail-overlay-side-panel-renderer"]')
            # check if there are no more results
            no_more_results = self.driver.find_elements(By.XPATH, "//*[contains(text(), 'No more results')]")
            if len(no_more_results) > 0:
                flag = True

        title_lst = []
        for title in playlist_title:
            title_lst.append(title.text)

        playlist_link_lst = []
        for link in playlist_link:
            playlist_link_lst.append(link.get_attribute('href'))

        playlist_videos_lst = []
        for views in playlist_videos:
            playlist_videos_lst.append(views.text)

        self.new_title = []
        self.new_playlist_link = []
        self.new_playlist_videos = []

        for i in title_lst:
            if i != "":
                self.new_title.append(i)

        for j in playlist_link_lst:
            if j != "":
                self.new_playlist_link.append(j)

        for k in playlist_videos_lst:
            if k != "":
                self.new_playlist_videos.append(k)

        print(title_lst)
        print(playlist_link_lst)
        print(playlist_videos_lst)


# CSV class which performs all operations
# related to CSV. (read the keywords csv,
# make the output csv and populate each playlist
# detail in the CSV.
class CSV(Scraper, Initializer):
    def read_csv(self, filename):
        df = pd.read_csv(filename)
        for i in df['Keywords']:
            self.keywords_lst.append(i)

    def make_csv(self, filename):
        with open(filename, "a", encoding="utf8", newline="") as f:
            write_csv = writer(f)
            columns = ['Playlist Title', 'No.of Videos', 'Playlist Link']
            write_csv.writerow(columns)

    def populate_csv(self,filename):
        with open(filename, "a", encoding="utf8", newline="") as f:
            write_csv = writer(f)
            for i,j,k in zip(self.new_title, self.new_playlist_videos, self.new_playlist_link):
                data = [i,j,k]
                write_csv.writerow(data)


# An implementor class which calls all
# the fucntions from above class and implements
# Scraper
class Scraper_Implementor(CSV):
    def get_playlist(self,read_filename,write_filename, url):
        super().read_csv(read_filename)
        print(self.keywords_lst)
        super().make_csv(write_filename)
        for i in self.keywords_lst:
            super().session()
            time.sleep(2)
            self.driver.get(url)
            time.sleep(5)
            super().search(keyword=i)
            super().playlist_scraper()
            super().populate_csv(write_filename)



# Driver Code
obj = Scraper_Implementor()
obj.get_playlist('keywords.csv','test_v2.csv', 'https://www.youtube.com/')

Итак, это выше, вот фактическая закодированная реализация🙌
Давайте обсудим, с какими типами ошибок я столкнулся и как я их преодолел. 👀

  1. Ошибка JavaScript:
    Сообщение: ошибка JavaScript: невозможно прочитать свойства неопределенного (чтение «DefaultView»)

Итак, эта ошибка возникала, когда селен пытался щелкнуть параметр плейлиста. Это происходило один раз из 5. Но вскоре я преодолел это, позволив JavaScript обрабатывать щелчок здесь. Во-первых, я позволял селену делать щелчок.

(Сценарий выше сейчас безошибочен 😊)

Заключительные примечания

Есть и другие способы парсинга сайтов, но это был один из них. Если вы хотите добавить к нему какую-либо функциональность, перейдите по ссылке репозитория. 👉 saad-24/Youtube-Scraper и не забудьте отметить этот репозиторий звездочкой 😉.