3 минут чтения
4 сентября 2020 г.
Обрабатываем нажатие кнопки в Selenium
В материале Парсим данные, используя Buetiful Soup и Selenium мы уже рассмотрели, как быть, когда данные на странице динамически подгружаются при скролле страницы. Но бывают ситуации, когда новые данные можно получить, только нажав на кнопку «Показать ещё» — сегодня узнаем, как через Selenium сымитировать нажатие кнопки для полного открытия страницы, соберём идентификаторы пива, оценки к каждому продукту и отправим данные в Clickhouse
Структура страницы
Возьмём случайную пивоварню — у неё 105 чекинов, то есть, отзывов. Страница с чекинами пивоварни показывает не более 25 чекинов и выглядит так:
Если попробуем промотать в самый низ, столкнёмся с той самой кнопкой, мешающей нам взять все 105 за раз:
Мы поступим так: выясним, к какому классу относится элемент кнопки и будем на неё нажимать, пока это возможно. Так как Selenium запускает браузер, следующая кнопка «Показать ещё» может не успеть прогрузиться, поэтому между нажатиями поставим интервал в пару секунд. Как только страница раскроется полностью — мы возьмём её содержимое и распарсим нужные данные из чекинов. Зайдём в код страницы и найдём кнопку — она относится к классу more_checkins.
У кнопки есть свойства стиля, а именно — display. В случае, если кнопка должна отображаться, display принимает значение block. Но когда промотаем страницу до самого конца, кнопку не нужно будет показывать, ведь открывать больше нечего — поэтому display кнопки примет значение none. В случае, если мы запросим у кнопки display и вернётся none будем знать, что открывать больше нечего и можно перестать жать на кнопку.
Пишем код
Начнём с импорта библиотек:
import time
from selenium import webdriver
from bs4 import BeautifulSoup as bs
import re
from datetime import datetime
from clickhouse_driver import Client
Chromedriver, необходимый для запуска браузера через Selenium, можно установить с официальной страницы
Подключимся к базе данных, зададим cookies:
client = Client(host=’ec1-23-456-789-10.us-east-2.compute.amazonaws.com’, user=», password=», port=’9000′, database=»)
count = 0
cookies = {
‘domain’:’untappd.com’,
‘expiry’:1594072726,
‘httpOnly’:True,
‘name’:’untappd_user_v3_e’,
‘path’:’/’,
‘secure’:False,
‘value’:’your_value’
}
О том, как запускать Selenium с cookies можно прочитать в материале «Парсим данные каталога сайта, используя Beautiful Soup и Selenium». Нам нужен параметр untappd_user_v3_e.
Так как мы планируем работать с пивоварнями, у которых более сотни тысяч чекинов, может оказаться так, что страница будет чересчур тяжёлой, и нагрузка на машину будет огромна. Чтобы этого избежать, отключим всё лишнее, а затем подключим cookie для авторизации:
options = webdriver.ChromeOptions()
prefs = {‘profile.default_content_setting_values’: {‘images’: 2,
‘plugins’: 2, ‘fullscreen’: 2}}
options.add_experimental_option(‘prefs’, prefs)
options.add_argument(«start-maximized»)
options.add_argument(«disable-infobars»)
options.add_argument(«—disable-extensions»)
driver = webdriver.Chrome(options=options)
driver.get(‘https://untappd.com/TooSunnyBrewery’)
driver.add_cookie(cookies)
Напишем функцию, которая принимает ссылку, переходит по ней, полностью раскрывает страницу и возвращает нам soup, который можно будет распарсить. Получим display кнопки и запишем в переменную more_checkins: пока он не равен none будем нажимать на кнопку и снова получать её display. Сделаем интервал в две секунды между нажатиями, чтобы подождать прогрузку страницы. Как только будет получена вся страница, переведём её в soup библиотекой bs4.
def get_html_page(url):
driver.get(url)
driver.maximize_window()
more_checkins = driver.execute_script(«var more_checkins=document.getElementsByClassName(‘more_checkins_logged’)[0].style.display;return more_checkins;»)
print(more_checkins)
while more_checkins != «none»:
driver.execute_script(«document.getElementsByClassName(‘more_checkins_logged’)[0].click()»)
time.sleep(2)
more_checkins = driver.execute_script(«var more_checkins=document.getElementsByClassName(‘more_checkins_logged’)[0].style.display;return more_checkins;»)
print(more_checkins)
source_data = driver.page_source
soup = bs(source_data, ‘lxml’)
return soup
Напишем следующую функцию: она тоже будет принимать url страницы, передавать его в get_html_page, получать soup и парсить его. Функция вернёт запакованные списки с идентификатором пива и оценкой к нему.
О том, как парсить элементы страницы мы уже говорили в материале «Парсим данные каталога сайта, используя Beautiful Soup».
def parse_html_page(url):
soup = get_html_page(url)
brewery_id = soup.find_all(‘a’, {‘class’:’label’,
‘href’:re.compile(‘https://untappd.com/brewery/*’)})[0][‘href’][28:]
items = soup.find_all(‘div’, {‘class’:’item’,
‘id’:re.compile(‘checkin_*’)})
checkin_rating_list = []
beer_id_list = []
count = 0
print(‘Заполняю списки’)
for checkin in items:
print(count, ‘/’, len(items))
try:
checkin_rating_list.append(float(checkin.find(‘div’, {‘class’:’caps’})[‘data-rating’]))
except Exception:
checkin_rating_list.append(‘cast(Null as Nullable(Float32))’)
try:
beer_id_list.append(int(checkin.find(‘a’, {‘class’:’label’})[‘href’][-7:]))
except Exception:
beer_id_list.append(‘cast(Null as Nullable(UInt64))’)
count += 1
return zip(checkin_rating_list, beer_id_list)
Наконец, напишем вызов функций по пивоварням. В материале «Использование словарей в Clickhouse на примере данных Untappd» мы уже рассмотрели, как получить список идентификаторов российских пивоварен — обратимся к нему через таблицу в Clickhouse
brewery_list = client.execute(‘SELECT brewery_id FROM brewery_info’)
Если посмотрим на brewery_list, то узнаем, что данные вернулись в неудобном формате: это список кортежей.
Небольшое лямбда-выражение позволит его «выпрямить»:
flatten = lambda lst: [item for sublist in lst for item in sublist]
brewery_list = flatten(brewery_list)
Работать с таким списком значительно комфортнее:
Для каждой пивоварни в списке сформируем url — он состоит из стандартной ссылки и идентификатора пивоварни в конце. Отправим url в функцию parse_html_page, которая сама вызовет get_html_page и вернёт списки с beer_id и rating_score. Так как два списка вернутся упакованными можем пройти по ним итератором, сформировав кортеж и отправив его в Clickhouse.
for brewery_id in brewery_list:
print(‘Беру пивоварню с id’, brewery_id, count, ‘/’, len(brewery_list))
url = ‘https://untappd.com/brewery/’ + str(brewery_id)
returned_checkins = parse_html_page(url)
for rating, beer_id in returned_checkins:
tuple_to_insert = (rating, beer_id)
try:
client.execute(f’INSERT INTO beer_reviews VALUES {tuple_to_insert}’)
except errors.ServerException as E:
print(E)
count += 1
С кнопками на этом всё. Постепенно мы формируем отличный датасет для последующего анализа, который рассмотрим в следующем цикле статей, как только завершим сбор данных — возможно, через месяц.
[ Рекомендации ]
Читайте также
[ Связаться ]
Давайте раскроем потенциал вашего бизнеса вместе
Заполните форму на бесплатную консультацию