Selenium найти элемент по имени класса два параметра - PullRequest
0 голосов
/ 08 ноября 2019

Как найти элементы по имени класса, не повторяя вывод? У меня есть два класса, чтобы очистить hdrlnk и results-price. Я написал код так:

x = driver.find_elements_by_class_name(['hdrlnk','result-price'])

, и это дает мне некоторую ошибку. У меня есть другой код, который я попробовал, и вот он:

x = driver.find_elements_by_class_name('hdrlnk'),
y = driver.find_elements_by_class_name('result-price')
for xs in x:
    for ys in y:
        print(xs.text + ys.text)   

Но я получил такой результат

sony 5 disc cd changer$40
sony 5 disc cd changer$70
sony 5 disc cd changer$70
sony 5 disc cd changer$190
sony 5 disc cd changer$190
sony 5 disc cd changer$190
sony 5 disc cd changer$190
sony 5 disc cd changer$10

Часть структуры HTML, которую я пытаюсь очистить

<p class="result-info">
    <span class="icon icon-star" role="button" title="save this post in your favorites list">
        <span class="screen-reader-text">favorite this post</span>
    </span>
    <time class="result-date" datetime="2019-11-07 18:20" title="Thu 07 Nov 06:20:56 PM">Nov  7</time>
    <a href="https://vancouver.craigslist.org/rch/ele/d/chandeliers/7015824686.html" data-id="7015824686" class="result-title hdrlnk">CHANDELIERS</a>
    <span class="result-meta">
        <span class="result-price">$800</span>
        <span class="result-hood"> (Richmond)</span>
        <span class="result-tags">
            <span class="pictag">pic</span>
        </span>
        <span class="banish icon icon-trash" role="button">
            <span class="screen-reader-text">hide this posting</span>
        </span>
        <span class="unbanish icon icon-trash red" role="button" aria-hidden="true"></span>
        <a href="#" class="restore-link">
            <span class="restore-narrow-text">restore</span>
            <span class="restore-wide-text">restore this posting</span>
        </a>
    </span>
</p>

Первый элемент повторяется, но я получил правильное значение для второго. Как мне исправить эту ошибку?

Ответы [ 4 ]

2 голосов
/ 08 ноября 2019

Похоже, у вас есть элементы с классами hdrlnk и result-price, которые идут парами. Таким образом, вам нужно выполнять итерации списков параллельно с zip():

xs = driver.find_elements_by_class_name('hdrlnk'),
ys = driver.find_elements_by_class_name('result-price')
for x, y in zip(xs, ys):
    print(x.text, y.text)

. Это предполагает, что два списка содержат одинаковое количество элементов в правильном порядке, чтобы они правильно совпали с zip(). Вероятно, безопаснее анализировать их непосредственно из HTML, просматривая родительские элементы <p>:

ps = driver.find_elements_by_class_name('result-info')
for p in ps:
    x = p.find_element_by_class_name('hdrlnk'),
    y = p.find_element_by_class_name('result-price')
    print(x.text, y.text)
2 голосов
/ 08 ноября 2019

Я думаю, вам не нужно nested loop, попробуйте итерацию по длине объекта, используйте len метод:

x = driver.find_elements_by_class_name('hdrlnk'),
#y = driver.find_elements_by_class_name('result-price')
y = driver.find_elements_by_xpath('//p[@class="result-info"]/span[@class="result-meta"]//span[@class="result-price"]')

print(len(x))
print(len(y))

for i in range(len(x)) :
    print(x[i].text + y[i].text)

ОБНОВЛЕНИЕ

На самом делеЯ просто представляю, что вы хотите связать элемент x с элементом y, это будет выглядеть так:

x[0] with y[0]
x[1] with y[1]
etc....

Так что я уверен, что у вас одинаковое число от x до y. По этой причине я думаю, что мне просто нужно x для представления loop (хотя вы также можете использовать y вместо этого).

Если вы хотите включить их обоих в loop, вы можете использовать zip. Пожалуйста, учитесь на других ответах в этой теме.

Для xpath вы можете увидеть здесь: Locator Strategies

С копией xpath из проверяющего элемента это дастты абсолютный путь. Я не рекомендую его, потому что он очень уязвим для изменений.

Пожалуйста, просмотрите эту ветку: Absolute vs Relative Xpath

2 голосов
/ 08 ноября 2019

.find_elements_by_class_name() принимает только одно имя класса. Я бы предложил использовать селектор CSS для этой работы, например .hdrlnk .result-price. Код будет выглядеть так:

prices = driver.find_elements_by_css_selector('.hdrlnk .result-price')

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

for heading in driver.find_elements_by_css_selector('.hdrlnk'):
    print(heading.text)
    for price in heading.find_elements_by_xpath('./following::span[@class="result-price"]'):
        print('  ' + price.text)

См. документы для всех опций поиска элементов.

CSSссылки на селекторы:
ссылка на W3C
Советы по Selenium: селекторы CSS
Укрощение расширенных селекторов CSS

0 голосов
/ 08 ноября 2019

Если ваш вариант использования должен использовать find_elements_by _classname(), лучшим подходом было бы заставить WebDriverWait для visibility_of_all_elements_located(), и вы можете использовать любую из следующих стратегий локатора :

  • Использование CLASS_NAME:

    items = WebDriverWait(driver, 20).until(EC.visibility_of_all_elements_located((By.CLASS_NAME, "hdrlnk")))
    prices = WebDriverWait(driver, 20).until(EC.visibility_of_all_elements_located((By.CLASS_NAME, "result-price")))
    for i,j in zip(items, prices):
        print(i.text + j.text)
    

Однако каноническим подходом будет использование любого из следующего:

  • CSS_SELECTOR:

    items = WebDriverWait(driver, 20).until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR, "p.result-info a.hdrlnk")))
    prices = WebDriverWait(driver, 20).until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR, "p.result-info span.result-meta>span.result-price")))
    for i,j in zip(items, prices):
        print(i.text + j.text)
    
  • XPATH:

    items = WebDriverWait(driver, 20).until(EC.visibility_of_all_elements_located((By.XPATH, "//p[@class='result-info']//a[contains(@class, 'hdrlnk')]")))
    items = WebDriverWait(driver, 20).until(EC.visibility_of_all_elements_located((By.XPATH, "//p[@class='result-info']//span[@class='result-meta']/span[@class='result-price']")))
    for i,j in zip(items, prices):
        print(i.text + j.text)
    
  • Примечание : Вы должны добавить следующий импорт:

    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...