Как нажать кнопку на сайте, парсинг?
У меня есть парсер (не ругайте за это), он делает работу нормально, но возникла проблема которую решить не получается. Я не могу нажать на кнопку сайта. Я использую selenium чтобы нажать на кнопку, но для моей задачи это не удобно. Посоветуйте чем еще можно нажимать кнопки сайтов и желательно чтобы браузер не открывался. Или же помогите с ошибкой, она будет ниже кода.
import requests from bs4 import BeautifulSoup as BS import re import webbrowser from selenium import webdriver def BUY_SK(url): r = requests.get(url) html = BS(r.content, 'html.parser') #hidden_tags = str(html.find("input", ))[50:][:-3] #webbrowser.open(url, new=2) driver = webdriver.Firefox() driver.get(url) element = driver.find_element_by_css_selector('.snap._color.buy-user-good') element.click() # Ошибка из-за этого элемента def SKINKEEN(): regular = re.compile(r']*?\s+)?href=([""])(.*?)\1') r = requests.get('https://skinkeen.ru/') html = BS(r.content, 'html.parser') for el in html.select('.item_view'): title = el.select('.item_view__info > span') title = title[0].text[8:][:-4] if int(title) >= 45: gun__ = all_links = el.find_all('a', href=True) gun = regular.split(str(gun__[0])) gun__info_ = html.select('.item_view > a') print('\n[INFO] Найдено подходящие оружие! Скидка', str(title) + '%\n', gun__info_[0].text) print('https://skinkeen.ru/' + str(gun[2]), '\n') BUY_SK('https://skinkeen.ru/' + str(gun[2])) else: print('[INFO] Оружие не подходит: Скидка', str(title) + '%') SKINKEEN()
Ошибка
Traceback (most recent call last):
File «C:/py/CSGO Trade Bot v 0.1/CSGOTB.py», line 41, in
SKINKEEN()
File «C:/py/CSGO Trade Bot v 0.1/CSGOTB.py», line 36, in SKINKEEN
BUY_SK(‘https://skinkeen.ru/’ + str(gun[2]))
File «C:/py/CSGO Trade Bot v 0.1/CSGOTB.py», line 15, in BUY_SK
element.click()
File «C:\py\CSGO Trade Bot v 0.1\venv\lib\site-packages\selenium\webdriver\remote\webelement.py», line 80, in click
self._execute(Command.CLICK_ELEMENT)
File «C:\py\CSGO Trade Bot v 0.1\venv\lib\site-packages\selenium\webdriver\remote\webelement.py», line 633, in _execute
return self._parent.execute(command, params)
File «C:\py\CSGO Trade Bot v 0.1\venv\lib\site-packages\selenium\webdriver\remote\webdriver.py», line 321, in execute
self.error_handler.check_response(response)
File «C:\py\CSGO Trade Bot v 0.1\venv\lib\site-packages\selenium\webdriver\remote\errorhandler.py», line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.ElementClickInterceptedException: Message: Element is not clickable at point (539,646) because another element obscures it
- Вопрос задан более трёх лет назад
- 1726 просмотров
Как сделать чтобы парсер мог «нажать кнопку»
Я делаю теграмм бота, в нем есть кнопка факты, я нашел сайт с генератором фактов и там есть кнопка — сгенерировать факт, мне надо «нажать кнопку» не открывая браузер, это возможно?
def get_fact(url, headers): r = requests.get(url, headers=headers) soup = BeautifulSoup(r.text, "html.parser") button = soup.find_all("button", class_="fact") fact = soup.find_all("tr", class_="td") return fact
Я сам глупость написал, но просто чтоб вы поняли
Отслеживать
задан 10 авг 2022 в 14:31
439 1 1 серебряный знак 11 11 бронзовых знаков
дайте ссылку на сайт, если не трудно.
10 авг 2022 в 14:33
2 ответа 2
Сортировка: Сброс на вариант по умолчанию
BeautifulSoup библиотека для красивого парсинга. Нужно использовать библиотеки, использующие драйвер браузера
Или как предложил человек по источнику:
Можно посмотреть через инспектор браузера (обычно на F12 вызывается) какой запрос отправляется при клике на ту кнопку и повторить ее через requests , urlopen или другую удобную вам библиотеку.
Вот пример авторизации через подсмотренный запрос:
import requests session = requests.session() rs = session.post('http://newlms.magtu.ru/login/index.php', data=) print(rs) # Если логин / пароль правильный, случится переход на главную страницу success = rs.url == 'http://newlms.magtu.ru/' print(success) if success: from bs4 import BeautifulSoup root = BeautifulSoup(rs.content, 'lxml') print('Меню:') for a in root.select('a.menu-action'): print(' <> -> <>'.format(a.text, a['href']))
Как при парсинге нажимать на кнопку python
Этим уроком мы начинаем курс, про который нас часто спрашивали — курс по парсингу данных с помощью Python. Мы уже рассказывали о парсинге без программирования, с помощью расширений для браузера, но их возможности ограничены и подходят не для всех сайтов. А вот Python поможет вам спарсить практически что угодно.
Съемка и монтаж: Глеб Лиманский
Чтобы правильно парсить, нужно понимать, как устроены сайты. Почти все они сверстаны с помощью языка HTML. Разберемся в его устройстве на примере сайта «КиноПоиск» и попробуем спарсить список из 250 лучших фильмов по версии пользователей сайта.
Похожим на «КиноПоиск» образом устроены многие сайты, с которых журналистам бывает необходимо собрать данные, поэтому он хорошо подойдет для примера.

Для этого курса мы используем браузер Google Chrome, поэтому, чтобы вам было проще понимать наши действия и не путаться в названиях функций, советуем использовать его же. Но в других браузерах, Firefox или Opera, например, все эти функции тоже есть.
Если вы кликнете на любое место сайта правой кнопкой мыши и нажмете на «Посмотреть код», то справа появится панель с кодом HTML (ее еще называют панелью разработчика).

Этот язык строится по тегам. Главный — html, в head обычно прописана метаинформация (заголовок, например), а нас сейчас интересует тег body, где лежит основная информация страницы.

Чтобы посмотреть код конкретного элемента, нужно кликнуть именно на него и нажать «Посмотреть код» — тогда в панели разработчика подсветится нужный тег.

И наоборот, если двигаться по коду в панели справа, то слева, на самой странице, будет подсвечиваться сверстанный этим тегом элемент.
На страницах со списками одни и те же теги (название, оценка и так далее) повторяются от карточки к карточке. Поэтому нужно обнаружить и выписать эти конкретные теги. Но сначала вытащим весь код страницы, и здесь пригодится библиотека Requests — мы уже рассказывали о ней, советуем сначала прочитать тот урок и установить ее.
Открываем Jupyter, импортируем библиотеку с помощью import requests. Чтобы обратиться к сайту, создаем переменную url и присваиваем ей значение нужного сайта (у нас это ссылка на топ «КиноПоиска»).

Отправим на сервер запрос с помощью команды get, на вход которой мы передаем переменную url. С помощью команды text посмотрим, что получилось.

Как видите, код получился нечитаемым. Справиться с этим поможет другая библиотека, Beautifulsoup. Импортируем ее с помощью команды from bs4 import BeautifulSoup. Возможно, для этого понадобится сначала установить библиотеку через pip install.

Мы должны передать библиотеке ответ, полученный с помощью Requests. Создадим переменную soup, передадим r.text и укажем необходимый формат (в нашем случае lxml).

Код упорядочен, теги идут один за одним — теперь мы можем вынимать из кода то, что нам нужно. Для этого вернемся в браузер, на страницу с данными. Как видно на скриншоте, подряд расположены несколько тегов div с классом desktop-rating-selection-file-item — это карточка каждого из фильмов в списке.

Сначала вытащим данные только из первой карточки, а затем перепишем код так, чтобы он сработал на все фильмы со страницы. Скопируем название класса — для этого два раза кликните на него мышкой и нажмите Ctrl+C (Cmd+C для macOS).
В Beautifulsoup есть команда find — укажем ей нужный тег (div) и через запятую класс (desktop-rating-selection-file-item). После class обязательно нужно поставить нижнее подчеркивание.

Отобразился уже не весь код, а только нужный элемент, в котором видно название фильма. Вернемся на сайт, чтобы углубиться в карточку и посмотреть, как называются нужные нам детали. Кликнем на название фильма «Зеленая миля» и снова выберем «Посмотреть код».
Например, мы видим, что ссылка на фильм лежит в теге a и имеет собственный класс selection-film-item-meta__link. В теге a, в свою очередь, есть теги p с русским и оригинальным названиями фильмов. Эти три элемента мы и заберем.

Дополним нашу первую команду: ставим точку, снова пишем find, указываем тег a и его класс.

Чтобы сделать ссылку на фильм работающей, в начале нужно дописать к ней домен. Сама ссылка лежит внутри тега, поэтому find мы применить не сможем. Воспользуемся командой get и укажем нужный атрибут (в нашем случае href).

Допишем в начало команды домен «КиноПоиска» и запустим еще раз — так мы получим готовую ссылку. Положим этот код в переменную link.

По аналогии достанем русскоязычное и оригинальное названия. Возьмем тот же код, допишем новый find, укажем нужные тег и класс. Чтобы очистить результат от ненужных элементов кода, добавим в конце команду text. Эти переменные назовем russian_name и original_name соответственно.

Еще мы можем достать из карточки страну производства и жанр — все будет работать точно так же, только класс будет не p, как у названий, а span. Страну положим в переменную country.
Однако в коде «КиноПоиска» страна и жанр имеют одинаковый класс selection-film-item-meta__meta-additional-item — а команда find находит только первое соответствие вашему запросу. Применим команду findAll, а все остальное оставим как раньше, чтобы получить список.

Чтобы вытащить только жанр, добавим нумерацию в квадратных скобках (не забывайте, что в Python отсчет идет с 0, поэтому нам нужен номер 1) и команду text. Переменную назовем film_type.

Основную информацию о фильме мы достали, но можем получить и кое-что еще — например, оценку. Проверим, как называется класс этого элемента на странице «КиноПоиска» с помощью уже известного метода «Посмотреть код». Как видите, нам повезло — класс имеет уникальное название, глубоко копать не придется.

Скопируем ту часть изначальной команды find, где мы заходим в первый div карточки фильма и сразу укажем новый поиск по тегу span и классу rating__value rating__value_positive (и не забудем про text). Переменную назовем rate.

Мы уже сделали почти всю работу, но пока что наш код работает только для первой карточки фильма в списке. Исправим это. Создадим переменную films, зададим новый поиск по самому первому div, но уже с командой findAll. И заодно посмотрим длину списка с помощью команды len. Их будет 50, потому что список топ-250 разбит на 5 страниц. Далее мы научим код ходить и по другим страницам.

Напишем цикл для каждого film в списке films. Пока скопируем команду по поиску link и посмотрим, что там нужно поправить. Нам не нужен запрос к первому div, потому что до этого мы обратились к нему через findAll — заменим его на film. Повторим так с каждым элементом.

Создадим переменную data, в который будем добавлять все переменные, которые запрашиваем.

Запустим код и посмотрим, что отображается в data.

Все ровно так, как нам было нужно. Осталось только разобраться, как собирать данные и со следующих страниц. Если мы перейдем на вторую страницу списка, то увидим, что ссылка в адресной строке браузера изменилась — там появилось page=2.

То есть, нам нужно передать этот параметр в цикл. Создадим перед циклом переменную url и воспользуемся методом f-строк, чтобы поместить внутрь фигурных скобок тот параметр, который нам нужен — номер страницы. Назовем параметр p и поместим его в цикл в промежутке от 1 до 6.
Переменную data при этом нужно вынести в начало кода, чтобы она не перезаписывалась с каждым новым циклом, а дополнялась. После этого скопируем код для запуска Requests и Beautifulsoup.

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

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

Все должно сработать. Если сейчас снова проверить длину нашего списка командой len(data), там будет 250 — как и в топе «КиноПоиска». Теперь сохраним наши данные в таблицу. Снова вернемся в область импорта и добавим туда Pandas и используем его для записи в csv.

Введем названия для колонок — пусть они дублируют названия переменных, которые мы присвоили ранее (не забудьте поместить их в ‘кавычки’). И после этого экспортируем наши данные.
Статья Сбор данных с сайта знакомств с помощью Selenium, BeautifulSoup и requests используя скрипт на Python
В данной статье я предлагаю вам немного отвлечься от слишком серьезных задач и попрактиковаться в парсинге. А, чтобы не было скучно, будем мы парсить достаточно известный сайт знакомств. А именно, забирать оттуда фото пользователей. Для наших целей мы будем использовать Selenium, BeautifulSoup, requests. А работать это будет в скрипте Python.
Дисклеймер : Все данные, предоставленные в данной статье, взяты из открытых источников, не призывают к действию и являются только лишь данными для ознакомления, и изучения механизмов используемых технологий .
Сначала немного (совсем чуть-чуть) предыстории. Уж не помню точно, что я искал в сети, но наткнулся на один забавный форум. Ничего необычного. Решил походить по разделам и наткнулся на забавный инструмент, сделанный на BAS. BAS – это BrowserAutomationStudio. Не знаю, насколько он популярен сейчас, однако пару-тройку лет назад, а примерно тогда и была написана статья об этом инструменте, был достаточно популярен.
Топикстартер пишет, что делал этот инструмент под свои нужды. Не буду даже предполагать, какие они у него. Но позиционирует он данный инструмент для достаточно широкого круга пользователей. То есть: для арбитражников, которые льют трафик на дейтинг и им нужно фото для профилей; людям пишущим автореги – для заполнения профилей; ну и собственно тем, кому просто нужно фото (хоть и не знаю для чего).
Если отбросить в сторону все эти, безусловно, конкретные цели, сама задача мне показалась интересной в качестве практики. Тут и авторизация и поиск ссылок на фото. Поэтому, я решил его сделать, ну и поделиться конечным результатом. Кто знает, может быть будет кому-то полезен.
Давайте же начинать.
Что потребуется?
Для начала – регистрация на данном сайте, то есть:
Ссылка скрыта от гостей
. К сожалению, без регистрации попасть дальше анкеты пользователя и его альбома с фото не получиться. В самом альбоме прямых ссылок на фото нет. Поэтому придется открывать каждую фотографию, чтобы ссылку эту получить. А без регистрации открыть фото нельзя. Для регистрации идем на любой сервис временной почты, получаем e-mail и регистрируемся хоть папой Римским. Это совершенно не важно, в данном конкретном случае. Я даже накидал небольшую схемку доступа для данного сайта.
Теперь, что касается будущего скрипта. Для его работы нам понадобиться несколько сторонних библиотек. А именно: Selenium – для автоматизации браузера; BeautifulSoup – для парсинга страниц; lxml – парсер; requests – для скачивания фото. Поэтому, для их установки пишем в терминале:
pip install selenium bs4 lxml requests
Для тех, у кого не получается установить сразу же несколько библиотек, попробуйте установить каждую по отдельности. Для примера:
pip install selenium
После этого, так как мы будем использовать selenium, необходимо скачать webdriver для конкретного браузера. Я использую Google Chrome, потому буду качать драйвер именно под него. Для того, чтобы узнать, какая версия драйвера нужна именно в вашем случае, запускаем браузер, жмем на три точки в правом верхнем углу, идем к пункту меню «Справка» и жмем на пункт «О браузере Google Chrome».
Пункт меню в браузере
Откроется страница, где и будет указана версия. На момент написания статьи версия браузера была: 112.0.5615.138.
Версия браузера Google Chrome
Здесь нам важна первая цифра номера версии: 112, для того, чтобы скачать драйвер. Поэтому, идем на страницу
Ссылка скрыта от гостей
и выбираем нужную нам, после чего попадаем в репозиторий и качаем webdriver под вашу операционную систему.
Версия драйвера для загрузки
После того, как драйвер будет загружен, необходимо положить его куда-то, в директории вашего скрипта, ну или просто прописать путь к нему в переменных окружения. Я пошел по простому пути, поэтому положил драйвер в папку… driver.
И еще, одна небольшая деталь. После того, как вы зарегистрируетесь на сайте, вы получите логин и пароль. Тут уже по вашим предпочтениям. Можете напрямую указать их в коде или, как поступил я, создать отдельный файл (у меня это set_love.py), в котором прописать полученные данные. Для примера:
login = 'ххххх@ххххххххх.com' # ваш логин password = 'хххххххххххххххх' # ваш пароль
А после импортировать в скрипт данные переменные. Впрочем, данные тут не такие уж секретные, а потому, на ваше усмотрение.
Что же, с подготовкой, вроде бы закончили. Давайте приступать к написанию кода.
Импорт библиотек в скрипт
Для работы скрипта необходимо импортировать все нужные в процессе его работы библиотеки. Поэтому, создаем файл love_planet_parse.py и прописываем блок импорта:
import os import sys import time from pathlib import Path from platform import system import requests from bs4 import BeautifulSoup from selenium import webdriver from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.chrome.options import Options from selenium.webdriver.chrome.service import Service from selenium.webdriver.common.by import By from set_love import login, password
Теперь, для того, чтобы сайт не считал, что мы используем ПО для автоматизации, необходимо указать опции, которые впоследствии будут переданы в webdriver:
options = Options() # options.add_argument("--headless") options.add_experimental_option("excludeSwitches", ["enable-automation"]) options.add_experimental_option('useAutomationExtension', False) options.add_argument("--disable-blink-features=AutomationControlled") options.add_argument("--disable-notifications")
Режим безголовости в данном случае не нужен. Позже поясню почему.
Указываем путь к загруженному нами ранее webriver и создаем переменную, в которую будем складывать адреса просмотренных страниц.
exec_path = os.path.join(os.getcwd(), 'driver', 'chromedriver.exe') if system() == "Windows" else \ os.path.join(os.getcwd(), 'driver', 'chromedriver') all_link = set()
С этого момента, думаю, что будем двигаться по порядку запуска функций в данном скрипте, а не в порядке их расположения. Это необходимо, для лучшего понимания логики работы. А потому, начнем с самого начала – с запроса параметров у пользователя.
Запрос параметров поиска
Для того чтобы понимать как ходить по страница поиска нужно было пройти небольшой квест. Для примера, значок поиска появляется только после того, как вы авторизуетесь на сайте. Именно этот значок нужен для того, чтобы появилась ссылка с нужными параметрами. Поэтому, авторизуемся и жмем на данный значок:
Значок поиска на сайте
И получаем вот такую ссылку:
Рассмотрим несколько параметров из нее, которые будут нам необходимы. pol-1 – это пол того, кто ищет. В данном случае 1 – соответствует пункту меню: Парень. spol-2 – пол того, кого ищут. В данном случае 2 – пункт меню: Девушку. Здесь будьте внимательны и аккуратны. Так как при неверном указании параметров можете найти не совсем то, что вам хотелось, вроде парней считающих себя девушками и девушек, считающих себя парнями ))
tage-35 – ограничение поиска по возрасту: До… bage-18 – ограничение поиска по возрасту: От…proof-1 – соответствует выставлению галочки – Проверенные фото. country – страна. В нашем случае 0, то есть все страны, равно как и у параметров: region и city.
Однако в данном запросе все еще нет страниц. И если вы попытаетесь прокрутить страницу до пагинации в авторизованном режиме, вы ее просто не найдете, так как анкеты будут подгружаться динамически. А вот для того, чтобы получить пагинацию, нужно эту же ссылку поиска вбить в режиме без авторизации. И перейти на любую страницу. Тут уже появляется нужный параметр. Нумерация страниц начинается с 0.
p-1 – номер страницы.
Ссылка на поиск наглядно
Теперь, когда у нас есть поисковый запрос на сайте, можно приступать к написанию кода.
Создаем функцию main() -> None. Определяем глобальные параметры: all_link, и глобальный параметр внутри функции: driver. Если вы побываете на сайте, то достаточно быстро поймете, что страниц с анкетами пользователей там достаточно много. Поэтому, скорее всего, выкачать все фото за один раз у вас не получиться. Хотя, кто знает, тут уже только ваше упорство. Тем не менее, при закрытии скрипта реализуем небольшой код, который будет сохранять содержимое all_link, а именно здесь будут храниться просмотренные адреса страниц анкет в текстовый файл. Проверяем наличие такого файла. Если он есть, загружаем его в множество all_link. Затем просим пользователя ввести пол для поиска. Тут еще можно добавить два пункта (Не такие мужчины, Не такие женщины), но, я этого делать не буду. В этом случае ничего в логике скрипта не измениться, будут только лишь меняться параметры в поисковом запросе. Проверяем корректность ввода. Просим ввести возраст До. Затем возраст От. Выполняем небольшие проверки на корректность ввода.
def main() -> None: global all_link driver = None try: if Path('links_people.txt').exists(): with open('links_people.txt', 'r', encoding='utf-8') as file: for ln in file.readlines(): all_link.add(ln.strip()) spol = input('Выберите пол для поиска фото:\n [1] Мужчины\n [2] Женщины\n >>> ') if spol not in ["1", "2"]: print('Введите корректный пол!') sys.exit(0) tage = input("Введите возраст до (max=100): ") if not tage.isdigit() or int(tage) > 100: print("Вы ввели не число. Перезапустите программу!") sys.exit(0) bage = input("Введите возраст от (min=18): ") if not bage.isdigit() or int(bage) < 18: print("Вы ввели слишком юный возраст! Перезапустите программу!") sys.exit(0)
После этого создаем объект драйвера, передаем в него указанные ранее опции, а также запускаем скрипт по удалению параметров, по которым можно определить, что используется автоматизированное ПО.
driver = webdriver.Chrome(options=options, service=Service(log_path=os.devnull, executable_path=exec_path)) driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", < 'source': ''' delete window.cdc_adoQpoasnfa76pfcZLmcfl_Array; delete window.cdc_adoQpoasnfa76pfcZLmcfl_Promise; delete window.cdc_adoQpoasnfa76pfcZLmcfl_Symbol; ''' >)
Запускаем функцию авторизации, в которую передаем созданные объект драйвера. После авторизации проверяем, что ввел пользователь и, в зависимости от этого, передаем параметры в функцию поиска find_people. Также, оборачиваем весь код в блок try – except и обрабатываем прерывание с клавиатуры. Закрываем браузер и сохраняем данные из множества в текстовый документ. Ну и также прописываем закрытие браузера после окончания работы скрипта.
logging(driver) if spol == "1": find_people(int(tage), int(bage), 1, 2, driver) elif spol == "2": find_people(int(tage), int(bage), 2, 1, driver) except KeyboardInterrupt: driver.close() driver.quit() with open('links_girl.txt', 'w', encoding='utf-8') as file: for lin in all_link: file.write(f'\n') driver.close() driver.quit()
Полный код функции запроса параметров поиска
def main() -> None: """ Запрос параметров поиска у пользователя. Проверка полученных параметров. Загрузка просмотренных ссылок и добавление их в множество для будущих проверок. Запуск функции авторизации и перехода по страницам. Если закрыт браузер или выполнено прерывание по "Ctrl + C" сохраняется информация о просмотренных страницах. """ global all_link driver = None try: if Path('links_people.txt').exists(): with open('links_people.txt', 'r', encoding='utf-8') as file: for ln in file.readlines(): all_link.add(ln.strip()) spol = input('Выберите пол для поиска фото:\n [1] Мужчины\n [2] Женщины\n >>> ') if spol not in ["1", "2"]: print('Введите корректный пол!') sys.exit(0) tage = input("Введите возраст до (max=100): ") if not tage.isdigit() or int(tage) > 100: print("Вы ввели не число. Перезапустите программу!") sys.exit(0) bage = input("Введите возраст от (min=18): ") if not bage.isdigit() or int(bage) < 18: print("Вы ввели слишком юный возраст! Перезапустите программу!") sys.exit(0) driver = webdriver.Chrome(options=options, service=Service(log_path=os.devnull, executable_path=exec_path)) driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", < 'source': ''' delete window.cdc_adoQpoasnfa76pfcZLmcfl_Array; delete window.cdc_adoQpoasnfa76pfcZLmcfl_Promise; delete window.cdc_adoQpoasnfa76pfcZLmcfl_Symbol; ''' >) logging(driver) if spol == "1": find_people(int(tage), int(bage), 1, 2, driver) elif spol == "2": find_people(int(tage), int(bage), 2, 1, driver) except KeyboardInterrupt: driver.close() driver.quit() save_data() driver.close() driver.quit()
Сохранение данных в файл
Создадим небольшую функцию save_data(), которая будет необходима для сохранения просмотренных страниц анкет в файл. Так как данная функция дублируется в нескольких местах.
def save_data(): global all_link with open('links_people.txt', 'w', encoding='utf-8') as file: for lin in all_link: file.write(f'\n')
Авторизация на сайте
В самой по себе авторизации на сайте с помощью selenium нет ничего особо сложного. Достаточно найти поля ввода и передать в них нужные данные, после чего нажать кнопку авторизации.
Создадим функцию logging(driver) -> None. В нее передается объект драйвера. Переходим на страницу авторизации. Ждем полсекунды для того, чтобы все прогрузилось. Ищем поле ввода логина по CSS-селектору. Отправляем в него логин. Также ищем поле ввода пароля и помещаем в него пароль. После чего еще чуть ожидания, ищем кнопку для отправки данных и жмем на нее.
Тут есть небольшой нюанс. Если вы первый раз заходите на сайт, да и вообще делаете это не слишком часто, то все будет хорошо и подойдет вышеописанный алгоритм. Однако, если вы мучаете сайт постоянными входами и выходами, вам будет предложено ввести капчу. Поэтому, обрабатываем исключение, которое возникнет, когда не будет найдена кнопка отправки данных. Дело в том, что ее селектор сместиться на 1. Так как добавиться еще поле ввода для капчи. Потому, ищем это поле ввода, помещаем в него курсор и ручками вбиваем капчу. На это действие у вас будет 5 секунд. Я успевал. За редким исключением, когда капча уж совсем дикая. Ну, а далее жмем кнопку отправки данных. Не нажимайте ее ручками. Скрипт все сделает за вас. От вас только требуется ввести капчу.
def logging(driver) -> None: """ Авторизация на сайте. Если часто авторизоваться выскакивает капча. В этом случае предоставляется время - 5 секунд, чтобы ее ввести. """ """Поиск полей. Заполнение паролем и логином.""" driver.get('https://loveplanet.ru/a-logon') time.sleep(0.5) field_login = driver.find_element(By.CSS_SELECTOR, '#dlg_login_log') field_login.send_keys(login) time.sleep(0.2) field_pass = driver.find_element(By.CSS_SELECTOR, '#dlg_login_pas') field_pass.send_keys(password) try: """Если нет капчи, просто нажатие на кнопку вход""" button = driver.find_element(By.CSS_SELECTOR, '#dlg_login > ul > li:nth-child(4) > button') button.click() time.sleep(1) except NoSuchElementException: """Если есть капча, пауза, затем нажатие на вход""" field_capt = driver.find_element(By.CSS_SELECTOR, '#dlg_pict_val') field_capt.click() time.sleep(5) button = driver.find_element(By.CSS_SELECTOR, '#dlg_login > ul > li:nth-child(5) > button') button.click() time.sleep(1)
Постраничный переход в бесконечном цикле
Создадим функцию find_people(tage: int, bage: int, spol: int, pol: int, driver: webdriver) -> None, которая принимает возраст До, возраст От, пол который искать, пол ищущего, и вебдрайвер.
Для поиска ссылок нам потребуется перейти на страницу, получить ее код и передать в функцию поиска. Что мы и сделаем. Неудобство данного сайта в том, что непонятно, какое количество страниц с анкетами пользователя доступно для просмотра. Потому и бесконечный цикл. Однако, если, для примера, ввести страницу 1000, то на данной странице отобразиться только одна анкета. И так будет, какой бы номер мы не вводили далее: 1001, 1002 … Поэтому, будем проверять количество найденных анкет. И если количество равно 1, то увеличивать счетчик. Далее проверять, если счетчик равен или больше 2, то выходим из цикла с сохранением данных.
Здесь все просто. Переходим на страницу, ищем ссылки на анкеты, а соответственно, выполняем все действия по загрузке, с помощью функции find_pages, куда передаем код страницы, драйвер и номер страницы. Данная функция и будет возвращать количество найденных ссылок на анкеты. Проверяем, если количество ссылок 1, увеличиваем счетчик. Проверяем счетчик, если он меньше 2, выполним еще одну итерацию, на всякий случай. Если же второй раз вернулось то же самое, то есть 1, то снова увеличиваем счетчик и уже выходим из функции с сохранением ссылок. Ну и обрабатываем исключение, если вы закроете браузер или возникнет исключение.
def find_people(tage: int, bage: int, spol: int, pol: int, driver: webdriver) -> None: """ Переход по страницам сайта. Запуск функции поиска страниц. """ num = 0 link_count = 0 while True: try: url = f'https://loveplanet.ru/a-search/d-1/pol-/spol-/tage-/bage-/purp-0/proof-1/country-0/region-0/city-0/p-' driver.get(url) time.sleep(1) count = find_pages(driver.page_source, driver, num) if count == 1: link_count += 1 if link_count >= 2: save_data() break num += 1 except Exception as ex: print(ex) save_data() break print("All pages down")
Поиск ссылок на анкеты пользователей
Создадим функцию find_pages(source: str, driver: webdriver, num: int) -> int. На входе она получает код страницы со ссылками на анкеты, вебдрайвер, номер страницы. А возвращает количество найденных ссылок на анкеты.
Для начала создадим объект BeautifulSoup, в который передадим код страницы и укажем парсер, с помощью которого будем парсить код. Выполняем поиск ссылок, которые содержаться в «div» с классом «to_els fbold». Вот этот тег для наглядности на изображении:
Ссылка на анкету в коде
Проверяем, есть ли что-то в найденных ссылках. Создаем два списка, в которые будем помещать имя владельца анкеты и ссылку на страницу анкеты. Затем в цикле перебираем найденные ссылки. Находим тег «a», из которого забираем текст содержащий имя, а также ссылку на анкету. Проверяем, нет ли найденной ссылки в множестве. Так как, данная анкета уже может быть обработана ранее. Если есть, пропускаем. Если нет, добавляем ссылку и имя в соответствующие списки.
def find_pages(source: str, driver: webdriver, num: int) -> int: global all_link soup = BeautifulSoup(source, 'lxml') if links := soup.find_all('div', class_='to_els fbold'): names = [] pages = [] for link in links: name = link.find('a').text.strip() page = f"https://loveplanet.ru" if page in all_link: print("Просмотрено") continue else: pages.append(page) names.append(name)
После того, как будет выполнен поиск, запустим функции для поиска данных и загрузки фото. В цикле перебираем полученные ссылки. Забираем из списка с именем по индексу имя пользователя анкеты. Из него мы будем формировать уникальное имя для папки, куда будем складывать данные по анкете. Так как, для примера Оксан на данном сайте, сами понимаете, может быть очень большое количество. Выводим в терминал данные об обрабатываемой странице. Переходим по ссылке в браузере. Затем передаем в функцию find_data код страницы анкеты, а также имя и номер который добавляем к нему и ссылку на анкету. Это будет необходимо для общих данных, которые мы соберем со страницы анкеты. Так как я подумал, что получение только фото будет достаточно скучным.
Функция вернет нам имя со страницы уже с возрастом пользователя и добавленными в него данными переданными ранее для формирования имени для директории. Ждем секунду и запускаем функцию поиска фото, куда также передаем код страницы, полученное имя директории и драйвер. И только после этого добавляем ссылку на анкету в глобальное множество, то есть, после выполнения всех действий, чтобы не получилось так, что данные не собраны, а ссылка уже в множестве. А это значит, что парсер в следующий раз просто пропустит страницу с несобранными данными. Ну и возвращаем из функции количество найденных ссылок на анкеты.
print(f'Обработка страниц:') """Переход на страницу пользователя. Сбор информации. запуск функции поиска фото""" for n, pg in enumerate(pages): print(f'[]. | ') driver.get(pg) name_age = find_data(driver.page_source, f"_", pg) time.sleep(1) find_photo(driver.page_source, name_age, driver) all_link.add(pg) return len(pages)
Полный код функции поиск ссылок
def find_pages(source: str, driver: webdriver, num: int) -> int: """ Поиск ссылок на страницы пользователей. """ global all_link """Поиск ссылок. Проверка на наличие в уже проверенных. Если есть - пропуск""" soup = BeautifulSoup(source, 'lxml') if links := soup.find_all('div', class_='to_els fbold'): names = [] pages = [] for link in links: name = link.find('a').text.strip() page = f"https://loveplanet.ru" if page in all_link: print("Просмотрено") continue else: pages.append(page) names.append(name) print(f'Обработка страниц:') """Переход на страницу пользователя. Сбор информации. запуск функции поиска фото""" for n, pg in enumerate(pages): print(f'[]. | ') driver.get(pg) name_age = find_data(driver.page_source, f"_", pg) time.sleep(1) find_photo(driver.page_source, name_age, driver) all_link.add(pg) return len(pages)
Получение данных со страницы анкеты
Создадим функцию find_data(source: str, name: str, url: str) -> str. Возвращает она сформированное на основании полученных данных имя директории для сохранения фото. А на входе получает код страницы с анкетой, имя, которое формируется в предыдущей функции из имени пользователя, плюс номер страницы с анкетами и ссылку на страницу анкеты.
Создаем список, куда будем складывать все полученные данные для последующего сохранения. Создаем объект BeautifulSoup, куда передаем код страницы и парсер. Далее выполняем поиск имени пользователя. На странице анкеты имя пользователя отображается вместе с его возрастом. Для примера: «Надежда, 25». Не буду подробно описывать теги. Их можно посмотреть в коде. Укажу только изображение с данными тегами на странице.
Имя пользователя анкеты с его возрастом
Также заберем город и страну, которые указал пользователь при создании анкеты. В коде данная информация забирается в переменную location.
Страна и город пользователя
Здесь ищем и забираем данные из блока: «Я ищу».
Теги блока «Я ищу»
Все полученные данные добавляем в список data.
def find_data(source: str, name: str, url: str) -> str: data = [] soup = BeautifulSoup(source, 'lxml') name_age = soup.find('div', class_='flex ai-center mb24').find('span', class_='fbold fsize20').text.strip() data.append(name_age) location = soup.find('div', class_='flex ai-center jc-between').find('div', class_='blue_14').find('span').text. \ strip() data.append(f'\n') su = soup.find('div', class_='fbold fsize15 mb6').text.strip() ifind = soup.find('ul', class_='reset fsize15 mt7').find('li').text.strip() data.append(f': ')
Также на странице (у большинства) есть блок с Личной информацией. Ее нам тоже нужно найти и забрать. Так как информации на странице может не оказаться, обрабатываем исключение как при переборе тегов «li», так и при получении информации о самом блоке.
Блок с личной информацией
После этого выводим полученные данные в терминал. Хотя, на самом деле в этом нет необходимости. Надо указать, что данная информация не является закрытой и может быть получена с данного сайта даже без авторизации.
try: data.append(f"\n:") info = soup.find('ul', class_='reset list_info show li_mt10').find_all('li') for inf in info: try: lb = f" " data.append(lb) except Exception: continue except Exception: pass data.append(f'\n') print(data)
Затем проверяем, не пуст ли список с данными. Если нет, создаем директорию, имя которой формируем из полученного в функцию имени с номером, добавляем к ней имя с возрастом. Громоздко, но достаточно уникально. Вполне может быть, можно было бы брать просто уникальное имя пользователя сайта из пути к странице. Но так просто выходит нагляднее. Ну и сохраняем полученные данные в созданную директорию в текстовый документ. После чего, возвращаем из функции имя созданной директории, так как оно будет нам нужно при сохранении фото из анкеты.
if data: path = Path.cwd() / 'photo' path.mkdir(exist_ok=True) path = path / f'_' path.mkdir(exist_ok=True) with open(path / f'.txt', 'w', encoding='utf-8') as file: for dat in data: file.write(f'\n') return f'_'
Полный код функции получения данных со страницы анкеты
def find_data(source: str, name: str, url: str) -> str: """ Поиск и сбор информации со страницы пользователя. Возвращает имя и возраст. """ """Поиск имени и информации "Я ищу. """"" data = [] soup = BeautifulSoup(source, 'lxml') name_age = soup.find('div', class_='flex ai-center mb24').find('span', class_='fbold fsize20').text.strip() data.append(name_age) location = soup.find('div', class_='flex ai-center jc-between').find('div', class_='blue_14').find('span').text. \ strip() data.append(f'\n') su = soup.find('div', class_='fbold fsize15 mb6').text.strip() ifind = soup.find('ul', class_='reset fsize15 mt7').find('li').text.strip() data.append(f': ') """Поиск доступной личной информации""" try: data.append(f"\n:") info = soup.find('ul', class_='reset list_info show li_mt10').find_all('li') for inf in info: try: lb = f" " data.append(lb) except Exception: continue except Exception: pass data.append(f'\n') print(data) """Проверка, если список с данными не пуст, сохраняем их в текстовый документ""" if data: path = Path.cwd() / 'photo' path.mkdir(exist_ok=True) path = path / f'_' path.mkdir(exist_ok=True) with open(path / f'.txt', 'w', encoding='utf-8') as file: for dat in data: file.write(f'\n') return f'_'
Получение ссылок на фото, загрузка и сохранение
Создадим функцию find_photo(source: str, name: str, driver: webdriver) -> None. На входе она получает код страницы анкеты, имя директории в которую будут сохранятся фото и вебдрайвер.
Так как мы будем сохранять фото с помощью библиотеки requests, нам необходимо определить заголовки для запроса. Поэтому добавим User-Agent, Accept и Host. Кстати, из этого также следует, что если вам удалось получить ссылку на фото, то она будет работать и без авторизации.
def find_photo(source: str, name: str, driver: webdriver) -> None: headers = < 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 ' 'Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,' 'application/signed-exchange;v=b3;q=0.7', 'Host': 'loveplanet.ru' >
Создаем объект BeautifulSoup, в который передаем код страницы анкеты и указываем парсер. После этого необходимо получить ссылку на альбом. Так как под основной фотографией пользователя располагается блок, в котором находятся превью фото, логично было бы парсить ссылки оттуда. Но, у некоторых пользователей нет этого блока, у кого-то там одна, основная фотография, а у кого-то так много фото, что дополнительные скрыты под спойлером. Обрабатывать каждый случай не имеет смысла. Поэтому, будем забирать ссылку из основной фотографии пользователя, которая также подтягивается из альбома. И вот уже здесь обработаем три случая с помощью блоков try – except. Дело в том, что есть два типа аккаунтов. Обычные и «элитные». Ну, или те, которые продвигаются системой. Они на странице поиска выделены желтой рамкой. В этом случае теги на странице будут слегка отличаться. Поэтому, для начала ищем обычное фото.
Ссылка на альбом в обычном аккаунте
Затем, если тегов не найдено, обрабатываем исключение и пытаемся найти «элитный».
Ссылка на альбом в «элитном» аккаунте
И уже совсем тяжелый случай, когда аккаунт есть, а фото никаких в него не загружено. Тогда система отображает картинку по умолчанию для анкет без фото. В этом случае также обрабатываем исключение. А так как фото в данном случае нет, возвращаемся из функции. Искать то нечего, равно как и двигаться дальше нет смысла.
После этого обрабатываем ссылку на фото, а это будет именно она, удалив последнюю часть после «/». Добавляем домен и переходим по сформированной ссылке на страницу альбома. После чего ждем полсекунды.
soup = BeautifulSoup(source, 'lxml') try: user_info_left = soup.find('div', class_='user-info_left').find('div', class_='prof-photo p_rel mb15'). \ find('a', class_='block')['href'] except (AttributeError, TypeError): try: user_info_left = soup.find('div', class_='user-info_left'). \ find('div', class_='frame-elite prof-photo p_rel mb15').find('a', class_='block')['href'] except (AttributeError, TypeError): return user_info_left = f'https://loveplanet.ru' driver.get(user_info_left) time.sleep(0.5)
Дальше, после того, как мы перейдем на страницу альбома, собираем ссылки на все фото в нем. Также создаем объект BeautifulSoup, передаем в него код страницы альбома и парсер. Ищем все теги со ссылками на фото. После в цикле пробегаемся по ним, забираем ссылки из тегов и добавляем в список для последующей обработки.
sp = BeautifulSoup(driver.page_source, 'lxml') ul = sp.find('ul', class_='reset album_photo_list lifl ovh').find_all('li', class_='p_rel') photo_links = [] for li in ul: ph = li.find('div', class_='img_clr tdbox').find('a')['href'] photo_links.append(f'https://loveplanet.ru')
Однако, полученные ссылки, это еще не совсем ссылки на фото. Это скорее ссылки на тулбокс, куда и подгружаются ссылки на фото. Поэтому, браузеру необходимо перейти по каждой найденной ссылке. Запускаем цикл, итерируемся по полученным ссылкам на тулбоксы. Переходим по ссылке на страницу. Забираем ее код и передаем в BeautifulSoup. Затем ищем тег, который содержит ссылку на фото. Ну, а далее выполняем запрос по найденной ссылке и загружаем ее на диск в указанную директорию, перед этим, на всякий случай пишем код, который создает эту директорию. В функции Path хорошо то, что она самостоятельно обрабатывает исключения, если директория существует, при указании соответствующего параметра: exist_ok=True. Ну и, собственно, обрабатываем статус-коды и возникшие исключения.
for n, photo in enumerate(photo_links): driver.get(photo) sp_ph = BeautifulSoup(driver.page_source, 'lxml') link = sp_ph.find('div', class_='gnl_photo_show tdbox').find('img')['src'] try: res = requests.get(url=link, headers=headers) if res.status_code == 200: path = Path.cwd() / 'photo' path.mkdir(exist_ok=True) path = path / name path.mkdir(exist_ok=True) with open(path / f'photo_.jpg', 'wb') as pht: pht.write(res.content) else: continue except Exception: continue
Полный код функции получения ссылок и загрузки фото
def find_photo(source: str, name: str, driver: webdriver) -> None: """ Поиск фото. Сохранение на диск. """ headers = < 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 ' 'Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,' 'application/signed-exchange;v=b3;q=0.7', 'Host': 'loveplanet.ru' >soup = BeautifulSoup(source, 'lxml') """Поиск ссылок на альбом пользователя.""" try: user_info_left = soup.find('div', class_='user-info_left').find('div', class_='prof-photo p_rel mb15'). \ find('a', class_='block')['href'] except (AttributeError, TypeError): try: user_info_left = soup.find('div', class_='user-info_left'). \ find('div', class_='frame-elite prof-photo p_rel mb15').find('a', class_='block')['href'] except (AttributeError, TypeError): return """Переход по найденным ссылкам на альбомы. Поиск ссылок на фото.""" user_info_left = f'https://loveplanet.ru' driver.get(user_info_left) time.sleep(0.5) sp = BeautifulSoup(driver.page_source, 'lxml') ul = sp.find('ul', class_='reset album_photo_list lifl ovh').find_all('li', class_='p_rel') photo_links = [] for li in ul: ph = li.find('div', class_='img_clr tdbox').find('a')['href'] photo_links.append(f'https://loveplanet.ru') """Загрузка ссылок на диск.""" for n, photo in enumerate(photo_links): driver.get(photo) sp_ph = BeautifulSoup(driver.page_source, 'lxml') link = sp_ph.find('div', class_='gnl_photo_show tdbox').find('img')['src'] try: res = requests.get(url=link, headers=headers) if res.status_code == 200: path = Path.cwd() / 'photo' path.mkdir(exist_ok=True) path = path / name path.mkdir(exist_ok=True) with open(path / f'photo_.jpg', 'wb') as pht: pht.write(res.content) else: continue except Exception: continue
Вот в принципе и все. После того, как написан код, запустим получившийся скрипт и посмотрим, что он нам насобирает.
Собранные данные с сайта
Конечно же, это далеко не все, что можно загрузить. Я собрал несколько анкет и прервал работу скрипта. В результате такого прерывания был создан файл с уже просмотренными анкетами. Таким образом, в следующий раз данные анкеты обрабатываться не будут.
Файл с просмотренными анкетами
К чему этот код? Просто, для того, чтобы попрактиковаться в парсинге данных. Ну и это просто весело.
Полный код скрипта для сбора данных
# pip install selenium bs4 lxml requests import os import sys import time from pathlib import Path from platform import system import requests from bs4 import BeautifulSoup from selenium import webdriver from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.chrome.options import Options from selenium.webdriver.chrome.service import Service from selenium.webdriver.common.by import By from set_love import login, password options = Options() # options.add_argument("--headless") options.add_experimental_option("excludeSwitches", ["enable-automation"]) options.add_experimental_option('useAutomationExtension', False) options.add_argument("--disable-blink-features=AutomationControlled") options.add_argument("--disable-notifications") exec_path = os.path.join(os.getcwd(), 'driver', 'chromedriver.exe') if system() == "Windows" else \ os.path.join(os.getcwd(), 'driver', 'chromedriver') all_link = set() def logging(driver) -> None: """ Авторизация на сайте. Если часто авторизоваться выскакивает капча. В этом случае предоставляется время - 5 секунд, чтобы ее ввести. """ """Поиск полей. Заполнение паролем и логином.""" driver.get('https://loveplanet.ru/a-logon') time.sleep(0.5) field_login = driver.find_element(By.CSS_SELECTOR, '#dlg_login_log') field_login.send_keys(login) time.sleep(0.2) field_pass = driver.find_element(By.CSS_SELECTOR, '#dlg_login_pas') field_pass.send_keys(password) try: """Если нет капчи, просто нажатие на кнопку вход""" button = driver.find_element(By.CSS_SELECTOR, '#dlg_login > ul > li:nth-child(4) > button') button.click() time.sleep(1) except NoSuchElementException: """Если есть капча, пауза, затем нажатие на вход""" field_capt = driver.find_element(By.CSS_SELECTOR, '#dlg_pict_val') field_capt.click() time.sleep(5) button = driver.find_element(By.CSS_SELECTOR, '#dlg_login > ul > li:nth-child(5) > button') button.click() time.sleep(1) def find_pages(source: str, driver: webdriver, num: int) -> int: """ Поиск ссылок на страницы пользователей. """ global all_link """Поиск ссылок. Проверка на наличие в уже проверенных. Если есть - пропуск""" soup = BeautifulSoup(source, 'lxml') if links := soup.find_all('div', class_='to_els fbold'): names = [] pages = [] for link in links: name = link.find('a').text.strip() page = f"https://loveplanet.ru" if page in all_link: print("Просмотрено") continue else: pages.append(page) names.append(name) print(f'Обработка страниц:') """Переход на страницу пользователя. Сбор информации. запуск функции поиска фото""" for n, pg in enumerate(pages): print(f'[]. | ') driver.get(pg) name_age = find_data(driver.page_source, f"_", pg) time.sleep(1) find_photo(driver.page_source, name_age, driver) all_link.add(pg) return len(pages) def find_data(source: str, name: str, url: str) -> str: """ Поиск и сбор информации со страницы пользователя. Возвращает имя и возраст. """ """Поиск имени и информации "Я ищу. """"" data = [] soup = BeautifulSoup(source, 'lxml') name_age = soup.find('div', class_='flex ai-center mb24').find('span', class_='fbold fsize20').text.strip() data.append(name_age) location = soup.find('div', class_='flex ai-center jc-between').find('div', class_='blue_14').find('span').text. \ strip() data.append(f'\n') su = soup.find('div', class_='fbold fsize15 mb6').text.strip() ifind = soup.find('ul', class_='reset fsize15 mt7').find('li').text.strip() data.append(f': ') """Поиск доступной личной информации""" try: data.append(f"\n:") info = soup.find('ul', class_='reset list_info show li_mt10').find_all('li') for inf in info: try: lb = f" " data.append(lb) except Exception: continue except Exception: pass data.append(f'\n') print(data) """Проверка, если список с данными не пуст, сохраняем их в текстовый документ""" if data: path = Path.cwd() / 'photo' path.mkdir(exist_ok=True) path = path / f'_' path.mkdir(exist_ok=True) with open(path / f'.txt', 'w', encoding='utf-8') as file: for dat in data: file.write(f'\n') return f'_' def find_photo(source: str, name: str, driver: webdriver) -> None: """ Поиск фото. Сохранение на диск. """ headers = < 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 ' 'Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,' 'application/signed-exchange;v=b3;q=0.7', 'Host': 'loveplanet.ru' >soup = BeautifulSoup(source, 'lxml') """Поиск ссылок на альбом пользователя.""" try: user_info_left = soup.find('div', class_='user-info_left').find('div', class_='prof-photo p_rel mb15'). \ find('a', class_='block')['href'] except (AttributeError, TypeError): try: user_info_left = soup.find('div', class_='user-info_left'). \ find('div', class_='frame-elite prof-photo p_rel mb15').find('a', class_='block')['href'] except (AttributeError, TypeError): return """Переход по найденным ссылкам на альбомы. Поиск ссылок на фото.""" user_info_left = f'https://loveplanet.ru' driver.get(user_info_left) time.sleep(0.5) sp = BeautifulSoup(driver.page_source, 'lxml') ul = sp.find('ul', class_='reset album_photo_list lifl ovh').find_all('li', class_='p_rel') photo_links = [] for li in ul: ph = li.find('div', class_='img_clr tdbox').find('a')['href'] photo_links.append(f'https://loveplanet.ru') """Загрузка ссылок на диск.""" for n, photo in enumerate(photo_links): driver.get(photo) sp_ph = BeautifulSoup(driver.page_source, 'lxml') link = sp_ph.find('div', class_='gnl_photo_show tdbox').find('img')['src'] try: res = requests.get(url=link, headers=headers) if res.status_code == 200: path = Path.cwd() / 'photo' path.mkdir(exist_ok=True) path = path / name path.mkdir(exist_ok=True) with open(path / f'photo_.jpg', 'wb') as pht: pht.write(res.content) else: continue except Exception: continue def save_data(): global all_link with open('links_people.txt', 'w', encoding='utf-8') as file: for lin in all_link: file.write(f'\n') def find_people(tage: int, bage: int, spol: int, pol: int, driver: webdriver) -> None: """ Переход по страницам сайта. Запуск функции поиска страниц. """ num = 0 link_count = 0 while True: try: url = f'https://loveplanet.ru/a-search/d-1/pol-/spol-/tage-/bage-/purp-0/proof-1/country-0/region-0/city-0/p-' driver.get(url) time.sleep(1) count = find_pages(driver.page_source, driver, num) if count == 1: link_count += 1 if link_count >= 2: save_data() break num += 1 except Exception as ex: print(ex) save_data() break print("All pages down") def main() -> None: """ Запрос параметров поиска у пользователя. Проверка полученных параметров. Загрузка просмотренных ссылок и добавление их в множество для будущих проверок. Запуск функции авторизации и перехода по страницам. Если закрыт браузер или выполнено прерывание по "Ctrl + C" сохраняется информация о просмотренных страницах. """ global all_link driver = None try: if Path('links_people.txt').exists(): with open('links_people.txt', 'r', encoding='utf-8') as file: for ln in file.readlines(): all_link.add(ln.strip()) spol = input('Выберите пол для поиска фото:\n [1] Мужчины\n [2] Женщины\n >>> ') if spol not in ["1", "2"]: print('Введите корректный пол!') sys.exit(0) tage = input("Введите возраст до (max=100): ") if not tage.isdigit() or int(tage) > 100: print("Вы ввели не число. Перезапустите программу!") sys.exit(0) bage = input("Введите возраст от (min=18): ") if not bage.isdigit() or int(bage) < 18: print("Вы ввели слишком юный возраст! Перезапустите программу!") sys.exit(0) driver = webdriver.Chrome(options=options, service=Service(log_path=os.devnull, executable_path=exec_path)) driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", < 'source': ''' delete window.cdc_adoQpoasnfa76pfcZLmcfl_Array; delete window.cdc_adoQpoasnfa76pfcZLmcfl_Promise; delete window.cdc_adoQpoasnfa76pfcZLmcfl_Symbol; ''' >) logging(driver) if spol == "1": find_people(int(tage), int(bage), 1, 2, driver) elif spol == "2": find_people(int(tage), int(bage), 2, 1, driver) except KeyboardInterrupt: driver.close() driver.quit() save_data() driver.close() driver.quit() if __name__ == "__main__": main()
А на этом, пожалуй, все.
Спасибо за внимание. Надеюсь, данная информация будет вам полезна
