前言:
初入Python,打算搞个练手项目,正巧又到了抢票的季节,那就12306了,反正也早就被玩坏了,哈哈哈哈。。。由于是边练手边写的,为了方便,没有啥优雅的姿势,每个功能一个方法大概如下:
1.获取登录需要的验证码图片保存到本地
2.自动识别验证码(或手动识别)
3.验证验证码并登录
4.多重验证(验证之后才能获取真正的登录状态)
5.扫票
6.下订单
7.获取联系人
8....
大概是这么个样子,那么就开始吧~~~~~~~~
复制代码
直奔主题:
用到的包:
import json
import random
import re
import time
import requests
复制代码
第一步:获取验证码图片保存到本地
# 首先为了之后能保持登录状态,我们要先弄一个全局的会话,以后的session都是这个了
session = requests.session()
# 获取验证码图片并保存
def get_code():
# 这是验证码图片接口 后面是个随机数
code_url = 'https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand&{}'.format(
str(random.random()))
r = session.get(code_url)
with open('code.png', 'wb') as f:
f.write(r.content)
print('获取验证码并保存成功')
复制代码
第二步:获取验证码的正确坐标
首先我们看到保存的验证图片如下(已打上编号):
# 对8个小图坐标化,因为最终验证接口是得用坐标做参数的,比如上图对应的参数就应该是: 260,40,110,120
code = ['40,40', '110,40', '180,40', '260,40', '40,120', '110,120', '180,120', '260,120']
# 识别验证码 并得到正确坐标
def code_answer():
num = input('请输入:')
try:
num = [int(num)]
except ValueError:
num = list(map(int, num.split()))
answer = '' # 构建一个空字符串
for i in num: # 对验证码序号列表进行遍历
answer += code[i - 1] + ',' # 将每个验证码序号对应的位置信息添加到字符串中,并加上','号
answer_result = answer.rstrip(',')
print('得到验证码坐标:', answer_result)
return answer_result
复制代码
然后就是高科技了,使用一个牛X的网站自动识别(最近不大稳定,可能要多几次):
# 识别验证码 并得到正确坐标
def code_answer():
# 自动识别的网站
url = 'http://littlebigluo.qicp.net:47720/'
files = {'file': open('code.png', 'rb')}
r = session.post(url, files=files)
num = r.text.split('<B>')[1].split('<')[0]
#其实也就是上面这块获取 num 手动改成自动了 有兴趣的朋友可以做个判断,自动不稳定时提醒手动输入
try:
num = [int(num)]
except ValueError:
num = list(map(int, num.split()))
print(num)
answer = '' # 构建一个空字符串
for i in num: # 对验证码序号列表进行遍历
answer += code[i - 1] + ',' # 将每个验证码序号对应的位置信息添加到字符串中,并加上','号
answer_result = answer.rstrip(',')
print('得到验证码坐标:', answer_result)
return answer_result
复制代码
第三步:验证验证码并登录
def check_and_login():
# 如果之前没加 User-Agent 这里加一下
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'
}
# 验证验证码的接口
check_url = 'https://kyfw.12306.cn/passport/captcha/captcha-check'
# 登录接口
login_url = 'https://kyfw.12306.cn/passport/web/login'
# 验证参数
check_data = {
'answer': code_answer(),# 这里就是上面我们得到的验证码坐标
'login_site': 'E',
'rand': 'sjrand'
}
# 登录参数
login_data = {
'username': '12306账号',
'password': '12306密码',
'appid': 'otn'
}
print('开始验证验证码...')
check_r = session.post(check_url, data=check_data, headers=headers, verify=False) # 注意关掉SSL验证
check_result = json.loads(check_r.text)
if check_result['result_code'] == '4': # 4代表成功,5代表验证码错误,8代表验证信息为空
print(check_result['result_message'])
login_r = session.post(login_url, data=login_data, headers=headers, verify=False)
login_result = json.loads(login_page.text)
print(login_result)
# 这里就是表面上登录成功了,但是是得不到用户信息得,还得需要多次验证
validate_apptk(get_apptk()) # 获取tk并验证tk
isLogin() # 验证登录 如果正确 返回带有实名的结果 至此登录完成
else:
print('验证失败,开始重新验证')
get_code()
check_and_login()
return
复制代码
第四步:验证登录
# 首先获取一个 apptk
def get_apptk():
url = 'https://kyfw.12306.cn/passport/web/auth/uamtk'
data = {'appid': 'otn'}
r = session.post(url, data=data)
result = json.loads(r.text)
return result['newapptk']
# tk验证 把上面获取到的 apptk Post去验证
def validate_apptk(newapptk):
url = 'https://kyfw.12306.cn/otn/uamauthclient'
data = {'tk': newapptk}
r = session.post(url, data=data)
result = json.loads(r.text)
print('postTk', result)
# 最后验证
def isLogin():
url = 'https://kyfw.12306.cn/otn/login/conf'
r = session.get(url)
result = json.loads(r.text)
print(result) # 打印结果 如果结果有 name = 你的实名 则真正登录成功,接下来就可以用这个保存登录状态的session去浪了~
复制代码
第五步: 下面就是真正的骚操作了
都已经拿到保存登录状态的session了,接下来 就是抓接口 去扫票下单了。 接口就不说了,我用的google浏览器 打开12306网站 F12 然后正常操作一遍扫票流程,就可以在右找到了。吃饭前给到大家发个红包 滑稽~滑稽~