Selenium-文本属性仅在调试器检查后才可用

时间:2019-06-21 11:19:21

标签: python-3.x selenium xpath css-selectors webdriverwait

我正在基于Selenium的Python 3网络抓取工具中应对意外行为,并想了解发生了什么事情:

我正在解析具有工作机会的网站。初步搜索后,我得到1到n个结果位点。这个网站的数量在第一页上显示为“ m-pagination__meta”元素的文本部分,并以德语显示。 “ 1 von 48”。我需要此字符串以进行进一步处理。它在网站上,不是iframe的一部分。

Sample link of job website

HTML:

<div class="m-pagination">
  <div class="m-pagination__inner m-pagination__inner--borderBottom">
    <button class="m-pagination__button m-pagination__button--disabled" data-page="" data-event-action="click: pagination-first">
      <svg viewBox="0 0 17 17" width="0" height="0" class="m-icon m-icon--large ">
        <g fill="none" stroke="currentColor" stroke-width=".7" stroke-linecap="round" stroke-linejoin="round">
          <path d="M9 13.2L4.2 8.5 9 3.8"></path>
          <path d="M12.8 13.2L8 8.5l4.7-4.7"></path>
        </g>
      </svg>
    </button>
    <button class="m-pagination__button m-pagination__button--previous m-pagination__button--disabled" data-page="false" data-event-action="click: pagination-previous">
      <svg viewBox="0 0 17 17" width="0" height="0" class="m-icon m-icon--large ">
        <path fill="none" stroke="currentColor" stroke-width=".8" stroke-linecap="round" stroke-linejoin="round" d="M10.9 3.8L6 8.6l4.7 4.6"></path>
      </svg>
    </button>
    <span class="m-pagination__meta" data-number="1"> 1 von 43 </span> 
    <button class="m-pagination__button m-pagination__button--next m-pagination__button--available" data-page="2" data-event-action="click: pagination-next">
      <svg viewBox="0 0 17 17" width="0" height="0" class="m-icon m-icon--large ">
        <path fill="none" stroke="currentColor" stroke-width=".7" stroke-linecap="round" stroke-linejoin="round" d="M6.1 3.8L11 8.6l-4.7 4.6"></path>
      </svg>
    </button>
  </div>
</div>

现在出现了一个奇怪的部分::当我调试程序并尝试使用“ m-pagination__meta”直接访问字符串元素时,它会返回一个空字符串。

但是,当我访问母元素对象m-pagination__meta并使用调试器对其进行检查时,向下滚动到text属性,期望的字符串是“ 1 von 48”。检查之后,我可以访问带有预期结果的“ m-pagination__meta” .text。

此行为似乎与计时无关。我试图用类似的代码等待必需元素的出现

wait = WebDriverWait(self.driver, 10)
wait.until(EC.text_to_be_present_in_element((By.CLASS_NAME,"m-pagination__meta"), "1 von 48"))
pagesTotal = int(self.driver.find_element_by_class_name("m-pagination__meta").text.split(" ")[2])

无济于事(当然,当我不知道会产生哪个字符串,但又不知道如何编码时,我意识到搜索特定字符串是愚蠢的。)

我还尝试了使用睡眠的“正常”等待,但似乎没有任何效果,只有调试器中提到的检查才对生产有用。

我真的很想了解这里发生的事情。

3 个答案:

答案 0 :(得分:3)

存在vertical scroll bar,该页面将页面分为两部分。但是,您需要先找到左侧滚动条元素,然后再进行location_once_scrolled_into_view。一旦到达,您就可以识别出该元素了在。

尝试以下代码。

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

driver=webdriver.Chrome()
driver.get('https://www.karriere.at/jobs/programmierer/wien')
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//div[@class='c-jobsSearch__listing']"))).location_once_scrolled_into_view
print(driver.find_element_by_xpath("//span[@class='m-pagination__meta']").get_attribute('innerText'))

答案 1 :(得分:1)

问题可能是由于页面加载时元素出现在HTML源中,但是JavaScript填充了幕后的值。

您可以在XPath中使用正则表达式根据模式匹配文本:

xpath = '//*[contains(@class, "m-pagination__meta") and matches(normalize-space(text()), "\d+ von \d+")]'
wait = WebDriverWait(self.driver, 30)
wait.until(EC.element_to_be_present(By.XPATH, xpath))

注意:为了安全起见,也许将等待时间也增加到30秒。

答案 2 :(得分:0)

您似乎与 WebDriverWait 非常接近。但不幸的是,该元素位于DOM Tree的下方,而不位于Viewport中。因此,将返回空字符串


解决方案

解决方案是使用 EC <在HTML DOM可见元素,在视口scroll()元素/ em>作为visibility_of_element_located(),然后您可以尝试提取所需的文本,并且可以使用以下任一Locator Strategies

  • 使用CSS_SELECTOR

    driver.execute_script("return arguments[0].scrollIntoView(true);", WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.CSS_SELECTOR, "span.m-pagination__meta"))))
    print(driver.find_element_by_css_selector("span.m-pagination__meta").get_attribute("innerHTML"))
    
  • 使用XPATH

    driver.execute_script("return arguments[0].scrollIntoView(true);", WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, "//span[@class='m-pagination__meta']"))))
    print(driver.find_element_by_xpath("//span[@class='m-pagination__meta']").get_attribute("innerHTML"))
    
  • 注意:您必须添加以下导入:

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