3 горизонтальные линии, бургер
3 горизонтальные линии, бургер
3 горизонтальные линии, бургер
3 горизонтальные линии, бургер

3 горизонтальные линии, бургер
Удалить все
ЗАГРУЗКА ...

Содержание



    Как написать парсер списка фильмов с кинопоиска на python

    Часы
    24.11.2024
    /
    Часы
    02.10.2025
    /
    Часы
    6 минут
    Глазик
    923
    Сердечки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    Соединённые точки
    0

    Как он работает

    Данный парсер собирает информацию со страниц сайта, которые содержат в своём адресе list. Проще говоря, это парсер страниц фильтраций и страниц пагинаций. Во каламбур :). Не стану скрывать, работает он довольно медленно, ибоб чтобы получить доступ к страницам данного сайта требуется использовать, так называемый динамический парсинг. То есть, парсинг страниц с предварительной отрисовкой и обработкой браузером.
    Это первый барьер, который необходимо преодолеть, перед тем как получить доступ к необходимым страницам. Второй барьер на нашем пути, это блокировка определённых IP адресов с которых происходит парсинг. По этому используются, соответственно подобранные прокси.
    Те прокси, которые ты получишь по умолчанию с исходниками данного парсера скорее всего уже не работают. По этому, не забудь заглянуть в главы о том, как такие прокси найти и как их подобрать для целевого сайта, то есть kinopoisk.ru
    Рабочий парсер сайта kinopoisk можно скачать от сюда. Тебе останется только активировать виртуальное окружение и установить необходимые пакеты.

    Как его сделать, установка пакетов

    Данный прасер мы напишем на python с использованием сторонних библиотек и утилит. Для начала создадим виртуальное оружение и установим его. Так же необходимо скачать мой прокси ротатор.
    python -m venv .venv
    Если windows то:
    .\.venv\Scripts\activate
    Если *unix системы то:
    source ./.venv/bin/activate
    Теперь очередь за необходимыми пакетами
    pip install selenium requests lxml beautifulsoup4 pandas openpyxl
    Или можно использовать специально подготовленный файл с зависимостями для данного проекта.
    pip install -r req.txt

    Как его сделать, написание скрипта

    Создай файл main.py в директории проекта. Наш скрипт не будет очень большим, чуть больше 100 строчек кода. Вот полностью готовый код парсера:
    import pandas from bs4 import BeautifulSoup # For creating webdriver from selenium import webdriver # For navigation purpose from selenium.webdriver.common.by import By # For easy to send parameters to driver when set from selenium.webdriver.firefox.options import Options # For events handling from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import TimeoutException from proxy_rotator import Proxy, Rotator, load_proxies URL = "https://www.kinopoisk.ru/lists/movies/genre--action/country--2/?b=series&ss_subscription=ANY" TEST_FILE = "result" RESULT_FILE = 'result' def get_page_number(text): soup = BeautifulSoup(text, features='lxml') number = int(soup.find_all('a', class_="styles_page__zbGy7")[-1].text) return number + 1 def save_to_exel(data): # So, because of missing values length of arrays in dict are different. Pandas work just fine if write data in rows # and then transpose it. # See https://stackoverflow.com/questions/40442014/pandas-valueerror-arrays-must-be-all-same-length frame = pandas.DataFrame.from_dict(data, orient='index') frame = frame.transpose() frame.to_excel(f"{RESULT_FILE}.xlsx") def scrape_kinopoisk_list(text, data): soup = BeautifulSoup(text, features='lxml') soup_films = soup.find_all('a', class_="base-movie-main-info_link__YwtP1") for soup_film in soup_films: soup_children = soup_film.findChildren('div', recursive=False) # if target element has more than default 4 children if len(soup_children) > len(data): for i in range(0, len(soup_children) - len(data)): data.update({f"{i}": []}) for indx, soup_child in enumerate(soup_children): for data_indx, key in enumerate(data): if indx == data_indx: data[key].append(soup_child.text) def run(): proxies: list[Proxy] = [] # Load proxies to memory proxies_json = load_proxies("proxies.json") for proxy_item in proxies_json: proxies.append(Proxy( proxy_item['path'], proxy_item['type'], proxy_item['protocol'], proxy_item['status'], proxy_item['weight']) ) # Making a rotator for a proxies rotator = Rotator(proxies) isFinished = False index = 1 max = 3 data = { "titles": [], "dates": [], 'coutry, producer': [], 'actors': [], } while not isFinished: try: proxy = rotator.get() print(f"Using proxy: {proxy}") # Create a webdriver firefox_opt = Options() firefox_opt.add_argument('--headless') firefox_opt.add_argument("--no-sandbox") firefox_opt.add_argument("--disable-dev-shm-usage") firefox_opt.add_argument(f"--proxy-server={proxy}") driver = webdriver.Firefox(options=firefox_opt) # Retrieve all reqeusts element on pages, while waiting they are loaded for i in range(index, max): if i == 1: print(f"\tPage: {i} [{URL}]") driver.get(URL) else: print(f"\tPage: {i} [{URL}&page={i}]") driver.get(f'{URL}&page={i}') items_container = WebDriverWait(driver, 1).until( EC.presence_of_all_elements_located((By.CLASS_NAME, 'base-movie-main-info_link__YwtP1')) ) scrape_kinopoisk_list(driver.page_source, data) save_to_exel(data) print(f"\tSuccess.") if i == 1: max = get_page_number(driver.page_source) print(f"\tGet number of available pages. [{max - 1}]") index = i + 1 if index >= max : isFinished = True except Exception as ex: print(f"\tProxy failed") print('Save the result') save_to_exel(data) if __name__ == "__main__": run()
    Дальше, чтобы было проще понять код, я разбил его на структурные элементы и функции. Начнём с главной функции run. Эта функция запускает парсинг и проводит ротацию прокси и решает, когда парсинг стоит закончить.
    proxies: list[Proxy] = [] # Load proxies to memory proxies_json = load_proxies("proxies.json") for proxy_item in proxies_json: proxies.append(Proxy( proxy_item['path'], proxy_item['type'], proxy_item['protocol'], proxy_item['status'], proxy_item['weight']) ) # Making a rotator for a proxies rotator = Rotator(proxies)
    Она же, создаёт виртуальный браузер и делает запросы необходимых URL.
    # Create a webdriver firefox_opt = Options() firefox_opt.add_argument('--headless') firefox_opt.add_argument("--no-sandbox") firefox_opt.add_argument("--disable-dev-shm-usage") firefox_opt.add_argument(f"--proxy-server={proxy}") driver = webdriver.Firefox(options=firefox_opt) # Retrieve all reqeusts element on pages, while waiting they are loaded for i in range(index, max): if i == 1: print(f"\tPage: {i} [{URL}]") driver.get(URL) else: print(f"\tPage: {i} [{URL}&page={i}]") driver.get(f'{URL}&page={i}')
    Дальше, Селениуму нужно зацепиться за что-то при загрузке. То есть начать действовать незамедлительно, как только появятся соответствующие элементы на странице. В случае с kinopoisk это элементы с классом base-movie-main-info_link__YwtP1. Вот цикл обхода по всем доступным страницам в том или ином списке.
    # Retrieve all reqeusts element on pages, while waiting they are loaded for i in range(index, max): if i == 1: print(f"\tPage: {i} [{URL}]") driver.get(URL) else: print(f"\tPage: {i} [{URL}&page={i}]") driver.get(f'{URL}&page={i}') items_container = WebDriverWait(driver, 1).until( EC.presence_of_all_elements_located((By.CLASS_NAME, 'base-movie-main-info_link__YwtP1')) ) scrape_kinopoisk_list(driver.page_source, data) save_to_exel(data) print(f"\tSuccess.") if i == 1: max = get_page_number(driver.page_source) print(f"\tGet number of available pages. [{max - 1}]") index = i + 1
    Стоит обратить внимание на то, что я сохраняю результат в таблицу при парсинге каждой страницы и после обхода всех страниц. Таким образом, даже если вдруг парсер "падёт", мы всё ещё сможем получить необходимые данные.
    Функция get_page_number, проще простого. Находим необходимый элемент и конвертируем строку в число:
    def get_page_number(text): soup = BeautifulSoup(text, features='lxml') number = int(soup.find_all('a', class_="styles_page__zbGy7")[-1].text) return number + 1
    Функция save_to_exel, ещё проще. Так как мы установили пакет pandas, всё что делает эта функция это создаёт особый фрейм данных и конвертирует его в таблицу:
    def save_to_exel(data): frame = pandas.DataFrame.from_dict(data, orient='index') frame = frame.transpose() frame.to_excel(f"{RESULT_FILE}.xlsx")
    Важно отметить, чтобы работать с эксель таблицами необходимо установить пакет openpyxl. Ну и что? Спросишь ты, а то что по идее она должна быть зависимостью при установке pandas, но таковой не является. Поэтому требуется мануальная установка.
    Функция scrape_kinopoisk_list ищет необходимые элементы на странице и заполняет отправленный словарь.
    def scrape_kinopoisk_list(text, data): soup = BeautifulSoup(text, features='lxml') soup_films = soup.find_all('a', class_="base-movie-main-info_link__YwtP1") for soup_film in soup_films: soup_children = soup_film.findChildren('div', recursive=False) # if target element has more than default 4 children if len(soup_children) > len(data): for i in range(0, len(soup_children) - len(data)): data.update({f"{i}": []}) for indx, soup_child in enumerate(soup_children): for data_indx, key in enumerate(data): if indx == data_indx: data[key].append(soup_child.text)
    Это собственно всё. Осталось только запустить функцию run. То, как это делать решать тебе. Просто запустить её внизу скрипта или сделать как я, то есть:
    if __name__ == "__main__": run()

    Сбор бесплатных прокси

    Так как kinopoisk это сайт работающий на территории России и СНГ(по крайней мере аудитория оттуда) то и прокси должны быть оттуда, для большей правдоподобности наших парсеров на обычных пользователей.
    Итак, как и откуда можно взять бесплатные прокси? Представляю тебе моего скраппера бесплатных прокси, с возможностью выбора и фильтрации прокси по странам, используемым протоколам и типу самих прокси.
    Чтобы собрать только русские прокси с используемыми протоколоми http, https, socks4, socks5 введи следующую команду:
    python .\main.py -p http, https, socks4, socks5 -c RU, BY, KZ
    Если хочешь узнать какие коды, каким странам соответствуют введи:
    python .\main.py -HC
    В результате ты получишь JSON файлы со списками прокси. Все такие файлы находятся в директории data. Всё происходит в параллельном режиме и ты можешь в любой момент остановить скрипт если посчитаешь, что тебе хватит.

    Проверка бесплатных прокси

    Итак, мы собрали сотни прокси и могу тебе гарантировать большинство из них это откровенный мусор. Нам нужно будет его отфильтровать, при чём, отфильтровать используя в качестве фильтра целевой сайт, то есть kinopoisk.
    Видишь ли, большинство сайтов, которые предоставляют прокси, проверяют живы ли они просто пингуя их. Но это не значит что эти прокси будут работать с тем или иным сайтом.
    Для проверки работоспособности прокси на том или ином сайте, я создал специальный CLI инструмент. Который ты можешь скачать по ссылке в предыдущем предложении (⊙_(⊙_⊙)_⊙). Вот как проверить список таких прокси, команда:
    python .\main.py -i 0_64.json -o .\res.json -U https://kinopoisk.ru
    Где -i это те прокси которые ты получил используя мой скрапер прокси
    Где -o это имя файла-результата где каждому прокси будет присвоен вес.
    Где -U это список сайтов проверки
    Больше опций и вариантов можно посмотреть используя -h флаг. Но в данном случае нас больше заинтересует log.txt файл. Ведь там хранятся результаты проверок каждого прокси и то сколько раз он успешно подключался к целевому сайту. Выбери самые успешные прокси и объедини их в один JSON файл, который потом будешь использовать для парсинга сайтов.

    Не забудь поделиться, лайкнуть и оставить комментарий)

    Комментарии

    (0)

    captcha
    Отправить
    ЗАГРУЗКА ...
    Сейчас тут пусто. Буть первым (o゚v゚)ノ

    Другое

    Похожие статьи


    Как написать простой парсер на python + уже готовый парсер

    Часы
    10.12.2024
    /
    Часы
    02.10.2025
    Глазик
    4665
    Сердечки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    Как написать простой парсер на python, на примере собора изображений с сайта. Данный парсер представляет из себя пример того, как парсить статические и динамические сайты. С исходным кодом и архивом …

    Пишем парсер поисковой выдачи google

    Часы
    15.02.2025
    /
    Часы
    02.10.2025
    Глазик
    1579
    Сердечки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    В этой статье будет описан процесс написания парсера поисковой выдачи google используя их официальный API. Покажу как получить API-ключ и ID поисковой машины. А так же предоставлю примеры и открытый …

    Использованные термины


    Релевантные вопросы