Как очистить данные из произвольного количества списков строк с помощью Python Selenium?

Итак, я пытаюсь создать бота, который идентифицирует списки кредитов NFT по размытию, которые соответствуют определенным критериям, таким как общая стоимость кредита, составляющая 80% или меньше минимальной цены, или APY, превышающая 100%. Я разобрался с основами загрузки Chrome с помощью селена и перехода к нужному разделу веб-сайта для просмотра кредитов на коллекции. Но я изо всех сил пытаюсь извлечь данные из таблицы кредитов. Что мне хотелось бы сделать, так это извлечь таблицу списков кредитов в массив массивов или массив словарей, где каждый массив/словарь содержит данные, представляющие каждое имя, статус, сумму займа, LTV и APY.

Что я работаю до сих пор:

import selenium
from selenium.webdriver.common.by import By
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
import time

path = "/Users/#########/Desktop/chromedriver-mac-arm64/chromedriver"

# Create an instance of ChromeOptions
options = Options()
options.add_experimental_option("detach", True)
options.add_argument("disable-infobars");

# Specify the path to the ChromeDriver
service = Service(path)

# Initialize the WebDriver with the service and options
driver = webdriver.Chrome(service=service, options=options)

# Open Blur beanz collection and navigating to active loans page
driver.maximize_window
driver.get("https://blur.io/eth/collection/beanzofficial/loans")
time.sleep(3)
loan_button = driver.find_element(By.XPATH, "/html/body/div/div/main/div/div[3]/div/div[2]/div[1]/div[1]/nav/button[2]")
loan_button.click()

Честно говоря, я новичок в селене, поэтому просто играл со своей интуицией и чатом, пытаясь решить эту проблему. Лучшее предположение, которое у меня было до сих пор, — это следующий фрагмент кода, который пытался извлечь APY всех кредитов. Это не сработало, так как я уверен, что это была какая-то ошибочная интуиция.

elements = driver.find_elements(By.CSS_SELECTOR, 'Text-sc-m23s7f-0 hAGCAO')


# Initialize an empty list to store the percentage values
percentages = []

# Iterate through each element and extract its text (which contains the percentage)
for element in elements:
    percentage = element.text
    percentages.append(percentage)

# Print the extracted percentage values
print(percentages)

time.sleep(10)
# Close the WebDriver
driver.quit()

Мне также кажется, что это немного сложно: нужно извлекать каждый столбец таблицы, а не каждую строку за раз. Не уверен, что есть более простой способ сделать это, если бы он был, было бы здорово. Если нет, тоже ок!

Похоже, Blur скоро выпустит API - обязательно отправьте форму для регистрации доступа, поскольку использование API всегда НАМНОГО быстрее/проще, чем использование Selenium. Обновлено: я нашел эту форму, щелкнув ссылку «API» внизу домашней страницы Blur.io.

ryyyn 19.06.2024 00:04

@ryyyn О, спасибо, я этого не заметил. Хотя на самом деле я просто пытаюсь реализовать этот проект, чтобы освоиться с селеном и в конечном итоге создать небольшое приложение для своего резюме. Так что, если у вас есть какие-либо советы о том, как заставить это работать с селеном, мы будем очень признательны! еще раз спасибо, ура.

number2patrician 19.06.2024 00:11
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
2
66
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Чтобы получить данные таблицы, я бы проанализировал элемент <script>, где данные хранятся в формате Json:

import json

import pandas as pd
import requests
from bs4 import BeautifulSoup

url = "https://blur.io/"

soup = BeautifulSoup(requests.get(url).content, "html.parser")
data = json.loads(soup.select_one("#__NEXT_DATA__").text)

table = data["props"]["pageProps"]["sections"]["tableCollections"]

for tab, data in zip(table["tabs"], table["data"]):
    df = pd.DataFrame(data)
    del df["iconUrl"]

    values = df.pop("values").apply(pd.Series)
    values.columns = table["headings"][1:]

    df = pd.concat([df, values], axis=1)

    print(tab)
    print(df)
    print()

Распечатки:

Trending
                                                collectionUrl                                         title Floor Price 1D Change 7D Change 1D Volume 7D Volume  Owners  Supply
0                        https://blur.io/collection/lilpudgys                                     LilPudgys        0.67    -12.89    -22.77    149.34    855.78    8269   21663
1                       https://blur.io/collection/degods-eth                                        DeGods        0.77     -8.62    -32.22     49.83    640.14    2006    5679
2                           https://blur.io/collection/clonex                                        CloneX        0.40     -0.12     -4.52     42.39    219.07    9488   19600
3                    https://blur.io/collection/mypethooligan                               My Pet Hooligan        0.34     -4.39    -12.42      9.83     68.65    3528    8888
4              https://blur.io/collection/cryptochasers-robot                           CryptoChasers Robot        0.88      0.00      0.00      0.88      0.88     472     499
5                  https://blur.io/collection/proof-moonbirds                                     Moonbirds        0.38    -10.93    -19.20     17.23     97.76    5797   10000
6            https://blur.io/collection/bored-ape-kennel-club                            BoredApeKennelClub        0.29    -12.28    -20.81     33.17    162.73    5076    9602
7            https://blur.io/collection/influenceth-asteroids                           Influence Asteroids        0.02     55.83    -18.33      1.93      2.77    1936    9666
8    https://blur.io/collection/lacma-cactoid-labs-rotf-vol-1  LACMA Remembrance of Things Future Volume #1        0.30    -24.05    -24.53      0.20      1.15     118     500
9                    https://blur.io/collection/beanzofficial                                         Beanz        0.17    -19.08    -20.61     30.37    153.57    7677   19950
10  https://blur.io/collection/murakami-flowers-2022-official                              Murakami.Flowers        0.15     -0.07      5.57      1.29     11.11    5365   10153
11                   https://blur.io/collection/habbo-avatars                                 Habbo Avatars        0.12     -0.69     -4.17      1.49      8.76    4410   11599
12                      https://blur.io/collection/deadfellaz                                    DeadFellaz        0.07     -0.14     -4.27      0.56      1.98    6413   10000
13                    https://blur.io/collection/trainersgen1              Pixelmon Trainers - Generation 1        0.08    -13.26    -17.59      0.25     11.89    1254    7000
14                https://blur.io/collection/str8fire-og-pass                              STR8FIRE OG PASS        0.05    -14.11     39.15      0.17      3.48     548    1200

Top
                                       collectionUrl                    title Floor Price 1D Change 7D Change 1D Volume 7D Volume  Owners  Supply
0           https://blur.io/collection/pudgypenguins            PudgyPenguins        7.29    -22.60    -28.50    894.49   2565.28    5182    8888
1       https://blur.io/collection/boredapeyachtclub        BoredApeYachtClub        8.89    -12.17    -24.25    680.12   3546.91    5460    9998
2                  https://blur.io/collection/milady                   Milady        4.73     -0.46     15.29    279.38   3113.31    5135    9978
3   https://blur.io/collection/mutant-ape-yacht-club       MutantApeYachtClub        1.47    -13.48    -20.11    219.61   2203.20   11658   19495
4          https://blur.io/collection/remilio-babies  Redacted Remilio Babies        1.28     -9.81      4.56    209.64   1303.70    4610    9998
5               https://blur.io/collection/lilpudgys                LilPudgys        0.67    -12.89    -22.77    149.34    855.78    8269   21663
6                   https://blur.io/collection/azuki                    Azuki        3.20    -10.64    -15.13    128.56   1994.88    4255   10000
7              https://blur.io/collection/degods-eth                   DeGods        0.77     -8.62    -32.22     49.09    640.54    2005    5679
8           https://blur.io/collection/kanpai-pandas            Kanpai Pandas        0.79    -15.17    -16.16     48.26    330.87    3191    7976
9                  https://blur.io/collection/clonex                   CloneX        0.40     -0.12     -4.52     42.39    219.07    9488   19600
10           https://blur.io/collection/pixelmongen1                 Pixelmon        0.44    -10.41     -9.65     37.48    191.28    2599   12566
11  https://blur.io/collection/bored-ape-kennel-club       BoredApeKennelClub        0.29    -12.28    -20.81     33.17    162.73    5076    9602
12                https://blur.io/collection/persona                  Persona        0.22    -11.29    -13.96     30.89    200.20    3222    8875
13            https://blur.io/collection/sappy-seals              Sappy Seals        0.42    -13.36    -18.76     30.79    135.66    1618    9997
14          https://blur.io/collection/beanzofficial                    Beanz        0.17    -19.08    -20.61     30.37    153.57    7677   19950

Как мне тогда получить данные о кредите? Это очень полезно, спасибо!

number2patrician 19.06.2024 00:41

@number2patrician А где находятся данные по кредитам?

Andrej Kesely 19.06.2024 00:43
Blur.io/eth/collection/azuki/loans например, это страница кредита для коллекции адзуки. Мне просто нужен способ получить всю информацию об активных кредитах для этой коллекции и подобных коллекций NFT! еще раз спасибо!
number2patrician 19.06.2024 00:46
Ответ принят как подходящий

Я бы порекомендовал поискать «как найти элементы с помощью Selenium» и немного почитать. Но, возможно, это поможет вам начать...

Ваш XPATH для выбора кнопки «ВСЕ КРЕДИТЫ» — /html/body/div/div/main/div/div[3]/div/div[2]/div[1]/div[1]/nav/button[2] — очевидно, что вы получили его, нажав «Копировать XPATH» в консоли разработчика. Как правило, это не очень хороший подход, потому что если что-то в структуре страницы изменится, ваш код сломается (представьте, что разработчик решает добавить или удалить элемент div в любом месте этой иерархии). Вместо этого попытайтесь найти уникальный способ выбрать элемент, который вряд ли изменится. Выбор по идентификатору (например: driver.find_element(By.ID, "main-menu")) предпочтителен, если это возможно. На этой странице кнопка «ВСЕ КРЕДИТЫ» не имеет идентификатора или уникального имени класса — в этом случае я предпочитаю использовать текст для поиска элемента. Мой рекомендуемый XPATH: //button[.='All Loans']. Этот XPATH означает, что нужно выбрать все элементы <button> в любом месте страницы, строковое содержимое которых равно «Все кредиты». (Обратите внимание, что этот текст, соответствующий регистру, чувствителен к регистру — даже несмотря на то, что текст «ВСЕ КРЕДИТЫ» отображается на странице в верхнем регистре, если вы проверите HTML-код, вы увидите, что фактический текст написан с заглавной буквы).

Чтобы протестировать XPATH в Chrome, откройте средство просмотра HTML (вкладка «Элементы» консоли разработчика) и нажмите CTRL+F, чтобы открыть панель поиска, затем введите свой XPATH (без кавычек). Вы увидите, сколько элементов расположено с помощью XPATH.

Для выбора кредитов вы можете использовать XPATH: //div[@id= 'COLLECTION_MAIN']//div[@role='rowgroup']//div[@role='row']. Сначала он находит <div> с идентификатором «COLLECTION_MAIN» — это центральная область экрана. Затем он находит элемент-потомок div "rowgroup", который содержит займы и, наконец, все сами строки. Вы можете попробовать поиграться с этим XPATH — если вы удалите любой из первых компонентов селектора, это не сработает, поскольку он найдет дополнительные элементы div с ролью «строка».

Затем вы можете перебирать эти строки, чтобы получить любую необходимую информацию.

Собираем это вместе:

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

...

options = Options()
options.add_experimental_option("detach", True)
# disable the message "Chrome being controlled by automated test software"
options.add_experimental_option("excludeSwitches",["enable-automation"])

driver = webdriver.Chrome(service=service, options=options)

# Open Blur beanz collection and navigating to active loans page
driver.maximize_window()  # fixed typo
driver.get("https://blur.io/eth/collection/beanzofficial/loans")
# wait until element is clickable then click it
loans_button = WebDriverWait(driver, 20).until(
    EC.element_to_be_clickable((By.XPATH, "//button[.='All Loans']")))
loans_button.click()

percentages = []

# wait for table to load
WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.XPATH, "//div[@id= 'COLLECTION_MAIN']//div[@role='rowgroup']//div[@role='row']")))

for loan_row in driver.find_elements(By.XPATH, "//div[@id= 'COLLECTION_MAIN']//div[@role='rowgroup']//div[@role='row']"):
   apy = loan_row.find_element(By.XPATH, "div[5]").text # select the 5th column
   percentages.append(apy) # could use float(apy[:-1]) to convert to number

Обновлено: ответ Андрея намного превосходит с точки зрения простоты и скорости - использование Selenium для очистки данных действительно должно быть последним средством.

Для меня это не заполняет массив процентов. Это сработало для вас?

number2patrician 19.06.2024 00:56

хм, да, я проверил это, и у меня это работает... заранее извините за этот вопрос, но вы включили строку для печати percentages? (это не в моем коде). В противном случае выполните отладку вручную. Откройте REPL, вставьте код построчно и посмотрите, какие значения вы получите. Это очень полезно, потому что вы можете попробовать разные селекторы/разные функции гораздо быстрее, чем каждый раз перезапускать скрипт. (И это применимо к любому проекту Python, особенно при работе с чем-то незнакомым, например с исходным веб-кодом, где вам наверняка придется попробовать разные подходы)

ryyyn 19.06.2024 01:05

да, я включил это, ха-ха. Вероятно, я где-то допустил какую-то другую простую ошибку, я посмотрю и попробую ваше предложение. Огромное спасибо за ваши ответы, это очень помогло!

number2patrician 19.06.2024 01:14

Я добавил строки, содержащие путь к драйверу Chrome и service = Service(path) к «...» в вашем коде и печать в конце, но это просто печать пустого массива! не знаю, что мне здесь не хватает ;{

number2patrician 19.06.2024 01:29

Если он не добавляет элементы в массив и не поднимает Exception, это означает, что driver.find_elements(By.XPATH, "//div[@id='COLLECTION_MAIN']//div[@role='rowgroup']//div[@r‌​ole='row']") возвращает пустой массив... вы пробовали запускать его построчно, как я предлагал? Если это работает для вас, но запуск скрипта — нет, возможно, сайт загружается у вас медленнее, и поэтому после нажатия кнопки «ВСЕ КРЕДИТЫ» требуется небольшая задержка; можешь попробовать добавить time.sleep(1)

ryyyn 19.06.2024 03:24

Да, это было именно то, спасибо!

number2patrician 19.06.2024 04:17

Другие вопросы по теме