Парсинг сайта на питон с библиотекой BeautifulSoup
Как обычно зависимости:
import requests from bs4 import BeautifulSoup
Установка пакета "КрасивыйСуп" для третьего питона очень проста.
pip install beautifulsoup4
Итак, начал я с написания функции которая будет парсить с сайта с фильмами нужные нам значения и возвращать их.
def all_in_one(link="http://kinopod.ru/movies/genre/crime/year/2010-2019/random.html"): r = requests.get(link).text soup = BeautifulSoup(r, 'html.parser') rdy = soup.find_all('div', {"class": "title"}) random_site = rdy[0]('a')[0]["href"]
В функцию передаётся параметр с ссылкой на сайт с кино, по жанру "Криминал". Далее мы делаем запрос на данный сайт и "сохраняем" его исходный код. Это происходит благодаря приписки .text в конце строки с запросом. Далее мы создаем объект soup в который передаём наш исходный код страницы полученный путём гет запроса.
Далее мы ищем все блоки div с классом title. мы получаем список в массиве. Список с ссылками на фильмы. Выглядит он так:
К счастью нам не надо далеко ходить, т.к сайт выдаёт рандомные фильмы в этом жанре, поэтому нам достаточно взять первый элемент массива. Что и происходит в строке:
random_site = rdy[0]('a')[0]["href"]
Тут мы берем первый элемент массива:
<div class="title"><a href="http://kinopod.ru/video.html?id=93263" title="Смотреть фильм Ошибка времени онлайн на Кинопод бесплатно">Ошибка времени</a></div>
Затем достаём из него элемент ссылки "а"
rdy[0]('a')
И получаем это:
[<a href="http://kinopod.ru/video.html?id=90479" title="Смотреть фильм Видения онлайн на Кинопод бесплатно">Видения</a>]
Вот только проблема...Элемент то у нас в массиве, он не объект "Супа", он объект массива. Поэтому нам следует преобразовать его в то что может распарсить суп:
rdy[0]('a')[0] >> <a href="http://kinopod.ru/video.html?id=54452" title="Смотреть фильм Zомби каникулы онлайн на Кинопод бесплатно">Zомби каникулы</a>
И теперь мы можем достать ссылку на фильм добавив ['href'] в конце:
rdy[0]('a')[0]["href"] >> http://kinopod.ru/video.html?id=25115
Итак, у нас есть ссылка на сам фильм, теперь же нам необходимо распарсить множество вещей. Такие как : Название, Описание фильма, Возрастное ограничение, Жанры, Продюсеры, Актёры, Страна.
Что же, будем идти по порядку. Начнем с названия.
Название у нас хранится вот тут:
Что бы его вытащить мы напишем следующий код:
find_title = soup2.find_all('meta', {"itemprop": "name"}) title = find_title[0]["content"]
Думаю тут всё понятно, в общем то ничего сложного. Если не понимаете откуда берутся те или иные вещи вы можете по шагам выполнить код.
Далее у нас идёт описание фильма. Хранится оно вот туть:
А вот и сам код что бы его вытащить:
find_discription = soup2.find_all('div', {"class": "video-desc"}) discription = find_discription[0]('p')[0].contents[0]
Такс, тут может быть немного непонятно. Давайте посмотрим что нам выдаст find_discription что бы понять как вытащить сам discription.
Итак, тут мы видим 2 элемента массива. Первый это описание фильма, второй это ересь. Поэтому мы берем первый элемент массива, затем используем .contents что бы вытащить весь текст из <p>, но он нам вернет текст в массиве, поэтому мы просто добавим в конец [0] что бы он вернул нам текст.
Думаю с этим понятно, дальше по списку идёт Возрастное ограничение. Не у каждого фильма на сайте обозначено возрастное ограничение, поэтому мы будем проверять, есть ли оно вообще, и если есть то получим его.
Вот тут у нас возрастное ограничение. Далее вы увидите код благодаря которому мы сможем вытащить его со страницы.
find_age = soup2.find_all('span', {"class": "age"}) if find_age != []: age = find_age[0].contents[0] else: pass
Тут всем вам знакомая конструкция по поиску определенного элемента с обозначением класса. Но, есть такой небольшой нюанс. Если возраст не указан то нам возвращается пустой массив. Поэтому мы должны сначала проверить, пустой ли массив мы получили, если да то просто пропускаем а если нет - парсим значение. Тут вроде всё не сложно и понятно. Давайте дальше.Жанры.
Таблицы, таблицы и еще раз таблицы...
Тут я уже пользовался перебором... Так как таблица это не единственная мы будем указывать конкретно эту. Как я уже говорил ранее - суп нам возвращает элементы страницы в массиве, поэтому после поиска всех таблиц - нужная нам будет элементом массива. Надеюсь понятно. А вот и код.
arr = [] for i in range(len(soup2.find_all('td')[3]('a'))): find_rating = soup2.find_all('td')[3]('a')[i].contents[0] arr.append(find_rating) genre = "" for i in range(len(arr)): genre = genre + str(arr[i]) + ", "
Для начала мы создадим пустой массив в который будем помещать все жанры, длинна массива будет нашим счетчиком в цикле for. Затем мы будем вытаскивать сам контент, жанры из элемента. Добавим их в массив. Затем с помощью другого цикла мы уже будем создавать строку с жанрами, разделяя жанры запятой. Надеюсь с этим понятно. Осталось чуть чуть.
ПРОДЮСЕРЫ, АКТЁРЫ, СТРАНЫ. Принцип тот же самый, циклы те же самые. Так что я просто оставлю ниже код.
# ПРОДЮСЕРЫ if soup2.find_all('a', {"itemprop": "producer"}) != []: producers = [] for i in range(len(soup2.find_all('a', {"itemprop": "producer"}))): find_producers = soup2.find_all('a', {"itemprop": "producer"})[i].contents[0] producers.append(find_producers) producer = "" for i in range(len(producers)): producer = producer + str(producers[i]) + ", " else: pass # АКЁТРЫ actors = [] for i in range(len(soup2.find_all('a', {"itemprop": "actor"}))): find_actor = soup2.find_all('a', {"itemprop": "actor"})[i].contents[0] actors.append(find_actor) actor = "" for i in range(len(actors)): actor = actor + str(actors[i]) + ", " # СТРАНЫ countrys = [] for i in range(len(soup2.find_all('td')[1]('a'))): find_country = soup2.find_all('td')[1]('a')[i].contents[0] countrys.append(find_country) country = "" for i in range(len(countrys)): country = country + str(countrys[i]) + ", "
Как видите принцип тот же. А теперь полный листинг программы, надеюсь статья вас не сильно утомила.
P.S. Чуть не забыл. Когда мы создаем из элементов массива строки то в конце у нас стоит лишняя запятая и пробел. Это можно легко убрать:
Вернёт нам ту же строку только без пробела и запятой в конце.
producer[:-2]
А вот и сам листинг:
def all_in_one(link="http://kinopod.ru/movies/genre/crime/year/2010-2019/random.html"): r = requests.get(link).text soup = BeautifulSoup(r, 'html.parser') rdy = soup.find_all('div', {"class": "title"}) random_site = rdy[0]('a')[0]["href"] req = requests.get(random_site) soup2 = BeautifulSoup(req.text, 'html.parser') # НАЗВАНИЕ find_title = soup2.find_all('meta', {"itemprop": "name"}) title = find_title[0]["content"] # ОПИСАНИЕ ФИЛЬМА find_discription = soup2.find_all('div', {"class": "video-desc"}) discription = find_discription[0]('p')[0].contents[0] # ВОЗРОСТНОЕ ОГРАНИЧЕНИЕ find_age = soup2.find_all('span', {"class": "age"}) if find_age != []: age = find_age[0].contents[0] # Возрастное ограничение else: pass # ЖАНРЫ arr = [] for i in range(len(soup2.find_all('td')[3]('a'))): find_rating = soup2.find_all('td')[3]('a')[i].contents[0] arr.append(find_rating) genre = "" for i in range(len(arr)): genre = genre + str(arr[i]) + ", " # ПРОДЮСЕРЫ if soup2.find_all('a', {"itemprop": "producer"}) != []: producers = [] for i in range(len(soup2.find_all('a', {"itemprop": "producer"}))): find_producers = soup2.find_all('a', {"itemprop": "producer"})[i].contents[0] producers.append(find_producers) producer = "" for i in range(len(producers)): producer = producer + str(producers[i]) + ", " else: pass # АКЁТРЫ actors = [] for i in range(len(soup2.find_all('a', {"itemprop": "actor"}))): find_actor = soup2.find_all('a', {"itemprop": "actor"})[i].contents[0] actors.append(find_actor) actor = "" for i in range(len(actors)): actor = actor + str(actors[i]) + ", " # СТРАНЫ countrys = [] for i in range(len(soup2.find_all('td')[1]('a'))): find_country = soup2.find_all('td')[1]('a')[i].contents[0] countrys.append(find_country) country = "" for i in range(len(countrys)): country = country + str(countrys[i]) + ", " all_text = "Название: " + title + "\nОписание фильма: " + discription + "\nВозрастное ограничение: " + age + "\nЖанры: " + genre[:-2] + "\nПродюсеры: " + producer[:-2] + "\nАктёры: " + actor[:-2] + "\nСтрана: " + country[:-2] return all_text
Мой код не идеален, вы всегда можете написать лучше или модернизировать мой код