подсчет количества экземпляров определенного класса и получение значений через Selenium

#python #selenium #xpath #web-scraping #webdriverwait

#python #selenium #xpath #веб-очистка #webdriverwait

Вопрос:

Я пытаюсь очистить данные с этого веб-сайта.

Более конкретно, я хочу, чтобы мой скрипт подсчитывал количество строк в таблице и извлекал номер посещаемости из каждой строки (см. Изображение, прикрепленное ниже).введите описание изображения здесь

Просматривая веб-сайт, я вижу следующее для даты в первой строке (1 декабря):

 <td ng-repeat="(k,h) in sec.headers track by $index" class="date ng-scope" data-high="false" data-hidden="false" 
ng-style="{'text-align':h.properties.align}" ng-bind-html="vals | getColData:[k]:language:seasonId" 
compile-table-col="" style="text-align: left;"><span>Dec. 1</span></td>
 

Затем я вижу блок кода для подсчета количества пользователей в первой строке (872)

 <td ng-repeat="(k,h) in sec.headers track by $index" class="attendance ng-scope" data-high="false" 
data-hidden="false" ng-style="{'text-align':h.properties.align}" ng-bind-html="vals | getColData:[k]:language:seasonId" 
compile-table-col="" style="text-align: right;"><span>872</span></td>
 

Я пробовал несколько версий driver.find_elements_by_class_name , таких как

 elements = driver.find_elements_by_class_name("date ng-scope") 
 

и

 driver.find_elements_by_xpath("//td[@class='date ng-scope']")))
 

К сожалению, ни одно из них не сработало.

Может ли кто-нибудь указать мне правильное направление? Если бы кто-нибудь мог дать совет о том, как правильно подсчитать количество строк, подсчитав количество экземпляров 'date ng-scope' и извлекая соответствующие подсчеты толпы.

Комментарии:

1. Вам на 100% нужно, чтобы все было сделано в selenium? BeautifulSoup или даже pandas_html может быть проще.

2. @CeliusStingher Нет, но меня как бы подтолкнули к использованию Selenium, потому что мне нужно было выбирать параметры в выпадающих меню и нажимать кнопки. Я бы хотел использовать BeautifulSoup, но мне нужно было бы иметь возможность обновлять адрес после выбора соответствующих пунктов выпадающего меню.

Ответ №1:

Поскольку это таблица, ее довольно легко достичь, так как все, что вам нужно делать, это постоянно увеличивать значение таблицы на 1. Вот как я это сделал:

 from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from time import sleep, strftime

url = "https://www.ushl.com/view#/schedule/24/67/12/home?league=1amp;gametype=-1"

webdriver = webdriver.Chrome()
webdriver.get(url)

x = 0
i = 2

while x == 0:
    try:
        date = webdriver.find_element_by_xpath(f"/html/body/div[5]/div[1]/div[4]/div[2]/div[1]/div/div[3]/div/div/div/div/div/div/ng-view/div[2]/div[3]/div[1]/table/tbody/tr[{i}]/td[1]/span").text
        attendance = webdriver.find_elements_by_xpath(f"/html/body/div[5]/div[1]/div[4]/div[2]/div[1]/div/div[3]/div/div/div/div/div/div/ng-view/div[2]/div[3]/div[1]/table/tbody/tr[{i}]/td[8]/span")[0].text

        print(f"Attendance Of {attendance} On Date {date}")
        i  = 1
    except:
        x = 1
        break
 

Позвольте мне объяснить:

Строка 1-3 импортирует необходимые модули, такие как selenium.

Строка 4 устанавливает URL в строку.

Строка 5 определяет webdriver как Chrome.

Строка 6 использует Chrome для открытия URL-адреса, который мы определили ранее.

Строка 7 определяет x как 0. Позже нам нужно, чтобы x было равно 0 для цикла while.

Строка 8 определяет i как 2, который нам понадобится для таблицы позже.

Строка 9 инициирует цикл while, который будет выполняться до тех пор, пока x равно 0, значение которого мы установили ранее.

Строка 10 запускает команду try . Позже вы поймете, зачем нам это нужно.

Строка 11 устанавливает дату в текст переменной xpath. Я уже использовал html раньше и поэтому примерно знаю, как работает табличная система. tr означает строку таблицы. Первая дата, 1 декабря, — это строка таблицы 2. Ранее мы установили i равным 2, поэтому мы можем использовать tr[{i}] для представления 2 .

Строка 12 делает то же самое, но для посещаемости, по-прежнему используя i, поскольку это таблица. Я добавил [0] в конце, потому что xpath для посещаемости был списком. Хотя я почти уверен, что списка нет, selenium все равно так думал, поэтому я решил использовать [0] для получения первого элемента списка. Нет второго или третьего элемента, поэтому [1] или [2] не будут работать.

Строка 13 выводит информацию для пользователя. Строка 14 увеличивает i на 1, потому что в следующем цикле нам нужно получить доступ к 3-й строке таблицы, поэтому i = 1 устанавливает i равным 3.

Мы продолжаем выполнять это до тех пор, пока не останется больше строк таблицы. Когда это происходит, мы используем команду try в строке 15, чтобы прервать цикл while.

Комментарии:

1. Спасибо. это действительно работает, но не могли бы вы объяснить синтаксис и мыслительный процесс? особенно за div[i] . Мне трудно понять, что происходит.

2. Я надеюсь, что это поможет

3. Я думаю, что я почти на месте. В основном мне было трудно понять, как вы получили все эти div [i], и я вижу, что вы «скопировали полный Xpath». Однако, как вы узнали, что вам нужно добавить /span в обе строки? Кроме того, вы сказали, что знали, что вам нужно добавить [0] для посещаемости, потому что xpath для attendendance — это список. Не могли бы вы подробнее остановиться на этом? Я попробовал [1] или разные числа, чтобы посмотреть, что я получу, и я узнал, что [0] это приводит только к тому, что что-либо печатается.

4. Извините, я понял, что я делал «копировать полный Xpath» на одну строку выше, где я должен был. Я до сих пор не понимаю, откуда вы знаете, что вы должны были [0]. указать, что я даже не могу attendance = webdriver.find_elements_by_xpath(f"/html/body/div[5]/div[1]/div[4]/div[2]/div[1]/div/div[3]/div/div/div/div/div/div/ng view/div[2]/div[3]/div[1]/table/tbody/tr[{i}]/td[8]/span").text распечатать, чтобы увидеть, что это список, я бы не догадался о решении.

5. Это помогает?

Ответ №2:

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

 driver.findElements("//div[contains(@class,'table-container')]//tr") 
 

вернет список элементов, а при получении размера этого списка вы получите количество строк (сюда входит строка заголовка, поэтому, если вы хотите, чтобы фактическое количество игр вычло 1). Переведенное выражение xpath выглядит следующим образом: «найдите любой элемент div, где имя класса содержит строку «table-container» и ниже по потоку любые элементы tr»

Поле посещаемости можно найти с помощью этого xpath:

 //div[contains(@class,'table-container')]//tr[2]/td[contains(@class,'attendance')]/span
 

где tr[2] означает вторую строку. Программно сделайте это «[2]» переменной и замените индекс цикла на 2 и выполните итерацию по количеству строк.

Ответ №3:

Используйте WebDriverWait() и ждите visibility_of_all_elements_located() и используйте следующее css selector , чтобы определить количество строк, а затем выполнить итерацию и найти соответствующие столбцы.

 driver.get("https://www.ushl.com/view#/schedule/24/67/12/home?league=1amp;gametype=-1")
totalnoofrows=WebDriverWait(driver, 10).until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR, ".resp >.ht-table >tbody >tr")))
for row in totalnoofrows[1:]:
    print("Date :"   row.find_element_by_xpath("./td[1]").text)
    print("Crowd :"   row.find_element_by_xpath("./td[8]").text)
    print("==============================================")
 

Вам необходимо импортировать следующие библиотеки.

 from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
 

Вывод на консоль:

 Date :Dec. 1
Crowd :872
==============================================
Date :Dec. 14
Crowd :816
==============================================
Date :Dec. 15
Crowd :1065
==============================================
Date :Dec. 16
Crowd :497
=============================================