win11系统下使用iedriver开发带有activex控件的网站的自动化脚本 前情提要 本文技术要点:win11、ie、iedriver、python、selenium4.14.0、activex控件
前情提要部分没啥用,大家需要了解编写脚本的技巧的自行在本页ctrl+F
搜索你想知道的相关关键词
最近有个小项目的工作流上,需要用到一个自动化脚本来填写表单,大体是这样:
用户在A系统上下单之后,要讲数据录入到系统B中,系统A和系统B属于不同公司,且数据不互通,并且将数据录入的过程中,还需要各种拍照、使用NFC或者高拍仪等工具读取身份证件等过程。
在接受这个项目的过程中,我遇到了以下几个比较棘手的点:
B系统的录入系统是基于ie开发的,并且用到了activex控件,所以必须使用ie内核的浏览器
表单录入的过程中,需要从系统A中查询用户的信息,信息多且数据长度较长,比较容易出错
表单录入的过程中,需要从一个有40多页、每页5格,且数据随机分散在这40页的表格中找到一个数据,数据可以与实际不符,也就是可以乱选,但不允许大量的用户选择到重复数据,人工填写很难保证随机性
ie浏览器设置cookie的问题:driver.add_cookie()
函数可能会不起作用,我换了各种版本的driver和selenium版本,甚至使用了win7系统都无法正常将cookie添加进去
验证码接入问题:这个其实不属于本文章范畴之内,我们使用了开源的短信转发系统,将验证码推送到飞书机器人或者自建的接口,用于接收验证码
send_keys()
的效率问题,在ie中,send_keys()
可能会很慢很慢,使用pyperclip
可能依然很慢,如果你遇到了和我一样的情况,建议使用edge,调试的效率不知提升一点点
win11/win10下使用iedriver驱动Edge的ie内核模式 使用下面这段代码,我们可以得到一个使用iedriver驱动的Edge的ie内核模式的浏览器
1 2 3 4 5 6 ie_options = webdriver.IeOptions() ie_options.attach_to_edge_chrome = True ie_options.ignore_protected_mode_settings=True ie_options.edge_executable_path = "C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe" driver = webdriver.Ie(options=ie_options)
ie_options.attach_to_edge_chrome
和ie_options.edge_executable_path
这两句话是用来保证我们能够一直使用edge来操控ie的,不然的话在脚本运行的期间,可能某些页面会跳转到ie11的界面,导致一些网页没法正常显示
activex控件启用不成功问题 你可能需要进入interne选项的安全面板,选择一个区域,然后点击自定义级别,将所有的activex控件相关的项目变更为“启用”状态
python3使用sqlalchemy的依赖问题以及密码中含有@等特殊字符的问题 这里我实现了一个自定义类,用来暴露给main.py
文件调用,方便调试代码与协同开发、降低耦合度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 from sqlalchemy import Column, Integer, String, ForeignKeyfrom sqlalchemy.ext.declarative import declarative_basefrom urllib.parse import quote_plus as urlquotefrom sqlalchemy import create_enginefrom sqlalchemy.orm import sessionmakerclass Query : def __init__ (self, host, user, password, database ): '''初始化数据库连接 host: 数据库地址 user: 数据库用户名 password: 数据库密码 database: 数据库名 ''' self.engine = create_engine(f'mysql://{user} :{urlquote(password)} @{host} /{database} ?charset=utf8mb4' ) self.Base = declarative_base() self.Base.metadata.create_all(self.engine) self.Session = sessionmaker(bind=self.engine) self.session = self.Session() def __del__ (self ): self.session.close() def __getSession (self ): return self.session def getOrdersByPhone (self, phone: str ): """通过手机号查询订单""" return self.session.query(Order).filter ( Order.phone == phone, Order.status == 1 ).all () def getOrdersByStudentId (self, studentId: str ): """通过学号查询订单""" return self.session.query(Order).filter ( Order.student_id == studentId, Order.status == 1 ).all () def getOrdersByIdCard (self, idCard: str ): """通过身份证号查询订单""" return self.session.query(Order).filter ( Order.id_card == idCard, Order.status == 1 ).all ()
首先声明一下,这里使用sqlalchemy
是因为作者太菜不会写sql语句。
依赖问题 这里我遇到了几个问题,在python3,如果出现no moudle named mysqldb
之类的报错,需要pip install mysql-client
这个库
特殊字符问题 需要将
1 create_engine('mysql://{user}:{password}@{host}/{database}?charset=utf8mb4' )
替换为
1 create_engine(f'mysql://{user} :{urlquote(password)} @{host} /{database} ?charset=utf8mb4' )
当然你需要在这之前
1 from urllib.parse import quote_plus as urlquote
使用driver.execute_script
为ie浏览器添加cookie而非driver.add_cookie()
在ie中driver.add_cookie()
很有可能没法正确设置cookie,如果你也遇到这样的问题,不妨尝试使用driver.execute_script()
以下是一个例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 from selenium import webdriver driver = webdriver.Ie() cookie = { 'name' : 'SESSION_ID' , 'value' : 'content' , 'path' : '/your/path' , 'domain' : 'example.com' } driver.execute_script("document.cookie = '{}={}; path={}; domain={}'" .format ( cookie['name' ], cookie['value' ], cookie['path' ], cookie['domain' ])) driver.refresh()print (driver.get_cookies())input ('Press ENTER to close the automated browser' ) driver.quit()