如何使用Selenium和Python根据另一个元素中的文本点击正确的链接?
我有一个这样的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 个回答
也许
找到这个元素……找到它的父元素……再找到它下面的标签
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()
当我需要创建一个稍微复杂的自定义XPath时,我有一个步骤流程。我会一步一步地构建XPath,并验证每一步是否返回我想要的元素。我觉得这样比一开始就创建最终的XPath,然后发现它不工作再去排查问题要简单和快速得多。
我们的目标是找到一个包含出生日期(DOB)和我们想要点击的链接(A标签)的表格行(TR)。这样我们就能确保出生日期和链接在同一行里。
我首先找到包含出生日期的TD元素。
//tr/td[text()='17/10/2002']
根据你现有的XPath,看来你已经掌握了这一步。接下来就开始变得有点复杂了。
调整XPath,使其返回TR而不是TD。
//tr[./td[text()='17/10/2002']]
现在我们只需要从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")
我在上面的代码中实施的一些建议...
我把
searched_text_bod
改成了searched_text_dob
,因为dob是出生日期的意思。由于最终的XPath比较短,我把它放进了一个字符串里,而不是之前的多个字符串。如果需要,你可以再把它们分开。
使用
WebDriverWait
时,"存在"意味着元素在DOM中,但不一定可见或可点击。为了点击一个元素,你应该等它可点击,使用EC.element_to_be_clickable()
。其他操作,比如.send_keys()
或.text
,则使用EC.visibility_of_element_located()
。注意:在这种情况下,我使用了可见性,尽管我是在点击一个元素。原因是我需要返回一个元素集合,而不是单个元素。问题是没有类似于
EC.visibility_of_all_elements_located()
的可点击版本,所以我只能退而求其次使用可见性。尽量避免使用
try-except
,因为这会降低代码的执行速度。在这种情况下我们不需要它... 所以我获取了一个集合而不是单个元素。我检查集合是否为空if links:
,如果不为空,就点击第一个元素。