Selenium爬取卫福署医院查询站遇NoSuchElementException问题求助
问题解决:Selenium爬取医院查询网站元素定位失败
以下是针对你遇到的NoSuchElementException错误的具体解决方案:
1. 排查验证码识别有效性
验证码识别错误会导致搜索后无结果页面,自然找不到目标元素。添加结果校验逻辑:
# 点击搜索后,先检查是否无结果 try: no_result = WebDriverWait(browser, 10).until( EC.presence_of_element_located((By.XPATH, '//*[contains(text(), "查無資料")]')) ) print(f"第{i}条:{df['New_Name'][i]} 无匹配结果") code_list.append("无结果") name_list.append(df['New_Name'][i]) address_list.append("无结果") browser.quit() continue except: pass
2. 替换动态ID为稳定定位策略
目标元素的ID包含动态后缀ctl02,会随结果行数或页面渲染变化,改用基于表格结构的定位:
# 等待结果表格加载,定位第一行的详情链接 WebDriverWait(browser, 20).until( EC.presence_of_element_located((By.ID, 'ctl00_ContentPlaceHolder1_gviewMain')) ) # 定位结果表格第二行(第一行是表头)的第一个链接 detail = WebDriverWait(browser, 20).until( EC.element_to_be_clickable((By.XPATH, '//table[@id="ctl00_ContentPlaceHolder1_gviewMain"]//tr[2]//a')) ) detail.click()
如果需要匹配医院名称,也可以用文本包含定位:
detail = WebDriverWait(browser, 20).until( EC.element_to_be_clickable((By.XPATH, f'//a[contains(text(), "{df["New_Name"][i]}")]')) )
3. 修复Headless模式渲染问题
Headless模式下页面渲染可能不全,添加窗口大小和反检测参数:
chrome_options = Options() chrome_options.add_argument("--headless") chrome_options.add_argument('--no-sandbox') # 添加窗口大小参数,确保页面完整渲染 chrome_options.add_argument("--window-size=1920,1080") # 反自动化检测 chrome_options.add_argument("--disable-blink-features=AutomationControlled") chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"]) chrome_options.add_experimental_option('useAutomationExtension', False)
4. 优化验证码截图逻辑
避免因屏幕缩放导致的坐标偏移,直接截取验证码元素:
# 直接截取验证码元素,无需整个页面截图 element = browser.find_element(By.ID, 'ctl00_ContentPlaceHolder1_ImageCheck') element.screenshot(f'C:/Users/jlee72/Desktop/Hos/selenium + captcha/{i}.jpg')
5. 优化等待逻辑,移除固定sleep
替换time.sleep(10)为显式等待,确保元素加载完成后再操作:
# 等待搜索按钮点击后结果表格出现 WebDriverWait(browser, 20).until( EC.presence_of_element_located((By.ID, 'ctl00_ContentPlaceHolder1_gviewMain')) ) # 再等待详情链接可点击 detail = WebDriverWait(browser, 20).until( EC.element_to_be_clickable((By.XPATH, '//table[@id="ctl00_ContentPlaceHolder1_gviewMain"]//tr[2]//a')) ) detail.click()
修改后的完整代码片段
from selenium import webdriver import time from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC import ddddocr from selenium.webdriver.chrome.options import Options import pandas as pd df = pd.read_csv('hos.csv') code_list = [] name_list = [] address_list = [] for i in range(len(df)): chrome_options = Options() chrome_options.add_argument("--headless") chrome_options.add_argument('--no-sandbox') chrome_options.add_argument("--window-size=1920,1080") chrome_options.add_argument("--disable-blink-features=AutomationControlled") chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"]) chrome_options.add_experimental_option('useAutomationExtension', False) browser = webdriver.Chrome(options=chrome_options) browser.get('https://ma.mohw.gov.tw/masearch/') # 截取验证码元素 element = browser.find_element(By.ID, 'ctl00_ContentPlaceHolder1_ImageCheck') element.screenshot(f'C:/Users/jlee72/Desktop/Hos/selenium + captcha/{i}.jpg') print(f'已保存验证码截图:{i}.jpg') # 识别验证码 ocr = ddddocr.DdddOcr() with open(f'C:/Users/jlee72/Desktop/Hos/selenium + captcha/{i}.jpg', 'rb') as f: img_bytes = f.read() res = ocr.classification(img_bytes) print(f'验证码识别结果:{res}') try: # 输入医院名称 Institution_name = browser.find_element(By.ID, 'ctl00_ContentPlaceHolder1_txtBAS_NAME') Institution_name.send_keys(df['New_Name'][i]) # 输入验证码 Institution_code = browser.find_element(By.ID, 'ctl00_ContentPlaceHolder1_TextBox1') Institution_code.send_keys(res) # 点击搜索 login = browser.find_element(By.ID, 'ctl00_ContentPlaceHolder1_btnSearch') login.click() # 检查是否无结果 try: no_result = WebDriverWait(browser, 10).until( EC.presence_of_element_located((By.XPATH, '//*[contains(text(), "查無資料")]')) ) print(f"第{i}条:{df['New_Name'][i]} 无匹配结果") code_list.append("无结果") name_list.append(df['New_Name'][i]) address_list.append("无结果") browser.quit() continue except: pass # 等待结果表格加载,定位详情链接 WebDriverWait(browser, 20).until( EC.presence_of_element_located((By.ID, 'ctl00_ContentPlaceHolder1_gviewMain')) ) detail = WebDriverWait(browser, 20).until( EC.element_to_be_clickable((By.XPATH, '//table[@id="ctl00_ContentPlaceHolder1_gviewMain"]//tr[2]//a')) ) detail.click() # 后续获取编码和地址的逻辑 hos_code = WebDriverWait(browser, 20).until( EC.presence_of_element_located((By.XPATH, '//*[@id="ctl00_ContentPlaceHolder1_lblBAS_ID"]')) ).text hos_address = WebDriverWait(browser, 20).until( EC.presence_of_element_located((By.XPATH, '//*[@id="ctl00_ContentPlaceHolder1_lblBAS_ADDR"]')) ).text code_list.append(hos_code) name_list.append(df['New_Name'][i]) address_list.append(hos_address) except Exception as e: print(f"第{i}条处理失败:{str(e)}") code_list.append("处理失败") name_list.append(df['New_Name'][i]) address_list.append("处理失败") finally: browser.quit() # 保存结果 result_df = pd.DataFrame({ '医院名称': name_list, '医院编码': code_list, '医院地址': address_list }) result_df.to_csv('hos_result.csv', index=False, encoding='utf-8-sig')
内容的提问来源于stack exchange,提问作者Duh
相关产品推荐
相关产品推荐

