selenium实现登录百度(自动识别简单验证码)
需要做的工作
0、工程结构
1、代码:
①baidu_login.py
1 import re 2 import os 3 import sys 4 import time 5 import random 6 from selenium import webdriver 7 from PIL import Image, ImageEnhance 8 import pytesseract 9 from func import base642str, str2base64 10 11 12 def input_account(account='请传入账号参数', xpath_rule="//input[@id='TANGRAM__PSP_3__userName']"): 13 '''模拟输入账号 14 :param account: 账号 15 :param xpath_rule: 账号输入框的xpath定位规则 16 :return: 17 ''' 18 input_box1 = driver.find_element_by_xpath(xpath_rule) 19 input_box1.send_keys(account) 20 time.sleep(0.5) 21 22 23 def input_pwd(pwd, xpath_rule="//input[@id='TANGRAM__PSP_3__password']"): 24 '''模拟输入密码 25 :param account: base64后的密码 26 :param xpath_rule: 密码输入框的xpath定位规则 27 :return: 28 ''' 29 input_box2 = driver.find_element_by_xpath(xpath_rule) 30 input_box2.clear() # 清空密码 31 input_box2.send_keys(base642str(pwd)) 32 time.sleep(0.5) 33 34 35 def input_verify_code(verify_code, xpath_rule="TANGRAM__PSP_3__verifyCode"): 36 '''模拟输入验证码 37 :param account: base64后的密码 38 :param xpath_rule: 密码输入框的xpath定位规则 39 :return: 40 ''' 41 driver.find_element_by_id(xpath_rule).send_keys(verify_code.strip()) 42 time.sleep(0.5) 43 44 45 def identify_verify_code(rootpath, pic_name="screenImg.png"): 46 '''tesseract识别百度验证码 47 :param rootpath: 验证码图片保存的文件夹路径 48 :param pic_name: 验证码图片保存的文件名 49 :return: 识别后的验证码文本 50 ''' 51 # 截图或验证码图片保存地址 52 screenImg = os.path.join(rootpath, pic_name) 53 # 浏览器页面截屏 54 time.sleep(3) 55 driver.get_screenshot_as_file(screenImg) 56 # 定位验证码位置及大小 57 location = driver.find_element_by_id('TANGRAM__PSP_3__verifyCodeImg').location 58 size = driver.find_element_by_id('TANGRAM__PSP_3__verifyCodeImg').size 59 left = location['x'] 60 top = location['y'] 61 right = location['x'] + size['width'] 62 bottom = location['y'] + size['height'] 63 # 从文件读取截图,截取验证码位置再次保存 64 img = Image.open(screenImg).crop((left, top, right, bottom)) 65 img = img.convert('L') # 转换模式:L | RGB 66 img = ImageEnhance.Contrast(img) # 增强对比度 67 img = img.enhance(2.0) # 增加饱和度 68 img.save(screenImg) 69 print("图片验证码以保存:%s" % screenImg) 70 # 再次读取识别验证码 71 print("开始读取识别图片验证码:%s" % screenImg) 72 img = Image.open(screenImg) 73 verifycode = pytesseract.image_to_string(img) 74 print("识别结果:%s" % verifycode) 75 return verifycode 76 77 78 def click_a_link(xpath_rule="//p[@id='TANGRAM__PSP_3__footerULoginBtn']"): 79 '''点击一个链接 80 :param xpath_rule: 被点击链接的xpath定位规则 81 :return: 82 ''' 83 input_box0 = driver.find_element_by_xpath(xpath_rule) 84 input_box0.click() 85 86 87 def click_a_id_link(id_rule="TANGRAM__PSP_3__verifyCodeChange"): 88 '''点击一个链接 89 :param id_rule: 被点击链接的id定位规则 90 :return: 91 ''' 92 input_box0 = driver.find_element_by_id(id_rule) 93 input_box0.click() 94 95 96 def is_need_verify_code(): 97 '''判断是否需要验证码 98 :return: 需要验证码返回True,否则False 99 ''' 100 imgsrc = driver.find_element_by_id("TANGRAM__PSP_3__verifyCodeImg").get_attribute('src') 101 if re.match(r'https://passport.baidu.com/cgi-bin/genimage.*', imgsrc): 102 return True 103 else: 104 return False 105 106 107 def get_id_node_text(id_rule="TANGRAM__PSP_3__error"): 108 '''获取id节点提示信息 109 :param id_rule:id节点的id匹配规则(id属性的值) 110 :return:该id节点中的文本信息 111 ''' 112 one_node = driver.find_element_by_id(id_rule) 113 text_info = one_node.text 114 return text_info 115 116 117 def is_login_success(): 118 '''判断登录是否成功 119 :return: 登录成功返回True,否则False 120 ''' 121 current_title = driver.title.strip() 122 if current_title.startswith("登录"): 123 return False 124 else: 125 return True 126 127 128 def deal_much_pop_up_window(): 129 '''处理手机验证码认证反复弹窗 130 :return: 131 ''' 132 i = 0 133 while True: # 处理手机验证码认证反复弹窗 134 try: 135 one3_click = driver.find_element_by_id("TANGRAM__%s__header_a" % (22 + i)) # 22+i在应对弹窗的关闭按钮id名称发生变化。 136 except Exception as e: 137 print("无需手机验证码") 138 break 139 else: 140 print("第 %s 次弹出安全验证,要求获取手机验证码" % (i + 1)) 141 time.sleep(0.5) 142 print("1s后自动选择无需手机验证码") 143 time.sleep(1) 144 one3_click.click() 145 print("1s后自动点击登陆") 146 time.sleep(1) 147 click_a_link(xpath_rule="//input[@id='TANGRAM__PSP_3__submit']") # 点击登录,提交表单 148 time.sleep(2) 149 # 判断是否成功登陆 150 current_title = driver.title.strip() 151 if current_title.startswith("登录"): 152 print('333-登陆失败...') 153 time.sleep(0.5) 154 print('333-2秒后自动重试...') 155 i = i + 1 156 time.sleep(2) 157 continue 158 else: 159 print("打印标题") 160 print(driver.title) 161 print('333-登录成功...') 162 sys.exit() # 程序终止 163 164 165 def deal_a_pop_up_window(xpath_rule="//input[@id='TANGRAM__PSP_27__rebindGuideCancel']"): 166 '''处理一次弹窗 167 :param xpath_rule:处理弹窗的按钮/链接的xpath匹配规则 168 :return: 169 ''' 170 # 判断是否需要手机号绑定确认 171 try: 172 # 绑定手机号确认 173 one_click = driver.find_element_by_xpath(xpath_rule) 174 except Exception as e: 175 print("无需绑定手机号确认") 176 else: 177 print("弹出了绑定手机号确认,1s后自动选择不需要") 178 time.sleep(1) 179 one_click.click() 180 181 182 if __name__ == '__main__': 183 # 将mm隐匿化 184 # print(str2base64("123456")) 185 # str1_base64="MTIzNDU2" 186 # print(base642str(str1_base64)) 187 # sys.exit() 188 189 # 账号和密码准备 190 account = random.randint(0, 1000000) # 随机数字作为账号 191 pwd = "MTIzNDU2" 192 print("account: %s" % account) 193 # 最大登录次数 194 max_login = 16 195 # 当前目录设置为根路径 196 ROOT_PATH = os.getcwd() 197 print('000-正在启用selenium...') 198 # 调用环境变量指定的PhantomJS浏览器创建浏览器对象 199 chromedriver_exe_path = os.path.join(ROOT_PATH, "chromedriver.exe") 200 driver = webdriver.Chrome(chromedriver_exe_path) 201 print('000-启用OK') 202 203 # 请求登录页面 204 url = 'https://passport.baidu.com/v2/?login' 205 print('111-selenium正在请求页面:%s' % url) 206 driver.get(url) # get方法请求页面,获取响应 207 print('111-请求OK') 208 209 print("打印标题") 210 print(driver.title) 211 212 # 点击账号和密码登录 213 click_a_link() 214 215 print('222-selenium正在填写表单...') 216 time.sleep(1) 217 # 第一次尝试登录 218 219 # 模拟填写账号 220 input_account(account) 221 222 # 模拟填写密码 223 input_pwd(pwd) 224 225 # 判断是否需要验证码 226 is_need = is_need_verify_code() 227 if is_need: # 需要验证码 228 print("需要验证码") 229 # 自动识别和模拟填写验证码 230 code = identify_verify_code(rootpath=ROOT_PATH, pic_name="screenImg.png") # 自动识别验证码 231 input_verify_code(code) # 模拟填写验证码 232 else: # 不需要验证码 233 print("不需要验证码") 234 print('222-填写表单OK') 235 time.sleep(1) 236 237 print('333-selenium提交表单...') 238 click_a_link(xpath_rule="//input[@id='TANGRAM__PSP_3__submit']") # 点击登录,提交表单 239 print("第 %s 次尝试登录" % 1) 240 time.sleep(3) 241 242 # 处理反复弹窗(手机验证码):点击关闭按钮 243 deal_much_pop_up_window() 244 # 处理一次弹窗(绑定手机号确认):点击不需要修改 245 deal_a_pop_up_window() 246 247 for login_i in range(max_login - 1): 248 # 判断是否登录成 249 is_logined = is_login_success() 250 if is_logined: 251 print("登录成功") 252 break 253 else: 254 print("第 %s 次登录失败,正在尝试重新登录..." % (login_i + 1)) 255 # 第二次尝试登录 256 print("=>第 %s 次尝试登录" % (login_i + 2)) 257 error_info = get_id_node_text() 258 if ("帐号或密码错误" in error_info) or ("用户名或密码有误"): # 第二次尝试登录2.1 259 print("正在尝试重新输入密码...") 260 # 模拟填写密码 261 input_pwd(pwd) 262 # 判断是否需要验证码 263 is_need = is_need_verify_code() 264 if is_need: 265 print("需要验证码") 266 # 点击更新验证码 267 click_a_id_link() 268 # 自动识别和模拟填写验证码 269 code = identify_verify_code(rootpath=ROOT_PATH, pic_name="screenImg.png") # 自动识别验证码 270 input_verify_code(code) # 模拟填写验证码 271 print("提示:验证码错误,js会使得提交无效") 272 else: 273 print("不需要验证码") 274 275 elif ("验证码" in error_info): # 第二次尝试登录2.2 276 print("正在尝试重新输入了验证码和密码...") 277 time.sleep(1) 278 # 模拟填写密码 279 input_pwd(pwd) 280 # 点击更新验证码 281 click_a_id_link() 282 # 自动识别和模拟填写验证码 283 code = identify_verify_code(rootpath=ROOT_PATH, pic_name="screenImg.png") # 自动识别验证码 284 input_verify_code(code) # 模拟填写验证码 285 print("提示:验证码错误,js会使得提交无效") 286 time.sleep(2) 287 288 else: 289 print("其他未知异常:登录失败") 290 sys.exit() # 程序终止 291 292 print('222-填写表单OK') 293 time.sleep(1) 294 295 print('333-selenium提交表单...') 296 click_a_link(xpath_rule="//input[@id='TANGRAM__PSP_3__submit']") # 点击登录,提交表单 297 time.sleep(3) 298 299 # 打印标题 300 print("打印标题") 301 print(driver.title) 302 time.sleep(1) 303 304 # 判断是否成功登陆 305 is_logined = is_login_success() 306 if is_logined: 307 print('333-登录成功...') 308 else: 309 print('333-登陆失败...')
②func.py
import base64 import time def timestamp2datems(timestamp): ''' 时间戳转为日期字串,精确到ms。单位s :param timestamp:时间戳 :return:日期字串 ''' local_time = time.localtime(timestamp) # data_head = time.strftime("%Y-%m-%d %H:%M:%S", local_time) data_head = time.strftime("%Y-%m-%d_%H-%M-%S", local_time) data_secs = (timestamp - int(timestamp)) * 1000 dt_ms = "%s.%03d" % (data_head, data_secs) # print(dt_ms) return dt_ms def bit2humanView(bit_val): ''' 文件大小bit转为人类易读大小bit、KB、MB :param bit_val:字节数值 :return:人类易读大小和单位 ''' is2kb = int(bit_val / 1042) # 转换为kb取整 is2mb = int(bit_val / 1024 / 1024) # 转为mb取整 is2gb = int(bit_val / 1024 / 1024 / 1024) # 转为gb取整 if is2gb is not 0: gb_val = bit_val / 1024 / 1024 / 1024 return "%.2f GB" % gb_val if is2mb is not 0: mb_val = bit_val / 1024 / 1024 return "%.2f MB" % mb_val if is2kb is not 0: kb_val = bit_val / 1024 return "%.2f KB" % kb_val return "%s bit" % bit_val def str2base64(pwd_decode_str): ''' 明文str转为base64密文 :param pwd_decode_str: 明文str :return: base64密文 ''' base64_encrypt = base64.b64encode(pwd_decode_str.encode('utf-8')) pwd_encode_str = str(base64_encrypt, 'utf-8') return pwd_encode_str def base642str(pwd_encode_str): ''' base64密文转为明文str :param pwd_encode_str: base64密文 :return: 明文str ''' base64_decrypt = base64.b64decode(pwd_encode_str.encode('utf-8')) pwd_decode_str = str(base64_decrypt, 'utf-8') return pwd_decode_str
③依赖包:requirements.txt
Pillow==6.0.0 pytesseract==0.2.6 selenium==3.141.0
2、selenium的相关支持:
①google浏览器;
②相应版本的浏览器驱动chromedriver.exe
http://npm.taobao.org/mirrors/chromedriver/
3、PIL安装:pip install pillow
4、图像识别工具:
①windows安装tesseract.exe
②python安装pytesseract