如何使用Selenium和Python根据另一个元素中的文本点击正确的链接?

0 投票
2 回答
34 浏览
提问于 2025-04-13 00:11

我有一个这样的HTML结构

<tbody>
    <tr role="row" class="odd">
        <td class="text-center dtr-control"></td>
        <td class="text-center">
            <a href="#" class="px-2 text-dark" onclick="bookPatient('1351','')">
                <i class="fa-solid fa-pen-to-square cursor-pointer fa-lg"></i>
                <i class="fa-solid fa-pen-to-square cursor-pointer fa-lg"></i>
            </a>
        </td>
        <td>Dedeh</td>
        <td class="text-center">Female</td>
        <td class="text-center">07/02/1983</td>
        <td class style>PT MAJU JAYA</td>
    </tr>
    <tr role="row" class="odd">
        <td class="text-center dtr-control"></td>
        <td class="text-center">
            <a href="#" class="px-2 text-dark" onclick="bookPatient('1352','')">
                <i class="fa-solid fa-pen-to-square cursor-pointer fa-lg"></i>
                <i class="fa-solid fa-pen-to-square cursor-pointer fa-lg"></i>
            </a>
        </td>
        <td>Mira</td>
        <td class="text-center">Female</td>
        <td class="text-center">17/10/2002</td>
        <td class style>PT MAJU JAYA</td>
    </tr>
</tbody>

我希望Selenium在点击这个<a>元素之前,先检查一下是否有对应的searched_text_bod值。当我用这段代码尝试时,输出结果并不总是能找到<a>元素在<td>里面。

这个网站的元素上没有类名或ID,所以我遇到了困难。

searched_text_bod = "20/03/1990"

# Improved XPath targeting based on confirmed structure
base_xpath = "//tbody/tr[@role='row']"
patient_row_xpath = f"{base_xpath}/td[text()='{searched_text_bod}']"

try:
  # Find patient row containing the exact date of birth
  patient_link = WebDriverWait(driver, 10).until(
      EC.presence_of_element_located((By.XPATH, patient_row_xpath)))

  edit_patient_info = patient_link.find_element(By.XPATH,
                                                "/following-sibling::td/a")

  if patient_link:
    print(f"Found patient with date of birth: {searched_text_bod}")
    edit_patient_info.click(
    )  # Click on the 'a' element (assuming it's the link)

  else:
    print(
        f"Patient with date of birth '{searched_text_bod}' not found using DoB search"
    )

2 个回答

0

也许

找到这个元素……找到它的父元素……再找到它下面的标签

element = driver.find_element(By.XPATH, "//*[contains(text(), '20/03/1990')]") 
# use any fool proof way of arriving at correct element containing the date

parent=element.find_element(By.XPATH, "./ancestor::tr") 

atag=parent.find_element(By.XPATH,"//a[@onclick='bookPatient']")
atag.click()
0

当我需要创建一个稍微复杂的自定义XPath时,我有一个步骤流程。我会一步一步地构建XPath,并验证每一步是否返回我想要的元素。我觉得这样比一开始就创建最终的XPath,然后发现它不工作再去排查问题要简单和快速得多。

我们的目标是找到一个包含出生日期(DOB)和我们想要点击的链接(A标签)的表格行(TR)。这样我们就能确保出生日期和链接在同一行里。

  1. 我首先找到包含出生日期的TD元素。

    //tr/td[text()='17/10/2002']
    

    根据你现有的XPath,看来你已经掌握了这一步。接下来就开始变得有点复杂了。

  2. 调整XPath,使其返回TR而不是TD。

    //tr[./td[text()='17/10/2002']]
    
  3. 现在我们只需要从TR中找到A标签。

    //tr[./td[text()='17/10/2002']]/td/a
    

如果你还没有这样做,建议使用浏览器的开发者工具控制台来测试你的定位器。使用 $x() 来处理XPath,使用 $$() 来处理CSS选择器。最终的XPath会是:

$x("//tr[./td[text()='17/10/2002']]/td/a")

关于Chrome开发者工具的更多信息,可以查看 文档

接下来,我们可以更新代码...

wait = WebDriverWait(driver, 10)
searched_text_dob = "17/10/2002"

links = wait.until(EC.visibility_of_all_elements_located((By.XPATH, f"//tr[./td[text()='{searched_text_dob}']]/td/a")))
if links:
    links[0].click()
else:
    print(f"Patient with date of birth '{searched_text_dob}' not found using DoB search")

我在上面的代码中实施的一些建议...

  1. 我把 searched_text_bod 改成了 searched_text_dob,因为dob是出生日期的意思。

  2. 由于最终的XPath比较短,我把它放进了一个字符串里,而不是之前的多个字符串。如果需要,你可以再把它们分开。

  3. 使用 WebDriverWait 时,"存在"意味着元素在DOM中,但不一定可见或可点击。为了点击一个元素,你应该等它可点击,使用 EC.element_to_be_clickable()。其他操作,比如 .send_keys().text,则使用 EC.visibility_of_element_located()

    注意:在这种情况下,我使用了可见性,尽管我是在点击一个元素。原因是我需要返回一个元素集合,而不是单个元素。问题是没有类似于 EC.visibility_of_all_elements_located() 的可点击版本,所以我只能退而求其次使用可见性。

  4. 尽量避免使用 try-except,因为这会降低代码的执行速度。在这种情况下我们不需要它... 所以我获取了一个集合而不是单个元素。我检查集合是否为空 if links:,如果不为空,就点击第一个元素。

撰写回答