日期控件的处理
日期控件的输入框中有一个readonly的属性,导致文本框只读。 日期控件如果将选择时间框点击之后,再去选择日期,第一元素不容易定位,第二不太稳定,因此,设置时间时是先更改日期控件文本框的属性,然后直接输入时间,来实现时间的选择 代码示例:
from selenium. webdriver. common. by import By
from selenium. webdriver. support. wait import WebDriverWait
from selenium. webdriver. support import expected_conditions as EC
from selenium import webdriver
import time
diver = webdriver. Chrome( )
diver. maximize_window( )
try :
diver. get( "https://www.12306.cn/index/" )
WebDriverWait( diver, 20 ) . until( EC. visibility_of_element_located( ( By. ID, 'fromStationText' ) ) )
diver. execute_script( 'document.getElementById("train_date").readOnly=false' )
diver. find_element_by_id( "train_date" ) . clear( )
diver. find_element_by_id( "train_date" ) . send_keys( '2020-10-01' )
diver. find_element_by_id( "search-input" ) . click( )
diver. find_element_by_id( 'search_one' ) . click( )
time. sleep( 10 )
diver. quit( )
except Exception as e:
diver. quit( )
raise e
上传文件
文件上传有两种形式:输入框(标签名为input)和打开上传框
文本输入框输入地址(input)
如果上传文件的输入框可以输入地址,处理方式和时间控件一样 直接使用send_keys写入文件的路径
需要打开弹框选择文件(非input)——windows
工具安装——AutoIT
如果只有上传按钮,即非input标签的上传,需要输入文件地址并点击打开按钮,这种方式使用selenium打开不了,使用的是wimdows控件 这时候,需要使用python第三方库来进行处理,需要使用python pywin32库,他的作用是事变对话框句柄,进而操作 python pywin32只能在windows上进行操作 处理流程:找元素——操作,路径必须是绝对路径 使用工具:AutoIT 工具下载地址 工具安装:直接点击网站上下方的按钮,然后下一步安装即可 安装完成之后,可在控制台看到以下几个工具: 我们就可以得到:
AutoIT Window Info 识别Windows元素信息
Complie Script to .exe 将AutoIT编写的脚本编译成exe可执行文件
SciTE Script Editor 编写AutoIT脚本 要注意的是:官方推荐使用X86版本,这样兼容性问题会少些
工具使用
将上传的Windows窗口打开 控制台(关机的地方)打开AutoIT Window Info 工具,Finder Tool下的图标一直按住,选择窗口中要识别的元素(文件名后面的输入框以及打开按钮),分别记录下此时的Tile、Class等信息 控制台(关机的地方)打开SciTE Script Editor ,粘贴下方的脚本即可(注意元素的定位是由Class和Instance进行拼接的,如Class为Edit,Instance为1,那么定位表达式为Edit1)
Edit1需要根据实际情况修改,取值为上方红框中的class和Instance(在Finder Tool下的图标左边显示)
; 等待“打开”窗口
WinWaitActive ( "打开" )
; 休眠2 秒
Sleep ( 2000 )
; 在输入框中写入上传文件的路径, $CmdLine[ 1 ] 代表接收外部传入的参数
ControlSetText ( "打开" , "" , "Edit1" , $CmdLine[ 1 ] )
; 休眠2 秒
Sleep ( 2000 )
; 点击打开按钮
ControlClick ( "打开" , "" , "Button1" ) ;
将脚本保存,后缀为au3 选择Complie Script to .exe 工具,选择本地的au3后缀的脚本,把脚本编译为exe文件 代码执行本地exe文件,需要指定上传的文件路径,执行文件的时候需要将上传文件的窗口打开
python中执行的步骤
首先点击上传输入框将上传文件的框打开(普通click无法点击的话,需要使用鼠标点击 在pythonz执行exe文件,os.system(‘执行文件 图片的路径’)
注意,system中传一个字符串,图片路径和执行文件用空格隔开,可以使用pathlib使用相对路径
linux 服务器上运行
如果生成的py文件在linux上运行,需要注意: 首先确保你的Linux服务器已经安装了Python。你可以通过在终端运行python --version命令来检查Python版本。 请确保upload_data.exe可执行程序位于正确的目录下,并且具备执行权限。可以使用ls -l命令查看文件权限,如果没有执行权限,可以使用chmod +x upload_data.exe为文件添加执行权限。 在执行Python脚本之前,你需要切换到脚本所在的目录,或者在脚本中使用绝对路径指定upload_data.exe的路径。这样可以确保正确地找到并执行可执行文件。
代码示例
import os
from selenium import webdriver
from selenium. webdriver. common. by import By
from selenium. webdriver. support. wait import WebDriverWait
from selenium. webdriver. support import expected_conditions as EC
from selenium. webdriver. common. action_chains import ActionChains
import time
import pathlib
login = ( By. XPATH, '//a[text()="登录"]' )
login_box = ( By. XPATH, '//div[@class="login-con"]//input[contains(@placeholder,"手机号")]' )
pwd_box = ( By. XPATH, '//div[@class="login-con"]//input[contains(@placeholder,"密码")]' )
login_button = ( By. XPATH, '//div[@class="login-con"]//a[text()="登录"]' )
login_success = ( By. XPATH, '//div[@id="__layout"]//span[@class="text"]' )
person_center = ( By. XPATH, '//span[text()="个人中心"]' )
person_img = ( By. XPATH, '//div[@class="portrait"]/img' )
vim_material = ( By. XPATH, '//div[@class="portrait"]/following-sibling::div' )
upload_img = ( By. XPATH, '//div[@tabindex="0"]' )
save_information = ( By. XPATH, '//a[text()="保存账户信息"]' )
def wait_ele_loc ( driver, ele) :
WebDriverWait( driver, 10 ) . until( EC. visibility_of_element_located( ele) )
def wait_ele_click ( driver, ele) :
WebDriverWait( driver, 10 ) . until( EC. element_to_be_clickable( ele) )
class SeleniumDriver :
with webdriver. Chrome( ) as driver:
driver. get( "http://mall.lemonban.com:3344" )
driver. maximize_window( )
wait_ele_loc( driver, login)
driver. find_element( * login) . click( )
wait_ele_click( driver, login_button)
driver. find_element( * login_box) . send_keys( "lemon_auto" )
driver. find_element( * pwd_box) . send_keys( "lemon123456" )
driver. find_element( * login_button) . click( )
time. sleep( 1 )
wait_ele_loc( driver, login_success)
driver. find_element( * person_center) . click( )
wait_ele_loc( driver, person_img)
ele = driver. find_element( * person_img)
ActionChains( driver) . move_to_element( ele) . perform( )
wait_ele_click( driver, vim_material)
driver. find_element( * vim_material) . click( )
wait_ele_click( driver, upload_img)
driver. find_element( * upload_img) . click( )
hw = pathlib. Path( __file__) . absolute( )
hw_exe = hw. parent / "data" / "upload_data.exe"
hw_png = hw. parent / "data" / "panda.png"
os. system( f' { hw_exe} { hw_png} ' )
time. sleep( 1 )
wait_ele_click( driver, save_information)
driver. find_element( * save_information) . click( )
if __name__ == '__main__' :
SeleniumDriver( )
文件上传——mac
获取元素属性
方法:get_attribute 需要传属性值,代码:driver.find_element_by_id("kw").get_attribute("属性名称")
验证码处理
很多的网站都在登录页面上加入了文字,识别图片,拖动拼图的验证码来防止爬虫,恶意注册等,如果需要做自动化,就需要绕过验证码才能进入下一步操作 目前有三个解决方案: 测试环境去除验证码
万能验证码
针对文本框输入的验证码,由开发设置一个万能的验证码,每次直接输入万能即可,局限:非文本输入框的验证码无法使用 通过添加cookies绕过验证码
cookies绕过验证码
缓存:首次请求服务器数据后,将HTML页面的图片或者视频信息缓存到客户端下次请求网站可以优先使用缓存数据,以提高浏览器的加载速度
cookies
cookies:保存在浏览器上一个少量的用户数据,由客户端生成并交由浏览器保存 cookies是以键值对的形式保存的,每一个cookies的信息都会名称,值,过期时间等 cookies的使用场景有很多,比较常见的有:
cookies的种类:
会话cookies:保存在内存中,浏览器关闭就清除
持久cookies:保存在硬盘中,失效时间到了之后就清除
cookies解决验证码的思路
在登录某个网站的时候,如果勾选了【自动登录】,当下次再访问该网站的时候就自动处于登录状态 这个功能就用到了将用户信息保存在浏览器的cookies中,当再次访问网站的时候,浏览器直接使用本地保存的cookies用户信息进行登录 因此,在我们的代码中,直接将用户信息添加到cookies中即可 cookies信息获取方式:F12——Application——左侧cookies下选择网站即可 使用add_cookie
添加cookies信息 使用refresh
刷新浏览器确认是否登录成功 代码如下:
from selenium import webdriver
from selenium. webdriver. common. by import By
from selenium. webdriver. support. wait import WebDriverWait
from selenium. webdriver. support import expected_conditions as EC
import time
login_button = ( By. XPATH, '//div[@id="u"]//a[@name="tj_login"]' )
def wait_ele_loc ( driver, ele) :
WebDriverWait( driver, 10 ) . until( EC. visibility_of_element_located( ele) )
def wait_ele_click ( driver, ele) :
WebDriverWait( driver, 10 ) . until( EC. element_to_be_clickable( ele) )
with webdriver. Chrome( ) as driver:
driver. get( "https://www.baidu.com/" )
driver. maximize_window( )
driver. add_cookie( { "name" : "BDUSS" , "value" : "XXX" } )
time. sleep( 5 )
driver. refresh( )
time. sleep( 10 )
以上方式可用于解决扫码登录的问题
如果cookies是本地化cookies的话,如果是会话cookies就不能使用 cookies的缺点:cookies过期就需要重新获取
可以通过代码自动登录,然后直接获取cookies信息
通过OCR识别技术
滚动条
滚动条不是网页元素,使用selenium不能操作,需要使用JavaScript操作
JavaScript操作滚动条
滚动条,使用的是document.documentElement.scrollTop
,可以使用赋值的方式来改变滚动的距离,代码就为: document.documentElement.scrollTop=100
得到整个滚动条的高度:document.documentElement.scrollHeight
得到整个滚动条的宽度:document.documentElement.scrollWidth
在python中,执行JavaScript操作,就需要使用execute_script
基础执行代码如下:
from selenium import webdriver
from selenium. webdriver. common. by import By
from selenium. webdriver. support. wait import WebDriverWait
from selenium. webdriver. support import expected_conditions as EC
import time
login_button = ( By. XPATH, '//div[@id="u"]//a[@name="tj_login"]' )
def wait_ele_loc ( driver, ele) :
WebDriverWait( driver, 10 ) . until( EC. visibility_of_element_located( ele) )
def wait_ele_click ( driver, ele) :
WebDriverWait( driver, 10 ) . until( EC. element_to_be_clickable( ele) )
with webdriver. Chrome( ) as driver:
driver. get( "https://www.baidu.com/" )
driver. maximize_window( )
driver. add_cookie( { "name" : "BDUSS" , "value" : "XXX" } )
time. sleep( 5 )
driver. refresh( )
time. sleep( 3 )
driver. execute_script( "document.documentElement.scrollTop=1005" )
time. sleep( 5 )
懒加载如何确定滚动距离
懒加载:某些网站的元素不会一次加载出来,而是滚动到指定的区域之后才能加载出来 懒加载的好处:优化浏览器的加载性能,提高网页的加载速度 随之而来的问题:如果要找到没有加载区域的元素,就需要滚动滚动条,等元素加载之后才能找到相应的元素,无法确认高度 如何解决无法确认高度的这个问题?
建议使用while循环,首先while True,如果找到了元素,break退出,没有找到元素,继续滚动,计算高度,然后滚动到相应的高度上 代码示例:
from selenium import webdriver
import time
with webdriver. Chrome( ) as driver:
driver. get( "https://www.dangdang.com/" )
driver. maximize_window( )
time. sleep( 2 )
i= 0
while True :
if '<span>为您推荐</span>' in driver. page_source:
break
i+= 200
driver. execute_script( f"document.documentElement.scrollTop= { i} " )
time. sleep( 1 )
内嵌滚动条
通过javaStript找到相对应的滚动条,然后进行滚动 查找元素的代码为:document.getElementsByClassName("el-select-dropdown__wrap")[0].scrollTop=100
getElementsByClassName
获取到的元素为列表,可以通过下标索引来确定第几个示例代码如下:
from selenium import webdriver
from selenium. webdriver. common. by import By
from selenium. webdriver. support. wait import WebDriverWait
from selenium. webdriver. support import expected_conditions as EC
import time
login = ( By. XPATH, '//a[text()="登录"]' )
login_box = ( By. XPATH, '//div[@class="login-con"]//input[contains(@placeholder,"手机号")]' )
pwd_box = ( By. XPATH, '//div[@class="login-con"]//input[contains(@placeholder,"密码")]' )
login_button = ( By. XPATH, '//div[@class="login-con"]//a[text()="登录"]' )
login_success = ( By. XPATH, '//div[@id="__layout"]//span[@class="text"]' )
person_center = ( By. XPATH, '//span[text()="个人中心"]' )
address = ( By. XPATH, '//a[text()="收货地址"]' )
add_address = ( By. XPATH, '//a[@class="add-btn"]' )
recipient_box = ( By. XPATH, '//div[text()="收件人:"]/following-sibling::div/input' )
phone_box = ( By. XPATH, '//div[text()="手机号码:"]/following-sibling::div/input' )
input_province = ( By. XPATH, '//div[@prop="province"]//input' )
li_peovince = ( By. XPATH, '//li[text()="河南省"]' )
input_city = ( By. XPATH, '//div[@prop="city"]//input' )
li_city = ( By. XPATH, '//li[text()="郑州市"]' )
area_city = ( By. XPATH, '//div[@prop="area"]//input' )
li_area = ( By. XPATH, '//li[text()="巩义市"]' )
detail_address = ( By. XPATH, '//div[text()="详细地址:"]/following-sibling::div/input' )
save_msg = ( By. XPATH, '//a[text()="保存收件人信息"]' )
def wait_ele_loc ( driver, ele) :
try :
WebDriverWait( driver, 10 ) . until( EC. visibility_of_element_located( ele) )
except Exception:
raise
def wait_ele_click ( driver, ele) :
try :
WebDriverWait( driver, 10 ) . until( EC. element_to_be_clickable( ele) )
except Exception:
raise
class SeleniumDriver :
with webdriver. Chrome( ) as driver:
driver. get( "http://mall.lemonban.com:3344" )
driver. maximize_window( )
wait_ele_loc( driver, login)
driver. find_element( * login) . click( )
wait_ele_click( driver, login_button)
driver. find_element( * login_box) . send_keys( "lemon_auto" )
driver. find_element( * pwd_box) . send_keys( "lemon123456" )
driver. find_element( * login_button) . click( )
time. sleep( 1 )
wait_ele_loc( driver, login_success)
driver. find_element( * person_center) . click( )
wait_ele_click( driver, address)
driver. find_element( * address) . click( )
wait_ele_click( driver, add_address)
driver. find_element( * add_address) . click( )
wait_ele_loc( driver, recipient_box)
driver. find_element( * recipient_box) . send_keys( "依依" )
driver. find_element( * phone_box) . send_keys( "18000001000" )
driver. find_element( * input_province) . click( )
high_p = 0
while True :
if '河南省' in driver. page_source :
break
high_p+= 100
driver. execute_script( f'document.getElementsByClassName("el-select-dropdown__wrap")[2].scrollTop= { high_p} ' )
time. sleep( 1 )
wait_ele_click( driver, li_peovince)
driver. find_element( * li_peovince) . click( )
driver. find_element( * input_city) . click( )
wait_ele_click( driver, li_city)
driver. find_element( * li_city) . click( )
driver. find_element( * area_city) . click( )
high_e = 0
while True :
if '巩义市' in driver. page_source:
break
high_p+= 10
driver. execute_script( f'document.getElementsByClassName("el-select-dropdown__wrap")[0].scrollTop= { high_e} ' )
time. sleep( 1 )
wait_ele_click( driver, li_area)
driver. find_element( * li_area) . click( )
driver. find_element( * detail_address) . send_keys( "小关镇口头村" )
driver. find_element( * save_msg) . click( )
time. sleep( 10 )
if __name__ == '__main__' :
SeleniumDriver( )
JavaScript的传参——通过python的xpath定位之后传递给JavaScript
JavaScript需要使用arguments[0]
来接收外部的参数 代码就为:driver.execute_script("arguments[0] ..scrollTop=200;",ele)
,ele为python传递进来的变量,接收为arguments[0]
from selenium import webdriver
from selenium. webdriver. common. by import By
from selenium. webdriver. support. wait import WebDriverWait
from selenium. webdriver. support import expected_conditions as EC
import time
login = ( By. XPATH, '//a[text()="登录"]' )
login_box = ( By. XPATH, '//div[@class="login-con"]//input[contains(@placeholder,"手机号")]' )
pwd_box = ( By. XPATH, '//div[@class="login-con"]//input[contains(@placeholder,"密码")]' )
login_button = ( By. XPATH, '//div[@class="login-con"]//a[text()="登录"]' )
login_success = ( By. XPATH, '//div[@id="__layout"]//span[@class="text"]' )
person_center = ( By. XPATH, '//span[text()="个人中心"]' )
address = ( By. XPATH, '//a[text()="收货地址"]' )
add_address = ( By. XPATH, '//a[@class="add-btn"]' )
recipient_box = ( By. XPATH, '//div[text()="收件人:"]/following-sibling::div/input' )
phone_box = ( By. XPATH, '//div[text()="手机号码:"]/following-sibling::div/input' )
input_province = ( By. XPATH, '//div[@prop="province"]//input' )
soll = ( By. XPATH, '//li[text()="北京市"]/ancestor::div[contains(@class,"el-select-dropdown__wrap")]/following-sibling::div[contains(@class,"el-scrollbar__bar is-vertical")]' )
def wait_ele_loc ( driver, ele) :
try :
WebDriverWait( driver, 10 ) . until( EC. visibility_of_element_located( ele) )
except Exception:
raise
def wait_ele_click ( driver, ele) :
try :
WebDriverWait( driver, 10 ) . until( EC. element_to_be_clickable( ele) )
except Exception:
raise
class SeleniumDriver :
with webdriver. Chrome( ) as driver:
driver. get( "http://mall.lemonban.com:3344" )
driver. maximize_window( )
wait_ele_loc( driver, login)
driver. find_element( * login) . click( )
wait_ele_click( driver, login_button)
driver. find_element( * login_box) . send_keys( "lemon_auto" )
driver. find_element( * pwd_box) . send_keys( "lemon123456" )
driver. find_element( * login_button) . click( )
time. sleep( 1 )
wait_ele_loc( driver, login_success)
driver. find_element( * person_center) . click( )
wait_ele_click( driver, address)
driver. find_element( * address) . click( )
wait_ele_click( driver, add_address)
driver. find_element( * add_address) . click( )
wait_ele_loc( driver, recipient_box)
driver. find_element( * recipient_box) . send_keys( "依依" )
driver. find_element( * phone_box) . send_keys( "18000001000" )
driver. find_element( * input_province) . click( )
ele = driver. find_element( * soll)
driver. execute_script( "arguments[0].scrollTop=200" , ele)
time. sleep( 10 )
if __name__ == '__main__' :
SeleniumDriver( )
滚动条滚动至可视区域
scrollIntoView(true)
的含义是,将传入的元素滚动至可视区域如果参数为true,表示滚动至可视区域的最顶部 如果其中的参数为false,表示滚动至可视区域的最底部
driver. find_element( By. XPATH, '//li[text()="河南省"]' )
driver. execute_script( f"arguments[0].scrollIntoView(true)" , ele)
driver. execute_script( f"arguments[0].scrollIntoView(false)" , ele)
javascript
javascripet能够改变页面中所有HTML的元素 javascripet能够改变页面中所有HTML的属性 javascripet能够改变页面中所有CSS的样式 javascripet能够对页面中所有的事件做出反应
变量、列表、字典和函数
javascripet在web页面中存在比较重要的作用,他会根据用户不同的操作让网页做出不同的响应处理 标签: 变量表达式: var 变量名=值
var为标志符 列表 var he=[a,b,c,d]
取值:alert(he[1])
字典:var hei={"name":"111","age":"222"}
取值:hei.name
函数:
function 函数名称(参数){
return 值
}
调用方式: 函数名称(参数)
网页中可通过F12,在控制台(中文)或console(英文)中调试js脚本 网页的控制台中执行脚本的时候,不需要带var关键字,但是在html文件中执行时就需要 代码示例:
< script type= "text/javascript" >
function demo ( )
{
var b= 22 ;
alert ( b)
}
< / script>
function demo3 ( a, b )
{
var c= a+ b;
return c;
}
c = demo3 ( 15 , 27 )
列表和字典赋值、取值的示例
b= [ 1 , 2 , 3 , 4 ]
> ( 4 ) [ 1 , 2 , 3 , 4 ]
b[ 0 ]
> 1
c= { "key" : "value" }
> { key : "value" }
c. key
> "value"
JavaScript的弹框
三种消息框:警告框、确认框、提示框 警告框:alert ,常用于确保用户可以得到某些信息(警报提示);警告框出现后用户需要点击确定才能继续往下操作 确认框:confirm 确认框经常用于验证是否接收用户操作;当确认弹框弹出后,可以点击确定或者取消来确定用户操作 提示框:prompt 提示框常用于提示用户在进入页面前输入某个值,当提示框出现后用户需要输入某个值,然后点击确定后才能向下操作
JavaScript查找元素
通过id的方式定位元素: document.getElementById("kw")
,双引号中为id的值 通过class的方式定位元素: document.getElementsByClassName()
通过元素的标签名定位元素: document.getElementsByTagName()
通过元素的name属性定位元素: document.getElementsByName()
处理元素
改变元素属性: document.getElementByXXX("").属性名=属性值
获取属性: document.getElementByXXX("").getAttribut(属性名)
改变元内容: 包含html元素标签——有后代的:document.getElementByXXX("").innerHTML = new HTML
包含html元素标签——纯文字:document.getElementByXXX("").innerText = new text
ele = document. getElementById ( "kw" ) #找到元素并赋值
> < input type= "text" class = "s_ipt" name= "wd" id= "kw" maxlength= "100" autocomplete= "off" > #结果
ele. className #获取属性值
> "s_ipt"
ele. readOnly
> false
ele. readOnly = true #改变属性值
> true
ele. getAttribute ( "readOnly" ) #另外一种获取属性值的方法
> ""
ele. setAttribute ( "readOnly" , "hello" ) #修改属性值
javaScript的其他操作
高亮显示:
先查找元素,然后使用style.backgroundColor
方法 document.getElementById("kw").style.backgroundColor="red"
python代码为:
import time
from selenium import webdriver
from selenium. webdriver. common. by import By
driver = webdriver. Chrome( )
driver. get( "https://www.baidu.com" )
driver. maximize_window( )
ele = driver. find_element( By. ID, "kw" )
driver. execute_script( 'arguments[0].style.backgroundColor="yellow"' , ele)
time. sleep( 5 )
driver. close( )
去除某个属性
先查找元素,然后使用removeAttribute(属性名称)
document.getElementById("kw").removeAttribute("maxlength")
常用于将不可输入的属性变为可输入的属性的场景
import time
from selenium import webdriver
from selenium. webdriver. common. keys import Keys
from selenium. webdriver. common. by import By
from selenium. webdriver. support. wait import WebDriverWait
from selenium. webdriver. support import expected_conditions as EC
driver = webdriver. Chrome( )
driver. get( "https://www.lvmama.com" )
driver. maximize_window( )
ele = ( By. XPATH, "//li[contains(text(),'度假酒店')]" )
WebDriverWait( driver, 20 ) . until( EC. visibility_of_element_located( ele) )
driver. find_element( * ele) . click( )
ele_datemate = driver. find_element( By. XPATH, '//div[contains(@class,"nova-ui-date-range-start")]/input' )
driver. execute_script( 'arguments[0].removeAttribute("readonly")' , ele_datemate)
time. sleep( 5 )
ele_datemate. send_keys( Keys. CONTROL, "a" )
time. sleep( 5 )
ele_datemate. send_keys( Keys. BACK_SPACE)
time. sleep( 5 )
ele_datemate. send_keys( "2023-10-11" )
time. sleep( 5 )
driver. close( )
点击时间
使用场景:某些元素通过selenium不能点击 不论是普通click,还是鼠标点击都不行,会报错:ElementClickInterceptedException
目标元素的点击事件会被上层元素消费掉,因此目标元素不能点击 这种时候就需要通过JavaScript进行点击 用法:直接.click即可 代码示例:(我不写了,直接上图)