来点接地气的,继续部门的老 web 自动化框架解读,这次里面一些偏方
因为自动化是根据不同的 hosts 来确定对应版本环境,所以要进行清理上次运行的代理、dns 缓存,于是有以下代码片段(修改注册表)
import os
cmd_switchProxy="chcp 65001 & reg add \"HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\" /v ProxyEnable /t REG_DWORD /d 0 /f & "+ \
"reg add \"HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\" /v ProxyServer /d \"\" /f & "+ \
"ipconfig /flushdns"
with os.popen(cmd_switchProxy,"r") as f: print('清理系统代理及dns缓存:',f.read())
chromedriver 打开 chrome 默认会打开一个 trigger 页面,让人心烦,同样也是修改注册表来关闭它
import os
cmd_closeTrigger="chcp 65001 & reg delete HKEY_CURRENT_USER\Software\Google\Chrome\TriggeredReset /f"
with os.popen(cmd_closeTrigger,"r") as f:print('关闭chrome的Trigger页面:',f.read())
webdriver 可以执行 js 和异步 js,但貌似无法执行 ajax,于是有如下模拟 ajax 的方法。
方法比较简单:利用 requests 库 +webdriver 获取 cookie 字符串 + 特殊请求头而已,这样可以模拟 ajax 执行一些请求了
import requests
def getAjaxedRequsetSession(driver:webdriver,proxy_ip:str,proxy_port:int) -> requests.Session:
cookies=driver.get_cookies()
cookieString="; ".join([c["name"]+"="+c["value"] for c in Cookie])
requestSession=requests.Session()
requestSession.trust_env=False
requestSession.headers.update(
{
'User-Agent': "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4478.0 Safari/537.36",
'Cookie': cookieString,
'x-requested-with':'XMLHttpRequest',
'Sec-Fetch-Site': 'same-origin'
}
)
if proxy_ip and proxy_port:
requestSession.proxies={
'http':'http://%s:%d'%(proxy_ip,proxy_port),
'https':'https://%s:%d'%(proxy_ip,proxy_port)
}
return requestSession
一些人转到新打开的窗口都是通过 title 来定位,但如果 title 重复、没有 title 咋办?
方法也比较简单:先获取当前窗口的句柄列表,执行某个操作后,再获取之后的的窗口句柄列表,找到多出来的那个就好了。
打开新窗口一般都是点击操作,而且一般是打开一个窗口(其他情况是反人类的)
以下方法 通过点击元素跳转到新的窗口,并返回原窗口的句柄,便于操作完成返回原先窗口
def switchToNewWindowByClick(driver:webdriver,element:WebElement):
"""
通过点击元素跳转到新的窗口
:param element:
:return:
"""
currentHandle = driver.current_window_handle
preAllHandles = set(driver.window_handles)
element.click()
time.sleep(5)
nxtAllHandles = set(driver.window_handles)
newHandles=nxtAllHandles.difference(preAllHandles)
if len(newHandles)<1:
return False,currentHandle
newWindow=newHandles.pop()
try:
driver.switch_to.window(newWindow)
return True,currentHandle
except NoSuchWindowException as nswe:
print(nswe.msg)
traceback.print_exc()
return False,currentHandle
测试环境的 ssl 证书错误比较烦人,一般要忽略证书错误来做,方法也能百度到,如下:
firefox 的
GeckodriverDriverPath="Geckodriver的路径"
firefoxProfiles=[
("network.http.phishy-userpass-length", 255),
("webdriver_assume_untrusted_issuer",False),
]
firefox_profile = webdriver.FirefoxProfile()
for profile in firefoxProfiles:
firefox_profile.set_preference(profile[0],profile[1])
driver = webdriver.Firefox(executable_path=GeckodriverDriverPath,firefox_profile=firefox_profile)
chrome 的
ChromeDriverPath="chromedriver的路径"
chromeOptions=['--demo-type','--ignore-certificate-errors']
for option in chromeOptions:
chrome_options.add_argument(option)
driver = webdriver.Chrome(executable_path=ChromeDriverPath,options=chrome_options)
假如有这样一个元素:<div> "双",'单' </div>
。那 xpath 应该怎样写?
【1】是//div[contains(text(),"A")]
或者//div[contains(text(),'B')]
格式吗
A、B 中内容有单双引号,与包裹他们的双、单引号是冲突的,xpath 中可不认转义符\"或\',所以不可行
【2】投机取巧//div[contains(text(),'"双",') and contains(text(),"'单'") ]
这种方法只能特殊情况特殊处理,不具备普遍性,不适合用于自动化框架中
【3】利用 concat 函数是正确方法,如://div[contains(text(),concat('"双"',",'单'")) ]
生成的字符串方式会很多,通用方法是将单/双引号做分割符,然后再拼接。于是有了如下方法:
def fixXpathText(text:str):
"""
处理用xpath文本使用text()定位时,里面包含单引号、双引号情况
生成xpath中的字符串
:param text:
:return:
"""
x=text.split('"')
if len(x)==1:
return "\""+text+"\""
y=[]
for s in x[:-1]:
y.append(s)
y.append('"')
y.append(x[-1])
ts="concat("
te=")"
for t in y[:-1]:
if "\""==t:
ts+="'\"',"
continue
ts+="\""+t+"\","
if "\""==y[-1]:
ts+="'\"',"
else:
ts+="\""+y[-1]+"\""
return ts+te
效果如下(虽不精炼,但够用)