本文使用python的第三方库requests实现12306网的登录以及验证码的提交功能。
本次操作是手动输入验证码,并不是自动识别提交验证码,因为自动识别提交验证码需要用到图像处理与模式识别,还没学到这方面的知识。
实现步骤:
1.创建会话session,如果单单使用requests.get()和post()等等方法是无法实现登录的。因为直接使用requests.get()方法执行后,没有保存cookie下来,下次访问服务器就无法获取验证码图片和其他任何东西。学过web的同学应该懂得。
2.使用session进入登录首页
然后打开浏览器,进入12306网登录页面,打开浏览器的审查元素
3.获取验证码图片,并存到本地文件
4.手动输入验证码
因为12306网的验证码是点击的,不是输入字母或者数字的
解决方法是:
发现上图中红色框中的数据是提交给服务器的验证码数据,这个数据是验证码图片中8张图中正确的验证码图片的像素的坐标组成
我们建立一个字典存储8张图片所在的像素坐标,以及一个函数获取正确的验证图片像素坐标组成
怎么知道每一个图片的像素坐标呢?
你可以使用电脑的画图软件打开之前保存下来的验证码图片,一般y轴坐标都是要减掉30的,因为图片上面的‘请输入下图中所有。。。。’是不包括的,像下面(40,69)最后应是(40,39)或者(40,40),在附近就行。
然后手动输入验证码的格式是输入第几张,用逗号隔开。上面的例子就是第二个和第四个图片,所以输入:2,4
这样通过定义的函数就可以获取正确的验证码格式。然后通过提交表单校验验证码。
4.校验验证码
根据返回的response,提取结果代码,判断是否校验成功。
可以添加print(captcha_check_response.text)打印返回数据,得到成功与失败的结果代码result_code,这样就可以设计下面的代码。下面登录验证用户名与密码同样。
5.验证码校验成功后,开始提交用户名与密码,在浏览器审查元素中找到提交用户名与密码的url
6.一般其他的网站登录的实现到上面就结束了,但是12306网的登录还没,我们还需获取到token才能确定登录成功
在浏览器中使用网页登录,第一步在审查元素中找到uamtk
第二步找到uamauthclient,一般都是在uamtk下面
代码如下:
进行到这里就登录成功了。
import requests
#1.创建会话session
session = requests.Session()
headers = {'User-':'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36'}
session.headers.update(headers)
#2.进入12306登录页面
url = 'https://kyfw.12306.cn/otn/login/init'
response = session.get(url)
#3.获取验证码图片,并保存到本地文件
captcha_url = 'https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand&0.8006430591776557'
captcha_response = session.get(captcha_url)
with open('captcha.jpg','wb') as f:
f.write(captcha_response.content)
#4.验证码提交验证
#定义一个字典变量来存验证码图片的像素坐标
map = {
'1':'35,40',
'2':'107,45',
'3':'175,43',
'4':'254,43',
'5':'37,115',
'6':'110,118',
'7':'177,117',
'8':'255,119'
}
#定义一个函数来获取验证码的提交格式
def make_answer(numpict):
num = numpict.split(',')
answer = ''
for i in range(len(num)):
answer += map[num[i]] + ','
return answer[:-1]
#手动输入验证码
captcha_answer = make_answer(input('请输入正确的验证码:'))
captcha_check_url = 'https://kyfw.12306.cn/passport/captcha/captcha-check'
form_data = {
'answer':captcha_answer, #验证码答案,填写正确图片的像素坐标
'login_site':'E',
'rand':'sjrand'
}
#校验验证码
captcha_check_response = session.post(captcha_check_url,data = form_data)
result_code = captcha_check_response.json()["result_code"] #获取返回的结果代码判断是否校验成功
if result_code != '4':
if result_code == '7':
print("验证码已经过期")
else:
print('验证码校验失败')
else:
#验证码校验成功,执行用户名密码提交登录
login_url = 'https://kyfw.12306.cn/passport/web/login'
username = 'xxxxxxxxxx'
password = 'xxxxxx'
form_data = {
'username': username,
'password': password,
'appid':'otn'
}
login_response = session.post(login_url,data = form_data)
if login_response.json()["result_code"] == 0:
#登录成功,获取权限token
uamtk_url = 'https://kyfw.12306.cn/passport/web/auth/uamtk'
form_data = {'appid':'otn'}
uamtk_response = session.post(uamtk_url,data = form_data)
if uamtk_response.json()["result_code"] == 0:
uamauthclient_url = 'https://kyfw.12306.cn/otn/uamauthclient'
form_data = {'tk':uamtk_response.json()["newapptk"]}
uamauthclient_response = session.post(uamauthclient_url,data = form_data)
print(uamauthclient_response.json())
else:
print('权限token获取失败')
print('登录成功')
else:
print('登录失败,用户名或者密码错误')
exit()