关于web自动化selenium的学习笔记

前言

  • 上一次用selenium还是在21年。
  • 前天要开发web自动化的脚本,这玩意其实用按键精灵比较适合。
  • 但是按键精灵PC版我基本没怎么用过,那就只能用selenium了。
  • 当然,selenium和按键精灵各有优劣,selenium也挺好的。
  • 用selenium踩坑点太多了,一些流程写起来很不好处理,全代码贼多的捕获异常语句。
  • 本文记录一些踩坑点...(有机会还得去熟悉下PC版按键,技多不压身)

关于selenium的安装

截至2024.04.12,不指定版本安装的话,selenium最新版是4.19.0

pip install selenium
  • 目前的最新版是不需要指定chromedriver驱动
  • 但是,如果下载的是第三方谷歌浏览器,比如说在虚拟机里可能无法直接安装官方谷歌浏览器
  • 那么下载第三方的浏览器可能就得指定chromedriver驱动
  • 根据浏览器版本下载指定的驱动,然后将驱动解压后放在浏览器的安装目录下
  • 但是的话如果要指定驱动路径就需要降低下selenium版本了,推荐3.14.0
pip install selenium==3.14.0
chrome_options = Options()
port = "1234"
user_data_dir = f"C:\\selenum\\AutomationProfile_{port}"
chrome_options.add_experimental_option("debuggerAddress", f"127.0.0.1:{port}")
driver_path = "C:/Users/daowuya/AppData/Local/MyChrome/Chrome/Application/chromedriver.exe"
os.popen(f'"{chrome_path}" --remote-debugging-port={port} --user-data-dir="{user_data_dir}"')
driver = webdriver.Chrome(executable_path=driver_path, options=chrome_options)

注:此处的chrome_options和最新版的引用不一样,最新版的引用见下文的启用调试模式

启用调试模式

当浏览器环境不够模拟的时候,就得启用调试模式了。

浏览器路径的指定

  • 通过读取本地里的文本来指定路径会有问题,这问题排查了很久。
  • 后面直接在代码里指定就解决了
chrome_path = r"C:\Program Files\Google\Chrome\Application\chrome.exe"

浏览器运行端口和用户数据的指定

  • 如果程序不需要多开的话就没必要去指定,否则就必须指定。
  • 用户数据不能用同一个路径,不然就无法多开,用户数据可以和端口相绑定。
  • 端口不建议随机生成,这是踩坑点。
  • 随机生成的端口会导致每次打开的浏览器都是全新的,全新的浏览器“初始设置”没设置,会导致打开url时上面的网页栏丢失,最终会造成后面的driver.close()或者driver.quit()命令无效。
  • 端口应该指定,或者读取本地文本。在指定端口后,先用指定的端口运行一遍,这样一个浏览器就有了“初始设置”,就不会出现上面的命令失效的问题。
chrome_options = webdriver.ChromeOptions()
port = "1314"
uer_data_dir = f"C:\\selenum\\AutomationProfile_{port}"
chrome_options.add_experimental_option("debuggerAddress", f"127.0.0.1:{port}")
os.popen(f'"{chrome_path}" --remote-debugging-port={port} --user-data-dir="{user_data_dir}"')
driver = webdriver.Chrome(options=chrome_options)

清除浏览器缓存

下面的跳转没啥问题,主要是弹窗的点击按钮用selenium根本无法定位到,于是使用了execute_script运行js代码命令去定位到

  • 设置-隐私和安全-清除浏览数据-清除数据
driver.get('chrome://settings/clearBrowserData')
driver.implicitly_wait(60)
time.sleep(1)
clearButton = driver.execute_script("return document.querySelector('settings-ui').shadowRoot.querySelector('settings-main').shadowRoot.querySelector('settings-basic-page').shadowRoot.querySelector('settings-section > settings-privacy-page').shadowRoot.querySelector('settings-clear-browsing-data-dialog').shadowRoot.querySelector('#clearBrowsingDataDialog').querySelector('#clearBrowsingDataConfirm')")
advancedArea.click()
time.sleep(2)
  • 设置-重置设置-将设置还原为原始默认设置-重置设置
driver.get("chrome://settings/resetProfileSettings?origin=userclick")
driver.implicitly_wait(60)
time.sleep(1)
clearButton = driver.execute_script("return document.querySelector('settings-ui').shadowRoot.querySelector('settings-main').shadowRoot.querySelector('settings-basic-page').shadowRoot.querySelector('settings-section > settings-reset-page').shadowRoot.querySelector('settings-reset-profile-dialog').shadowRoot.querySelector('#dialog').querySelector('#reset')")
clearButton.click()
time.sleep(2)

判断元素的存在性

使用隐式等待,再配合捕获异常,看起来是比较丑陋了点,不过能实现就好!踩坑点,换了两三种写法...

while True:
    try:
        element = driver.find_element(By.XPATH, "//div[contains(@class, 'ui-form-explain') and contains(text(), '发送次数超过限制')]")
        if element.is_displayed():
            print("存在发送次数超过限制")
            break
    except Exception as e:
        print("不存在发送次数超过限制!")

要点就是if element 和 if element.is_displayed()的区别:

  • if element
    主要检查element对象是否存在,即使这个对象代表的元素在页面上不可见或者位置为空,这个检查不关心元素是否可见,只关心元素是否被成功找到并引用。
  • if element.is_displayed()
    具体检查页面上的元素是否对用户可见。一个元素可能在DOM(文档对象模型)中存在,但由于各种原因(例如,CSS设置为display: none或visibility: hidden),它可能不会显示在页面上。

因此,如果只用if element去判断一个元素后执行点击,往往可能卡住,即使加了隐式等待去用捕获异常判断,因为元素对象存在,但元素不可见,就可能导致了元素不可交互,也就是不能执行点击操作。所以稳妥的用法就是嵌套使用,先判断是否存在,再判断是否可见!

一些元素在页面但无法被定位到

检查下是否这个元素被iframe所包裹

如果被iframe所包裹,那么切换后再执行定位的命令,基本能解决

iframe = driver.find_element(By.ID, "iframe1")
driver.switch_to.frame(iframe)

切换回主文档:最外层的HTML文档,也就是没有被任何iframes或frames嵌套的部分

driver.switch_to.default_content()

使用代理去启动浏览器

有时候单ip就会导致被检测到或者限制了,此时就需要用到代理了。

  • 如果不是用调试模式启动的,那么就直接在chrome_options增加就行了
proxy=""
chrome_options.add_argument(f'--proxy-server={proxy}')
  • 如果是在调试模式下启动的,那么加在chrome_options是无效的,需要在启动的时候直接加
proxy=""
os.popen(f'"{chrome_path}" --remote-debugging-port={port} --user-data-dir="{user_data_dir}" --proxy-server={proxy}')

关于过滑块方面

下面给的例子毫无轨迹可言,可应付没有轨迹检测的滑块。轨迹滑块在这不作分享...

slider = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, "/html/body/div/div[2]/div/div[1]/div[2]/center/div[1]/div/div/div/span")))
ActionChains(driver).click_and_hold(slider).move_by_offset(300, 0).release().perform()

其他

遇到了再补充,暂时没用到其他的...


作 者:道无涯
来 源:道无涯博客
链 接: https://www.daowuya.love/关于web自动化selenium的学习笔记/
版 权 声 明:本博客所有文章除特别声明外,均采用CC BY-NC-SA 4.0许可协议。文章版权归作者所有,未经允许请勿转载!


暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇