使用XPATH语句定位动态生成的网页元素后出现的错误
正如标题所说,我在用XPATH语句定位网页元素时遇到了麻烦。我的程序刚启动时,脚本可以处理数百条记录,这些信息是从一个单独的文件中获取的。问题出现在DOM结构似乎发生了变化,这导致了错误的发生。这样一来,selenium的WebDriver就会重新定位到程序中之前引用的一个不想要的元素。
为了提供更多信息,元素是通过以下代码片段用XPATH定位的。
def diagnosis(self, driver, patient):
try:
wait = WebDriverWait(driver,10)
valid_diagnoses = [dx for dx in patient.diagnosis if dx and len(str(dx)) < 1000 and not re.search(r"\bnan\b",str(dx))]
xpath_id = [7, 10, 13, 16, 19, 22, 25]
count = 0
diagnosis_index = 0
while count < len(valid_diagnoses)/2:
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button.btn.btn-sm.btn-secondary.font-medium.text-sm.text-gray-700"))).click()
time.sleep(2)
try:
diagnosis_field = None
diagnosis_field = wait.until(EC.visibility_of_element_located((By.XPATH, f'//*[@id="919e06c4ea7e2a5bb720134d693a8671"]/div[2]/div[1]/div[2]/div/form/div/div/div[{xpath_id[count]}]//input[not(@disabled)]')))
text = valid_diagnoses[diagnosis_index].strip()
diagnosis_field.send_keys(text)
wait.until(EC.text_to_be_present_in_element_value((By.XPATH, f'//*[@id="919e06c4ea7e2a5bb720134d693a8671"]/div[2]/div[1]/div[2]/div/form/div/div/div[{xpath_id[count]}]//input[not(@disabled)]'), text))
except:
print(f'An error related to the patient\'s diagnosis being entered is occurring. Program will wait 100 seconds, inspect the HTML')
time.sleep(100)
patient.dx_issue = True
diagnosis_index += 2
count += 1
except TimeoutError:
print("Timed out while completing the diagnosis process in Webdriver.py")
正在定位的DOM元素
上面图片的XPATH从检查器中复制过来是:
//*[@id="919e06c4ea7e2a5bb720134d693a8671"]/div[2]/div[1]/div[2]/div/form/div/div/div[10]/div[2]/input
上面图片的XPATH从检查器中复制过来是:
//*[@id="919e06c4ea7e2a5bb720134d693a8671"]/div[2]/div[1]/div[2]/div/form/div/div/div[10]/div[2]/input
提供更多背景信息
我尝试了不同类型的选择器,遍历了不同的CSS选择器和XPATH语句,最终发现XPATH最适合我的需求。最开始我使用的是
//*[@id="919e06c4ea7e2a5bb720134d693a8671"]/div[2]/div[1]/div[2]/div/form/div/div/div[{xpath_id[count]}]/div[1]/input
然后我把它修改成了
//*[@id="919e06c4ea7e2a5bb720134d693a8671"]/div[2]/div[1]/div[2]/div/form/div/div/div[{xpath_id[count]}]//input[not(@disabled)]
我发现第二种方法更可靠地定位了WebElement,因为可能会有我在第一条语句中没有考虑到的DOM变化。这种方法证明更具韧性,符合我的需求,因为它已经能够处理数百条记录。
我可能忽视的一个问题是Selenium在长时间运行WebDriver时的限制。我对selenium还比较陌生,所以不太了解程序在长时间运行后会遇到的限制,尤其是当处理数百条每条都有独特的办公室访问细节时。
参考资料
如果有人能提供更多见解来帮助我解决这个问题,我将非常感激。谢谢!
附加信息
- 谷歌浏览器版本 122.0.6261.95(官方版本)(64位)
- Windows 11 家庭版
- selenium 4.15.2
编辑
附上了HTML页面以便更深入了解DOM的结构
1 个回答
下面是你需要的INPUT相关的HTML代码。我把一些不相关的元素和属性剪掉了,这样更容易阅读。
<div class="col-span-6">
<label class="..."> Diagnosis 2: </label>
...
<div>
<input class="..." wire:model.debounce.500ms="search_diagnoses.1" type="text" placeholder="Search diagnosis...">
...
</div>
</div>
下面的定位器可以唯一地识别上面的INPUT。
//label[contains(text(),'Diagnosis 2:')]/following-sibling::div/input[@placeholder='Search diagnosis...']
语法 | 意思 |
---|---|
//label[contains(text(),'Diagnosis 2:')] | 一个包含文本“Diagnosis 2:”的LABEL标签 |
/following-sibling::div | 一个与上面的LABEL标签同级的DIV标签 |
/input[@placeholder='Search diagnosis...'] | 上面LABEL标签的一个子INPUT,包含一个属性placeholder ,其值为“Search diagnosis...” |