使用XPATH语句定位动态生成的网页元素后出现的错误

0 投票
1 回答
61 浏览
提问于 2025-04-14 18:33

正如标题所说,我在用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元素 诊断1的DOM表示 上面图片的XPATH从检查器中复制过来是://*[@id="919e06c4ea7e2a5bb720134d693a8671"]/div[2]/div[1]/div[2]/div/form/div/div/div[10]/div[2]/input

诊断2的DOM表示 上面图片的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 个回答

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...”

撰写回答