1.起
最近重新使用以前写的selenium模拟登陆,登陆淘宝发现出现了问题。在网上搜索了一番大多数都说是淘宝会检测window.navigator.webdriver。当使用selenium打开时会被设置为True,而普通模式下则是undefined。实验如下
图1是手动开启淘宝页面所以显示undefined,图3是使用了selenium打开的显示了True,那图2为何会显示undefined呢?,其实只不过是在代码里把chrome浏览器变成开发者模式即可。经过实验发现图2通过手动输入帐号密码验证后依然可以登录到淘宝,而使用图3的方法再输入完账号密码后,拉动验证的时候是会显示出错的。也就是说我们无需使用网上说mitmproxy做中间人代理,那么不是凭借着开发者模式就可以模拟登录了吗?
2.承
答案是不可以的,使用如下代码做实验
from
手动切换
browser.get('https://login.taobao.com/member/login.jhtml')
from selenium import webdriver as wb
options=wb.ChromeOptions()
options.add_experimental_option('excludeSwitches', ['enable-automation'])#切换到开发者模式
browser=wb.Chrome(options=options)
browser.get('https://login.taobao.com/member/login.jhtml')
login_switch=browser.find_element_by_css_selector("#J_Quick2Static") #通过id找到那个从扫码登录切换的密码登录的
selenium切换
于是很有意思的一件事情发生了,使用第一段代码手动切换到帐号密码登录模式没问题验证通过。当尝试第二段代码的时候事情发生了,第二段代码只是去寻找网页里的一个元素,这时候淘宝就可以识别出来了,这不是正常的登录行为,就算手动输入账号密码验证也会失败。这是因为淘宝使用了ua加密算法,来分析用户登录状态是否异常,使用selenium肯定是异常登录,所以服务器会返回code=300,然后拉动滑块后会显示验证失败。所以使用selenium模拟登录失败的根本原因并不是拉动滑块是匀速的而检测失败。这个在后面也会验证。在知道了ua算法屏蔽以后,上网查了很久,也没找到绕过ua的方法(如果有可以评论告诉我,是我孤陋寡闻了)。那到底应该怎么绕过?
3.转
之前已经说过,使用开发这模式下的selenium不找节点的话手动登录是可以成功的,那么可不可以,在登录页面手动登录,然后跳转淘宝首页的时候,再用selenium里的方法搜索节点呢?于是乎又用一下代码做了实验
from selenium import webdriver as wb
from selenium.webdriver.support.ui import WebDriverWait as wdw
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import time
options=wb.ChromeOptions()
options.add_experimental_option('excludeSwitches', ['enable-automation'])#切换到开发者模式
browser=wb.Chrome()
browser.get('https://login.taobao.com/member/login.jhtml')
time.sleep(10) #利用这段时间手动登录,在转到淘宝首页
wait=wdw(browser,10)
input=wait.until(EC.presence_of_element_located((By.ID,'q'))) #获取搜索框
input.send_keys('iPhone') #输入iphone
答案居然是. (o゜▽゜)o☆[BINGO!] 可以!!完全跟我想的一样,成了!
那么就是说明,淘宝在登录的时候会限制selenium,但是登录完以后就可以使用selenium了,那么模拟登录要解决的问题就是把手动登录改为自动登录咯。也就是说用python操作鼠标键盘就可以做到了。于是通过google查到了一个叫做pyautogui的库,下面说一下pyautogui的安装方法,直接在cmd输入
pip3 install pyautogui
在这期间遇到了一点点小问题,cmd里显示
UnicodeDecodeError: 'gbk' codec can't decode byte 0xa2 in position 905: ille gal multibyte sequence
具体的原因不知道,但是知道解决办法把pip3降低版本就可了,如下
pip3 install PyGetWindow==0.0.1
有了pyautogui之后,在我们使用selenium打开如下画面后,我们主要做到,
1.自动点击切换登录方式按钮,
2.自动输入账号密码
3.自动拖动拉条,
4.自动点击登录
这里说一下要用到的pyautogui的方法
- pyautogui.PAUSE=0.5 设置每个动作的等待时间,防止上个动作未完成,接切换到下个动作
- pyautogui.moveTo(left,top) 鼠标移动到指定坐标函数,left和top在左上角时为left=0,top=0
- pyautogui.click() 鼠标点击操作
- pyautogui.typewrite(text) 输入字符串操作
- pyautogui.press(button) 键盘按下松开操作
- pyautogui.locateOnScreen(path) 截图定位操作,path表示该截图的位置,要使用‘/’代替 ‘’,返回值为left,top,width,length指向截图的中心
4.合
代码过程
1.使用到的库
from selenium import webdriver as wb
import pyautogui
2.打开淘宝
pyautogui.PAUSE=0.5 #设置每个动作0.2s太快来不及输入密码
options=wb.ChromeOptions()
options.add_experimental_option('excludeSwitches', ['enable-automation'])#切换到开发者模式
browser=wb.Chrome(options=options)
browser.maximize_window() #窗口最大化保证坐标正确
browser.get('https://login.taobao.com/member/login.jhtml')
3.截取淘宝的登录切换按钮,用windows自带的截图工具,QQ截图无效,然后定位出截图在页面中的位置,通过坐标的偏移指向切换登录按钮,在调用鼠标点击完成。完成后鼠标的焦点是在帐号框里直接输入帐号,在调用press方法按下tab,焦点转到密码处,直接输入密码。
因为真正的登录页面是分为绿色和蓝色的所以截取两张,然后用try except尝试获取坐标。这里之所直接注释,是因为之前已经获取过了,知道切换登录按钮的坐标在哪里,就直接用了。
#try:
#left,top,width,height=pyautogui.locateOnScreen('G:/jupyter project/淘宝/login_switch_blue.PNG')
#except:
#left,top,width,height=pyautogui.locateOnScreen('G:/jupyter project/淘宝/login_switch_green.PNG')
#获取login_switch位置,先尝试获取蓝色,获取不到就试绿色
moveToX=1484 #切换登录按钮的X坐标
moveToY=297 # #切换登录按钮的Y坐标
pyautogui.moveTo(1484,297) #移动到切换登录的位置
pyautogui.click() #点击切换按钮
pyautogui.typewrite(username) #输入用户名
pyautogui.press('tab')
pyautogui.typewrite(password) #输入密码
4.拖动滑条,滑条同样也分为绿色和蓝色,有时候还是会出现不需要滑条的情况,这样子登录按钮的位置,就会不一样了,所以并不能提前定位出滑条的位置,只能老老实实用locateOnScreen,这也是拖慢整个速度的原因。且这里并没有设置变速滑动,而是直接匀速滑动,一样可以通过检验
errorType
设置errorType的原因是因为,防止出现没有滑块的原因,没有滑块的话就直接点击登录即可,同样登录位置事先已经找到。代码中的注释已经说的很详细了,至此完成登录,效果就是开头的图,再放一次。
P.S在打开浏览器的时候,一定要让焦点在浏览器上,这样pyautogui才能识别图片的位置
完整代码
from selenium import webdriver as wb
from selenium.webdriver import ActionChains
from selenium.webdriver.support.ui import WebDriverWait as wdw
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import time
import pyautogui
def __login__(username,password,pathA,pathB):
pyautogui.PAUSE=0.5 #设置每个动作0.2s太快来不及输入密码
options=wb.ChromeOptions()
options.add_experimental_option('excludeSwitches', ['enable-automation'])#切换到开发者模式
browser=wb.Chrome(options=options)
browser.maximize_window() #窗口最大化保证坐标正确
browser.get('https://login.taobao.com/member/login.jhtml')
#try:
#left,top,width,height=pyautogui.locateOnScreen('G:/jupyter project/淘宝/login_switch_blue.PNG')
#except:
#left,top,width,height=pyautogui.locateOnScreen('G:/jupyter project/淘宝/login_switch.PNG') 获取login_switch位置
moveToX=1484
moveToY=297
pyautogui.moveTo(1484,297) #移动到切换登录的位置
pyautogui.click() #点击切换按钮
pyautogui.typewrite(username)
pyautogui.press('tab')
pyautogui.typewrite(password)
errorType=0
try:
left,top,width,height=pyautogui.locateOnScreen(pathA)
print('识别蓝色')
moveToX=left+140
moveToY=top+15
print(moveToX,moveToY)
pyautogui.moveTo(moveToX,moveToY)
pyautogui.mouseDown()
moveToX=moveToX+300
pyautogui.moveTo(moveToX,moveToY)
pyautogui.mouseUp()
pyautogui.moveTo(moveToX-250,moveToY+60)
pyautogui.mouseDown()
pyautogui.mouseUp()
except:
errorType=1 #识别不出蓝色
if errorType==1:
try:
left,top,width,height=pyautogui.locateOnScreen(pathB)
moveToX=left+110
moveToY=top+13
print('识别绿色')
print(moveToX,moveToY) #1299 497
pyautogui.moveTo(moveToX,moveToY)
pyautogui.mouseDown()
moveToX=moveToX+300
pyautogui.moveTo(moveToX,moveToY)
pyautogui.mouseUp()
pyautogui.moveTo(moveToX-250,moveToY+60)
pyautogui.mouseDown()
pyautogui.mouseUp()
except:
errorTye=2 #识别不出绿色
if errorType==2:
print('没有滑块')
pyautogui.moveTo(1189,497)
pyautogui.mouseDown()
pyautogui.mouseUp()
return browser #返回浏览器当前的页面
if __name__=='__main__':
browser=__login__('你的账号','你的密码','G:/jupyter project/淘宝/block_blue.PNG','G:/jupyter project/淘宝/block_green.PNG')
如果觉得有用或者有错的话,可以帮我点个赞或者评论一下,投个币(不好意思B站玩多了=-=)。另外如果又不懂的地方或者爬虫的单子可以加我QQ498721954,注明爬虫。
要是人多看的话,我下面会教大家怎么做一个稳定点的代理池,我的代理池里面又70多个都是已经检测几十次还能用的代理ip,毕竟爬淘宝没有多点ip怎么爬呢。╮(╯3╰)╭