zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    关于shell输出的一些问题
    python一些问题
    excel
    梁先生家书摘录
    使用conda安装requirement.txt指定的依赖包
    Matplotlib 的默认颜色 以及 使用调色盘调整颜色
    各种 Shell 的使用
    将实验数据保存到txt文件中
    机器学习-学习资源
    Gvim 的使用
  • 原文地址:https://www.cnblogs.com/andy9468/p/10907741.html
Copyright © 2011-2022 走看看