2021最新版12306网站selenium实现自动化登录

前言:

感觉12306自动化登录是所有学习爬虫爱好者都必须经过的一道练习题,但是由于12306的版本更新,很多之前的自动化登录代码或多或少有些纰漏,所以我写了2021年最新的12306自动化登录,希望对你会有所启发。

需要导入的库如下:

from selenium import webdriver
from selenium.webdriver import ActionChains
import chaojiying
import base64
import re
from lxml import etree
from time import sleep

1.进入12306界面

言不多说,直接进入正题,对于12306自动化登录,首先我们需要进入12306的官网首页,即如下图片

在这里插入图片描述
实现过程如下

url='https://www.12306.cn/index/'

bro=webdriver.Chrome(executable_path='输入自己电脑的webdriver的绝对位置即可')

bro.get(url=url)

2.进入登录界面

我们在这个图片里面的右上角可以看到登录与注册两个选项,我们需要选择登录这一选项,从而进入他的登陆页面,具体代码实现如下:

bro.find_element_by_xpath('//*[@id="J-header-login"]/a[1]').click()   

代码中我们采用webdriver的find系列,通过xpath解析从而找到‘登录’的位置。实现过程如下:在这里插入图片描述

按照图片里面数字的顺序,先左击第一个箭头所指的位置,然后左击第二个箭头所指的位置,在之后,我们需要在第三个箭头所指的位置右击,出来选项框之后,在copy那一栏里面就可以找到copy xpath,从而可以得到到‘登录’的xpath解析

3. 选择账号登陆

进入登录页面之后,我们会发现是二维码登录,我们不采用二维码登录,我们使用的是账号登录,所以我们需要点击账号登录,从而进入他的账号登录页面。 具体代码如下:

bro.find_element_by_xpath('/html/body/div[2]/div[2]/ul/li[2]/a').click()            # 点击账号登录

具体图片如下:

在这里插入图片描述

同理,也是按照图片里面数字的顺序,先左击第一个箭头所指的位置,然后左击第二个箭头所指的位置,在之后,我们需要在第三个箭头所指的位置右击,出来选项框之后,在copy那一栏里面就可以找到copy xpath,从而可以得到到‘账号登录’的xpath解析

从这个账号登录页面来看,我们需要填入用户名,用户密码以及需要识别验证码图片,接下来我们分步操作,分别完成这三项任务

4.用户名的输入

首先是用户名的输入,我们需要先定位到用户名这一栏,然后输入我们的用户名即可。具体代码如下:

bro.find_element_by_xpath('//*[@id="J-userName"]').send_keys('******账号')         # 输入账号

这个代码前面半段可以不用说,就是为了定位到用户名这一栏,而后面的send_keys的作用是将内容输入到我们定位好的浏览器的文本框里
具体操作流程如下:
在这里插入图片描述
这个图片操作流程前面已经多次重复了,这次就不讲了

5.用户密码的输入

然后是用户密码的输入,其实和用户名的输入步骤一模一样
代码如下:

bro.find_element_by_xpath('//*[@id="J-password"]').send_keys('****自己的账户密码即可')            # 输入密码

图片如下:
在这里插入图片描述

6.验证码的识别

最后是验证码的识别,验证码的识别我采用的是超级鹰第三方软件识别,可能会有其他更好更快的识别方式,这里为了简便,我用的是自己最熟悉的超级鹰识别。

准备工作:

  1. 再写这个代码之前呢,我们需要做一些准备工作,就是将超级鹰的py文件封装到一个包里面,这样我们就可以直接调用包,而不用将超级鹰的模块代码全部在复制一遍,当然,如果你不想单独放一个包,全部复制一遍也是可以的,只不过这样代码会显得比较乱。

将超级鹰模块封装到一个包里面,其实也很简单,就是在pycharm里面新建一个包,即python package,然后将超级鹰的模块代码复制到这个包下面就可以了,完成之后,其实就是这样子

在这里插入图片描述

有个最重要的一点,就是在封装之后呢,需要按照图示如下操作
在这里插入图片描述
这样pycharm就可以调用我们自己设置的包了,如果没有这个操作的话,前面我所说的导入的库里面import chaojiying这个语句就会报错,所以这个图片一定要执行哦

实现原理:
完成准备工作之后呢,我们来解释一下如何让第三方软件去识别验证码?

在这里插入图片描述
其实原理就是我们将验证码下载下来保存到指定的位置上,在保存之后,我们将保存的图片信息传递给第三方软件,在他识别之后呢?他会返回给我们x,y坐标,这些x,y坐标就是图片需要点击的x,y坐标,有一点需要注意,这些x,y是相对坐标,是相对于图片左上角(0,0)坐标而言的

最后一个知识点:

在理解这份代码之前,还有一个知识点也需要讲,就是我们在定位到验证码图片的时候,会有这样一段乱码

<img id="J-loginImg" `class="imgCode" alt="" src="data:image/jpg;base64,/9j/4AAQSkZJRgABAgAAAQABAAD/2wB........" 

这个乱码太长了,后面的我就用省略号代替了

其实第一眼见到这个乱码我也很懵逼,查询之后才知道他就是将这个图片的信息以base64的编码格式直接保存到这个html中,这样在这个html打开图片的时候,就不用再动态加载了。然后我们继续看,在这个src属性里面,‘data:image/jpg;base64,’这些符号只是告诉我们这个图片的格式为jpg,他是采用了base64编码保存的,所以其实他并不是图片信息的二进制转换成的base64编码。了解这些之后,我们就只需要将base64编码的数据解码,然后以二进制的格式保存,这样就可以得到图片原来的样子了

要使用base64解码,需要用到库为:
import base64
需要用到的指令为:
base64.b64decode()

ok,接下来我们就先将这个图片保存到本地,具体代码如下

	page = bro.page_source
	# 获得浏览器此时的html信息
    tree = etree.HTML(page)
    pic_url = tree.xpath('//*[@id="J-loginImg"]/@src')[0]
    # 通过xpath解析,将编码后的图片信息提取出来,保存到pic_url中
   
    pic_url3 = re.sub('data:image/jpg;base64,', '', pic_url1)
    # 使用正则的替换函数,将'data:image/jpg;base64,'替换成啥都没有,相当于删除这些内容,至此,我们得到了图片的base64编码的所有字符
    
    
    pic = base64.b64decode(pic_url3)
	#然后将字符进行解码
	
    with open('code.jpg', 'wb') as fp:
        fp.write(pic)
        
	# 将解码后的字符以code的文件名保存到当前文件夹中,保存格式为二进制
	ok,现在我们已经把图片保存下来了,接下来就只需要将图片接入第三方软件中,让他帮我们去识别,我们只是要等着就好了,具体代码如下:
chaojiying1 = chaojiying.Chaojiying_Client('自己注册的用户名', '用户名对应的密码', '自己注册的软件ID')  
		# 用户中心>>软件ID 生成一个替换 96001
im = open('./code.jpg', 'rb').read()  
        # 本地图片文件路径 来替换 code.jpg 有时WIN系统须要//
xy = chaojiying1.PostPic(im, 9004)['pic_str']
        #9004是我们发送的验证码的格式,然后这个指令的返回值是一个字典,在键为['pic_str']的值的时候,保存地视返回的需要点击的坐标

我们获得坐标之后呢,就要想办法分别获取每个点的x,y,上面超级鹰验证码识别可以看到他返回形式是x1,y1|x2,y2|x3,y3这样子的,所以我们可以先以’|‘符号来切片,获得各个点的列表的值,然后对于列表,我们直接使用for in循环,在使用’,'来切片获得对应点的x,y的坐标值。对于每一个坐标值,我们直接先定位到图片上,然后使用指令
action.move_to_element_with_offset(目标元素, x, y).click().perform()

指令中,目标元素就是我们图片的xpath定位元素,x,y为我们获得的x,y的坐标值,这个指令会将鼠标移动到举例定位元素x方向有x的偏移量,y方向有y的偏移量,然后点击执行

具体代码如下:

xy = xy.split(sep='|')
# 通过使用符号'|'来进行劈分,将各个点保存在设置的xy列表里面
for i in xy:
	cl = bro.find_element_by_xpath('//*[@id="J-loginImg"]')
	# 需要先定位到图片地址,cl其实就是click的简写,我就图个简单
	action.move_to_element(cl).perform()  # ——鼠标移动到某个元素
	# 将鼠标移动dao二维码图片中
	xy1 = (i.split(sep=','))
	x=int(xy1[0])
	y=int(xy1[1])
	# 分别获取x,y的值
	action.move_to_element_with_offset(cl, x, y).click().perform()
	# 就是通过刚才获得的x,y的值点击相应的位置


其实代码里面将鼠标移动到某个元素处,并不是我们所见的鼠标箭头就移动过去了,而是他就会定位到这个坐标处,鼠标其实压根没动

至此,相应的验证码识别即告一段落,接下来我们需要点击登录,其实点击登录特别简单,代码如下

bro.find_element_by_xpath('//*[@id="J-login"]').click()

ok,这样一来我们就相当于完成了验证码识别以及后续的点击登录操作,但是在运行过程中,你会发现有时候这个第三方软件并不能特别准确的识别验证码,有时也会出错,或者在图片保存的时候,有时也会出现图片没有正确保存的情况,对于这种情况,我们就想设置一个循环,将这个操作放到循环里面,只有验证码正确识别之后,我们才给它进行下一步

然后我们会发现,在他验证成功之后呢,还会出现一个滑块验证,那我们就可以检测在我们识别二维码点击登录之后,会不会出现滑块验证,然后我们定位到滑块这里,然后我们会发现在二维码识别之前和识别之后,这个滑块代码其实一直都在html中,只不过没有正确识别之前,里面的属性display的值为none,而正确识别之后呢,display属性就没了。所以其实我们只需要判断这个里面的display属性值是不是none,我们就可以判断有没有正确识别成功了在这里插入图片描述
在这里插入图片描述
第一张图片是验证码正确验证之后滑块代码情况,第二张图片是正确验证之前的滑块代码情况

然后我们需要在一个循环里面不停的去判断,然后去执行,代码如下

while(True):
    t2 = tree.xpath('//*[@id="login_slide_box"]/@style')[0]
    # 获取到滑块验证的style的属性值,因为我们所讲的display在style属性中,所以需要这样判断
    t=re.search(‘none’,t2)
    # 使用正则搜索,判断none是否在style属性中,注意返回值不是str,所以我们需要强制转换
    t=str(t)
    action = ActionChains(bro)
    if t!='None':
        chaojiying1 = chaojiying.Chaojiying_Client('*****用户名', '***用户密码', '软件id')  # 用户中心>>软件ID 生成一个替换 96001
        im = open('./code.jpg', 'rb').read()  # 本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
        xy = chaojiying1.PostPic(im, 9004)['pic_str']
        try:
            print(xy)
            xy = (xy.split(sep='|'))
            for i in xy:
                cl = bro.find_element_by_xpath('//*[@id="J-loginImg"]')
                action.move_to_element(cl).perform()  # ——鼠标移动到某个元素
                xy1 = (i.split(sep=','))
                x=int(xy1[0])
                y=int(xy1[1])
                action.move_to_element_with_offset(cl, x, y).click().perform()
            bro.find_element_by_xpath('//*[@id="J-login"]').click()
        except ValueError:
            print('验证失败,正在重新验证')
# 我们在这里使用try expect是因为有时候,图片出错导致没有办法识别处我们需要点的坐标,会报错,我们将错误输出一下,然后让他重新验证就好了,不然错误会导致程序无法运行下去

这个代码其他部分上面已经讲过,所以这边不在赘复

7.滑块验证码的通过

在执行完这些之后呢,我们只需要完成最后一步,进行滑块码验证,首先我们需要用到一下指令

        
        action.click_and_hold(drag1).perform()
        # 这个其实就是长按点击目标元素
        action.move_to_element_with_offset(drag1, 400, 0).perform()
        # 这个其实就是拖动目标元素相对偏移量x,y
        action.release().perform()
        # 这个其实就是释放刚才长按的鼠标
	其中呢,perform都表示执行的意思,然后action其实就是我之前的
action = ActionChains(bro)				即动作连

所以要完成滑块码验证,我们需要先定位到滑块码位置处,然后长按点击滑块码位置处,然后拖动滑块码位置进行偏移量,最后释放长按的鼠标

具体代码如下:

drag = bro.find_element_by_xpath('//*[contains(@class,"nc_iconfont btn_slid")]')
# 这个就是定位到滑块出,并且赋值给drag
action.click_and_hold(drag).perform()
# 这个就是长按滑块的意思
action.move_to_element_with_offset(drag, 400, 0).perform()
# 这个就是拖动滑块的意思
action.release().perform()
# 这个就是释放滑块

在完成这些之后呢,12306的登录程序就已经完成了,下面看我详细代码

#作业人:zhuangzhou
#作业时间:2021/2/20 12:32

from selenium import webdriver
from selenium.webdriver import ActionChains
import chaojiying
import base64
import re
from lxml import etree
from time import sleep


url='https://www.12306.cn/index/'


bro=webdriver.Chrome(executable_path='***相对地址')

bro.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
  "source": """
    Object.defineProperty(navigator, 'webdriver', {
      get: () => undefined
    })
  """
})
 #这段也特别重要,是为了让webdriver规避被检测的风险

bro.get(url=url)
bro.maximize_window()

bro.find_element_by_xpath('//*[@id="J-header-login"]/a[1]').click()                 

bro.find_element_by_xpath('/html/body/div[2]/div[2]/ul/li[2]/a').click()            

bro.find_element_by_xpath('//*[@id="J-userName"]').send_keys('****用户名')         


bro.find_element_by_xpath('//*[@id="J-password"]').send_keys('***用户密码')  
          

gd="window.scrollTo(0,document.body.scrollHeight=500)"
# '''用于设置鼠标滚动500像素点,'''
bro.execute_script(gd)


while(True):

    page = bro.page_source
    tree = etree.HTML(page)
    pic_url = tree.xpath('//*[@id="J-loginImg"]/@src')[0]

    pic_url3 = re.sub('data:image/jpg;base64,', '', pic_url)
    
    pic = base64.b64decode(pic_url3)

    with open('code.jpg', 'wb') as fp:
        fp.write(pic)

    t2 = tree.xpath('//*[@id="login_slide_box"]/@style')[0]

    t=re.search('display',t2)
    t=str(t)
    action = ActionChains(bro)
    if t!='None':
        chaojiying1 = chaojiying.Chaojiying_Client('***用户名', '***用户密码', '软件ID')  # 用户中心>>软件ID 生成一个替换 96001
        im = open('./code.jpg', 'rb').read()  # 本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
        xy = chaojiying1.PostPic(im, 9004)['pic_str']
        try:
            xy = (xy.split(sep='|'))
            for i in xy:
                cl = bro.find_element_by_xpath('//*[@id="J-loginImg"]')
                action.move_to_element(cl).perform()  # ——鼠标移动到某个元素
                xy1 = (i.split(sep=','))
                x=int(xy1[0])
                y=int(xy1[1])
                action.move_to_element_with_offset(cl, x, y).click().perform()
            sleep(5)
            bro.find_element_by_xpath('//*[@id="J-login"]').click()
            sleep(5)

        except ValueError:
            print('验证失败,在重新验证')

    else:

        drag = bro.find_element_by_xpath('//*[contains(@class,"nc_iconfont btn_slid")]')

        sleep(2)
        action.move_to_element(drag).perform()
        sleep(1)
        action.click_and_hold(drag).perform()
        sleep(1)
        action.move_to_element_with_offset(drag, 400, 0).perform()
        sleep(1)
        action.release().perform()
        break

  

后记:

至此,自动化登录程序就完成了,希望本文对大家有用,如果可以,一键三联哦

  • 8
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值