DrissionPage

✨️ 概述

DrissionPage® 是一个基于 Python 的网页自动化工具。

既能控制浏览器,也能收发数据包,还能把两者合而为一。

可兼顾浏览器自动化的便利性和 requests 的高效率。

功能强大,语法简洁优雅,代码量少,对新手友好。

控制浏览器

电脑必须安装谷歌浏览器,或者chrome内核浏览器:比如edge,qq浏览器等(dp版本大于4.1)#从dp库导入chromium

 from DrissionPage import Chromium
 #连接浏览器并创建浏览器对象
 browser = Chromium()
 #通过浏览器对象创建一个新标签页,新标签页访问百度网址
 tab = browser.new_tab('https://www.baidu.com')

启动浏览器前的配置

此案例有权限问题无法修改浏览器路径

 #从dp库导入chromium
 from DrissionPage import Chromium
 #ChromiumOptions 类专门用于配置启动浏览器之前的参数
 from DrissionPage import ChromiumOptions
 ​
 ​
 #创建浏览器启动配置对象
 options = ChromiumOptions()
 #配置浏览器启动的选项
 #设置浏览器路径
 options.set_browser_path(r'"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"')
 #忽略证书错误 比如https 没有s 谷歌浏览器会报错 加上这个可以忽略掉此错误
 options.ignore_certificate_errors
 #禁用图片
 options.no_imgs()
 #无头模式
 options.headless(False)
 #设置浏览器debug端口  比如我想从其他调试浏览器端口进入 
 #options.set_local_port(9696)
 # 设置启动时最大化
 options.set_argument('--start-maximized')
 # 设置初始窗口大小
 options.set_argument('--window-size', '800,600')
 #此方法用于清空已设置的arguments参数。
 options.clear_arguments()
 #把创建的options对象传入browser对象
 browser = Chromium(options)
 #获取标签页对象打开网址
 tab = browser.new_tab('https://www.baidu.com')

操作标签页

browser.latest_tab --- 最新标签页(最后打开的标签页)

 from DrissionPage import Chromium
 ​
 # 创建一个Chromium浏览器实例
 browser = Chromium()
 ​
 # 打开一个新的标签页,访问百度
 tab1 = browser.new_tab('https://www.baidu.com')
 # 打开一个新的标签页,访问必应
 tab2 = browser.new_tab('https://www.bing.com')
 # 获取最新打开的标签页
 tab3 = browser.latest_tab
 ​
 # 打印百度标签页的标题
 print(tab1.title)
 # 打印必应标签页的标题
 print(tab2.title)
 # 打印最新标签页的标题
 print(tab3.title)
 # 关闭浏览器的最新标签页
 browser.latest_tab.close()

标签页没有Selenium所谓的焦点的概念,多个标签页可以并行操作,所以可以多线程同时打开多个标签页

 #标签页没有Selenium所谓的焦点的概念,多个标签页可以并行操作,所以可以多线程同时打开多个标签页
 ​
 # 导入ThreadPoolExecutor类,用于创建和管理一个线程池
 from concurrent.futures import ThreadPoolExecutor
 ​
 def open_url(browser, url):
     """
     打开指定的URL。
 ​
     :param browser: 浏览器实例,用于打开URL。
     :param url: 需要打开的网址字符串。
     """
     browser.new_tab(url)
 ​
 # 定义一个包含多个中文网站URL的列表
 chinese_websites=[
     "https://www.taobao.com",
     "https://www.jd.com",
     "https://www.tmall.com"
 ]
 ​
 # 使用ThreadPoolExecutor来并发打开URL,最大工作线程数设置为3
 with ThreadPoolExecutor(max_workers=3) as executor:
     # 遍历网址列表,提交任务到线程池
     for url in chinese_websites:
         executor.submit(open_url, browser, url)

元素定位之普通元素定位

第一种:文本内容定位 tab.ele('文库')

  • 原理:这种定位方式是基于元素的文本内容进行查找。它会在页面中搜索所有包含指定文本(这里是 “文库”)的元素,并返回第一个匹配的元素。

  • 优点:非常直观和简单,适用于通过元素显示的文本来定位元素的场景,尤其当元素没有明确的 ID、类名等属性时,使用文本内容定位是一种有效的方法。

  • 缺点:不够精确,因为可能存在多个元素包含相同的文本内容。而且如果页面上的文本发生变化,定位可能会失效。

  • 适用场景:适用于元素文本具有唯一性且比较稳定的情况,例如按钮、链接等元素的文本通常是固定的,可以使用这种方式定位。

第二种:ID 属性定位 tab.ele('@id=kw')

  • 原理:通过元素的 id 属性来定位元素。在 HTML 中,id 属性是唯一的,每个元素的 id 值在页面中应该是独一无二的。因此,使用 id 属性定位可以准确地找到特定的元素。

  • 优点:定位精确,效率高。由于 id 的唯一性,使用 id 属性定位可以快速准确地找到目标元素,并且不容易受到页面结构变化的影响。

  • 缺点:如果页面的 HTML 代码中没有为目标元素设置 id 属性,或者 id 属性值被动态修改,这种定位方式就会失效。

  • 适用场景:适用于页面中具有唯一 id 属性的元素,如输入框、特定的按钮等。在大多数情况下,优先使用 id 属性定位可以提高代码的稳定性和可维护性。

第三种:属性组合定位 tab.ele('tag:input@@type=submit@@value=百度一下')

  • 原理:这是一种组合定位方式,它结合了元素标签名和多个属性来定位元素。在这个例子中,它会查找标签名为 inputtype 属性值为 submitvalue 属性值为 百度一下 的元素。

  • 优点:定位更加精确,可以通过多个条件来筛选元素,适用于需要根据多个属性来确定唯一元素的场景。

  • 缺点:代码相对复杂,需要了解元素的多个属性信息。而且如果页面的 HTML 结构或属性值发生变化,定位可能会失效。

  • 适用场景:当仅使用单个属性无法准确定位元素时,可以使用属性组合定位。例如,页面上可能有多个 input 元素,通过结合 typevalue 属性可以更准确地找到目标按钮。

第四种:XPath 定位 tab('xpath:/html/body/div[1]/div[1]/div[5]/div[2]/div/form/span[2]/input')

  • 原理:XPath 是一种用于在 XML 或 HTML 文档中定位节点的语言。这里使用的是绝对 XPath,从文档的根节点(``)开始,按照元素的层级结构和索引来精确描述元素的位置。

  • 优点:定位能力强大,可根据元素的层级、属性、文本内容等多种信息定位,灵活性高。可以处理复杂的页面结构和动态元素。

  • 缺点:代码复杂且难以维护,绝对 XPath 对页面结构变化非常敏感,一旦页面结构有改动,定位就会失效。而且相比其他定位方式,性能可能稍差,因为需要遍历整个 DOM 树来匹配。

  • 适用场景:当元素没有明显的 ID、类名等属性,或者需要根据元素的相对位置定位时使用。不过更推荐使用相对 XPath 来提高稳定性。

    xpath如图获取

    绝对 XPath 对页面结构变化非常敏感,推荐使用相对 XPath 来提高代码的稳定性。例如,如果要定位 value 属性为 百度一下input 元素,可以使用以下相对 XPath 表达式:

关于xpath还有一种优化写法:

 search_button = tab('xpath://input[@value="百度一下"]')
 search_button.click()

其中元素是根据这些来填写

 from DrissionPage import Chromium
 ​
 # 创建Chromium浏览器实例
 browser = Chromium()
 ​
 # 打开新标签页并导航到指定URL
 tab = browser.new_tab('https://www.baidu.com')
 ​
 # 查找并点击页面上的"文库"按钮
 wenku_button = tab.ele('文库')
 wenku_button.click()
 ​
 # 在搜索框中输入'python'
 input_box = tab.ele('@id=kw')
 input_box.input('python')
 ​
 # 查找并点击搜索按钮
 search_button = tab.ele('tag:input@@type=submit@@value=百度一下')
 search_button.click()
 ​
 # xpath定位搜索按钮并点击,开始搜索
 search_button = tab('xpath:/html/body/div[1]/div[1]/div[5]/div[2]/div/form/span[2]/input')
 search_button.click()
 ​
 # 定位并点击具有特定值的搜索按钮
 search_button = tab('xpath://input[@value="百度一下"]')
 search_button.click()

元素定位之iframe定位

iframe元素是一种特殊的定位元素,用于网页嵌套的元素。

<iframe>是什么?

<iframe>是 HTML 标签,用于在网页里嵌入另一个 HTML 文档。它能嵌入外部网页(如地图、视频),实现页面模块化和跨域通信。优点是内容独立、可复用、加载可控;缺点有性能差、样式布局难统一、影响 SEO。还存在安全风险 可用 sandbox 属性限制。

1. 专用框架定位法

iframe = tab.get_frame('t:iframe')

定位原理

  • get_frame 是专门用于获取框架(包括 )的方法。't:iframe' 是一种元素定位表达式,t: 表示通过标签名来定位,这里即定位标签名为 iframe 的元素。该方法会返回匹配条件的第一个 `` 框架对象,并且它会按照框架相关的逻辑进行查找和处理,确保返回的是一个有效的框架实例。

特点

  • 规范性高:这种方式是专门针对框架元素的定位方法,语义明确,代码的可读性和规范性较好,能够清晰地表明你是在获取一个框架元素。

  • 功能完整:使用 get_frame 方法获取的框架对象,在后续操作中可以完整地使用框架相关的功能和属性,例如可以方便地在该框架内继续定位元素、执行操作等。

试用场景

  • 当你明确要操作 <iframe> 元素,并且希望代码具有较高的规范性和可读性时,推荐使用这种方式

 # 创建Chromium浏览器实例
 browser = Chromium()
 ​
 # 打开一个新的标签页,访问指定的URL
 tab = browser.new_tab('https://drissionpage.cn/demos/iframe_diff_domain.html')
 ​
 # 获取页面中的iframe元素,使用最规范的方式
 iframe = tab.get_frame('t:iframe') #最规范
 # 在iframe中找到指定文本的元素,并打印
 ele = iframe.ele('网易首页')
 print(ele)
2. 通用元素定位法

iframe = tab.ele('t:iframe')

定位原理

  • ele 方法是一个通用的元素定位方法,可以用于定位页面中的各种元素。同样,'t:iframe' 表示通过标签名 iframe 来定位元素。该方法会返回匹配条件的第一个元素对象,这里返回的是 `` 元素对象。

特点

  • 简洁性好:使用通用的元素定位方法,代码简洁,不需要额外记忆专门的框架定位方法。

  • 兼容性好:由于 ele 是通用方法,在不同的场景下使用较为一致,对于已经熟悉该方法的开发者来说,使用起来更加顺手。

适用场景

  • 当你希望代码尽可能简洁,并且对框架的特殊处理需求不多时,可以选择这种方式。但需要注意的是,返回的是普通元素对象,在使用一些框架特定功能时可能需要进行额外的转换或处理。

 # 创建Chromium浏览器实例
 browser = Chromium()
 ​
 # 打开一个新的标签页,访问指定的URL
 tab = browser.new_tab('https://drissionpage.cn/demos/iframe_diff_domain.html')
 # 获取页面中的iframe元素,使用最简洁的方式
 iframe = tab.ele('t:iframe') #最简洁
 # 在iframe中找到指定文本的元素,并打印
 ele = iframe('网易首页')
 print(ele)
3.元素列表索引定位法

iframe = tab.eles('t:iframe')[0]

定位原理:

  • eles 方法用于获取页面中所有匹配条件的元素列表。't:iframe' 表示通过标签名 iframe 来定位元素,然后通过索引 [0] 从元素列表中取出第一个 <iframe> 元素对象。

特点:

  • 成功率高:当页面中可能存在多个 元素,并且不确定使用其他方法是否能准确获取到目标 时,使用 eles 方法可以先获取所有的 `` 元素,再通过索引选择需要的元素,从而提高定位的成功率。

  • 灵活性强:可以根据实际情况选择不同索引的 元素,适用于需要处理多个 元素的场景。

适用场景:

  • 当页面中存在多个 元素,且你需要根据具体情况选择特定的 元素时,这种方式更加合适。

 # 创建Chromium浏览器实例
 browser = Chromium()
 ​
 # 打开一个新的标签页,访问指定的URL
 tab = browser.new_tab('https://drissionpage.cn/demos/iframe_diff_domain.html')
 # 获取页面中的iframe元素列表,使用成功率最高的方式
 iframe = tab.eles('t:iframe')[0]  #成功率最高
 # 在iframe中找到指定文本的元素,并打印
 ele = iframe('网易首页')
 print(ele)

代码运行控制台效果:

class BlogLogin: url = “” driver = “” def __init__(self): chrome_driver_path = "C:/Users/hyl18/AppData/Local/Google/Chrome/Application/chromedriver.exe" chrome_options = Options() chrome_options.add_argument("--remote-allow-origins=*") # 3. 创建 WebDriver 对象 # self.driver = webdriver.Chrome(service=Service(chrome_driver_path), options=chrome_options) self.url = "https://www.csdn.net/" self.driver = BlogDriver.driver self.driver.get(self.url) #成功登录的测试用例 def LoginSucTest(self): self.driver.find_element(By.CSS_SELECTOR, "#csdn-toolbar > div > div > div.toolbar-container-right > div > div.toolbar-btn.toolbar-btn-login.toolbar-btn-login-new.csdn-toolbar-fl > a").click() time.sleep(1) self.driver.find_element(By.CSS_SELECTOR, "#csdn-toolbar > div.toolbar-inside.exp3 > div > div.toolbar-container-left > ul > li:nth-child(5) > a").click() time.sleep(2) # self.driver.find_element(By.CSS_SELECTOR,"body > div > div > div > div.login-box > div.login-box-top > div > div.login-box-tabs-main > div.login-form > div:nth-child(1) > div > input").send_keys("18830883413") # time.sleep(1) # self.driver.find_element(By.CSS_SELECTOR,"body > div > div > div > div.login-box > div.login-box-top > div > div.login-box-tabs-main > div.login-form > div:nth-child(2) > div > input").send_keys("20040324Hyl.") # time.sleep(2) # self.driver.find_element(By.CSS_SELECTOR,"body > div > div > div > div.login-box > div.login-box-top > div > div.login-box-tabs-main > div.login-form > div:nth-child(4) > button").click() # time.sleep(2) self.driver.quit() #异常登录的测试用例 login = BlogLogin() login.LoginSucTest() 我在自动化测试的过程中,我想打开https://www.csdn.net/网站,然后自动点击登录,登陆后点击密码登录,我正确的复制了密码登录的SELECTOR,但是报错了,错误是:Traceback (most recent call last): File “C:\Users\hyl18\PycharmProjects\BlogAutoTest\tests\BlogLogin.py”, line 43, in <module> login.LoginSucTest() File “C:\Users\hyl18\PycharmProjects\BlogAutoTest\tests\BlogLogin.py”, line 30, in LoginSucTest self.driver.find_element(By.CSS_SELECTOR, “#csdn-toolbar > div.toolbar-inside.exp3 > div > div.toolbar-container-left > ul > li:nth-child(5) > a”).click() File “C:\Users\hyl18\PycharmProjects\BlogAutoTest.venv\lib\site-packages\selenium\webdriver\remote\webelement.py”, line 80, in click self._execute(Command.CLICK_ELEMENT) File “C:\Users\hyl18\PycharmProjects\BlogAutoTest.venv\lib\site-packages\selenium\webdriver\remote\webelement.py”, line 693, in _execute return self._parent.execute(command, params) File “C:\Users\hyl18\PycharmProjects\BlogAutoTest.venv\lib\site-packages\selenium\webdriver\remote\webdriver.py”, line 418, in execute self.error_handler.check_response(response) File “C:\Users\hyl18\PycharmProjects\BlogAutoTest.venv\lib\site-packages\selenium\webdriver\remote\errorhandler.py”, line 243, in check_response raise exception_class(message, screen, stacktrace)
03-09
<think>好的,用户在使用Selenium进行自动化测试时遇到了问题。他们想打开CSDN网站,自动点击登录,然后切换到密码登录,但执行到点击密码登录时抛出了异常。我需要分析可能的原因和解决方案。 首先,用户提供的错误信息是元素点击时出现异常,可能是元素未找到或者无法交互。常见的原因包括元素定位不正确、页面加载延迟、元素被遮挡或动态变化等。 查看用户代码,发现他们在点击登录按钮后使用了time.sleep(1),然后尝试点击密码登录选项。但页面加载可能需要更长时间,特别是如果页面有动态内容或AJAX请求。此时,隐式等待或显式等待可能比固定等待更可靠。 另外,用户注释掉了输入用户名和密码的部分,可能是因为测试时跳过这部分,但实际页面可能需要先输入才能继续。不过当前错误发生在点击密码登录之前,所以可能和输入无关。 检查CSS选择器是否正确。用户使用的选择器路径较长,可能依赖于页面结构,如果CSDN的前端结构变化,选择器可能失效。需要验证选择器是否准确,可以通过浏览器开发者工具检查元素是否存在。 还有,用户初始化driver的方式可能有问题。他们从BlogDriver.driver获取driver实例,但不确定是否正确初始化。如果driver没有正确配置,可能导致页面无法正常加载,元素无法找到。 此外,是否有弹窗或iframe遮挡了目标元素?需要确认页面是否有模态框或其他元素阻碍点击操作。 可能的解决方案包括:增加等待时间,使用显式等待(如WebDriverWait),验证CSS选择器的正确性,检查页面结构是否有变化,确保driver正确初始化,处理可能的弹窗等。 需要逐步排查这些可能性,建议用户先手动测试步骤,确认选择器有效,然后调整代码中的等待策略,使用更可靠的定位方式,如XPath或相对选择器,减少对长CSS路径的依赖。</think>你的代码存在多个潜在问题导致元素定位失败。以下是逐步排查与修复方案: --- ### **问题 1:WebDriver 初始化方式错误** #### 现象 - 代码中 `self.driver = BlogDriver.driver` 未明确定义来源,可能未正确初始化 WebDriver。 #### 修复方案 - **直接初始化 Chrome WebDriver**(取消注释原有代码): ```python from selenium import webdriver from selenium.webdriver.chrome.service import Service from selenium.webdriver.chrome.options import Options class BlogLogin: def __init__(self): chrome_driver_path = "C:/Users/hyl18/AppData/Local/Google/Chrome/Application/chromedriver.exe" chrome_options = Options() chrome_options.add_argument("--remote-allow-origins=*") self.driver = webdriver.Chrome(service=Service(chrome_driver_path), options=chrome_options) self.driver.get("https://www.csdn.net/") ``` --- ### **问题 2:元素定位不稳定** #### 现象 - 使用长链式 CSS 选择器(如 `#csdn-toolbar > div.toolbar-inside.exp3 > div > div.toolbar-container-left > ul > li:nth-child(5) > a`)容易因页面结构微小变化导致失效。 #### 修复方案 - **改用更简洁的定位方式**: ```python def LoginSucTest(self): # 点击登录按钮 self.driver.find_element(By.CSS_SELECTOR, "a[href='/login']").click() time.sleep(1) # 切换到密码登录标签(假设页面存在该元素) password_login_tab = self.driver.find_element(By.XPATH, "//span[contains(text(), '密码登录')]") password_login_tab.click() ``` - **说明**:使用属性选择器 `a[href='/login']` 或文本匹配 `contains(text(), '密码登录')` 更稳定。 --- ### **问题 3:未处理页面加载延迟** #### 现象 - 使用 `time.sleep(1)` 可能导致元素尚未加载完成就尝试操作。 #### 修复方案 - **使用显式等待(Explicit Waits)**: ```python from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC def LoginSucTest(self): # 点击登录按钮 login_button = WebDriverWait(self.driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, "a[href='/login']")) ) login_button.click() # 切换到密码登录标签 password_tab = WebDriverWait(self.driver, 10).until( EC.element_to_be_clickable((By.XPATH, "//span[contains(text(), '密码登录')]")) ) password_tab.click() ``` --- ### **问题 4:未处理弹窗或 iframe** #### 现象 - 如果登录弹窗在 iframe 中,需先切换到对应 iframe。 #### 修复方案 - **检查是否涉及 iframe**: ```python # 假设登录弹窗在 iframe 中 iframe = self.driver.find_element(By.TAG_NAME, "iframe") self.driver.switch_to.frame(iframe) # 操作元素 self.driver.switch_to.default_content() # 切回主文档 ``` --- ### **验证步骤** 1. **手动验证选择器**: - 打开浏览器开发者工具(F12),使用 `$$("a[href='/login']")` 验证是否能定位到登录按钮。 2. **逐步执行代码**: - 在 `click()` 操作前添加断点或 `print` 语句,确认元素已找到。 3. **检查网络请求**: - 确保页面没有因动态加载导致元素延迟出现。 --- ### **完整修复代码示例** ```python from selenium import webdriver from selenium.webdriver import Chrome from selenium.webdriver.chrome.service import Service from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import time class BlogLogin: def __init__(self): chrome_driver_path = "C:/Users/hyl18/AppData/Local/Google/Chrome/Application/chromedriver.exe" chrome_options = Options() chrome_options.add_argument("--remote-allow-origins=*") self.driver = webdriver.Chrome(service=Service(chrome_driver_path), options=chrome_options) self.driver.get("https://www.csdn.net/") def LoginSucTest(self): try: # 点击登录按钮 login_button = WebDriverWait(self.driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, "a[href='/login']")) ) login_button.click() # 切换到密码登录标签 password_tab = WebDriverWait(self.driver, 10).until( EC.element_to_be_clickable((By.XPATH, "//span[contains(text(), '密码登录')]")) ) password_tab.click() time.sleep(3) # 观察结果 finally: self.driver.quit() if __name__ == "__main__": login = BlogLogin() login.LoginSucTest() ``` --- ### **其他建议** 1. **使用相对路径定位**:避免依赖复杂的 CSS 层级结构。 2. **启用无头模式(可选)**: ```python chrome_options.add_argument("--headless=new") # 不显示浏览器窗口 ``` 3. **日志记录**:添加 `try-except` 捕获异常并输出日志。 通过以上调整,你的自动化脚本应能稳定执行登录操作。若问题仍存,请提供最新的页面 HTML 片段或错误截图进一步分析!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值