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-登陆失败...')
View Code

②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

 

posted @ 2019-05-22 18:29  安迪9468  阅读(1173)  评论(0编辑  收藏  举报