自学python差不多有一年半载了,这两天利用在甲方公司搬砖空闲之余写了个小项目——【12306-tiebanggg-master】注:本项目仅供学习研究,如若侵犯到贵公司权益请联系我第一时间进行删除;请勿用于一切非法行为,否则后果自行承担!
通过分析123O6,车次列表信息无需登录即可获取,但是如果我们想要使用代码代替手动为自己进行购票时,则需要进行登录网站;为了不给对方服务器造成压力,本项目并未开启多线程。项目为全自动进行车票的购买,包括(登录、验证码识别、刷票、判断是否有票、预购、下单、邮箱通知)本项目思路——使用selenium登录网站获取到cookie(供后续购票使用),定时检查cookie是否有效,获取列车列表信息及购票流程均使用requests的方式进行。
之前我们学习了如何获取与到列车信息数据,本篇将讲解【使用selenium结合超级鹰登录验证】。如果没有看过之前的文章请移步:python爬取12306列车信息自动抢票并自动识别验证码(一)列车数据获取篇
本项目思路、过程过于复杂,共分为【列车数据获取篇】【登录验证篇】【购票篇】【项目结束】,本篇文章只讲第一点【登录验证篇】
涉及到的第三方包:
① selenium
② requests
③ lxml
④ PIL
⑤chromedriver.exe(谷歌浏览器驱动)
⑥google浏览器
chromedriver.exe 需要[点击此处下载]与google浏览器[点击此处下载]的版本相对应。
打码平台:超级鹰
这里不做过多介绍,详情请移步第一篇文章,好了,正片开始~
本次“幸运”对象地址:aHR0cHM6Ly9reWZ3LjEyMzA2LmNuL290bi9yZXNvdXJjZXMvbG9naW4uaHRtbA==
1. 登录起始页
①首先进入登录起始页
可以看到,网页中有两种登录方式,分别是扫码登录和账号登录。网站默认显示扫码登录页面,我们使用账号登录。所以接下来使用selenium+chromedriver来对界面进行操作。
大致流程:打开登录页-选择账号登录-输入账号密码-图片点选验证-点击登录-滑块验证-成功登录
selenium 的使用方法在这里不做过多介绍,安装方法:pip install selenium
首先在Chepiao_Models中定义一个类:class MonestFunctionSeleniumSpider(object),通过这个类实现整体的登录验证流程
创建一个初始化信息配置包:setting_class.py
def __init__(self):
self.lourl = setting.login_url # 登录地址
self.driver_path = setting.driver_path # chromedriver路径
self.username = setting.username # 账号
self.password = setting.password # 密码
# 实例化一个Options对象,作用是为给浏览器(driver)对象添加一些参数,防止网站监测到我们为机器对象
self.chrome_options = Options()
self.chrome_options.add_argument('disable-infobars')
self.chrome_options.add_experimental_option('excludeSwitches', ['enable-automation'])
# 实例化一个浏览器对象(driver)
self.driver = webdriver.Chrome(executable_path=self.driver_path, options=self.chrome_options)
# 设置隐式等待
self.wait = WebDriverWait(self.driver, 15, 0.3)
# 浏览器窗口最大化
self.driver.maximize_window()
接下来定义一个登录函数login,通过代码打开浏览器,并请求登陆地址:
def login(self):
self.driver.get(self.logurl)
time.sleep(2)
print("正在登录12306平台 请稍后...")
运行效果
可以看到程序自动打开浏览器并且访问登录页,接下来我们需要选择账号登录,上代码
self.wait.until(EC.visibility_of_element_located((By.LINK_TEXT, '账号登录'))).click()
输入账号和密码
self.wait.until(EC.visibility_of_element_located((By.ID, 'J-userName'))).send_keys(self.username)
time.sleep(0.5)
self.wait.until(EC.visibility_of_element_located((By.ID, 'J-password'))).send_keys(self.password)
运行效果
接下来是关键,想要登陆必须通过图片点选验证码才能够点击登录按钮
所以,接下来我们将使用超级鹰打码平台来进行图片点选的验证。首先需要到超级鹰官方网站注册一个账号,并且关注公众号之后,平台会送你1000个积分,这里每次验证需要消耗25点积分,用来测试已经足够。这里我们使用的是返回坐标类型的验证方式:
选择开发文档中的python语言Demo下载
下载到的代码如图
将代码拷贝到我们项目下的Cjy_Pythons文件夹chaojy_chapts.py
具体的操作请自行阅读相关文档,在这里不做过多介绍,接下来进行验证码的识别。
超级鹰验证码识别思路为:将验证码图片上传至对应接口,平台识别后返回验证码中正确图片的位置坐标(坐标在之后的验证识别过程中是必须的)。
所以这里我们想要识别验证,就得先把网页中的验证码图片获取到。经过多次观察,网页的验证码会在每次请求的时候进行更换,也就是说我们使用selenium这种方式来登录的话,就不能使用requests来对验证码图片的获取,所以这里提供一种解决方案:selenium打开网页并填写账号密码后,通过截屏的方式来获取验证码图片。
上代码:
# 首先获取验证码图片的对应element对象
code_img_ele = self.driver.find_element_by_id('J-loginImgArea')
# 定义一个截取全屏的保存路径
img_path = 'images/全屏图像.png'
# 通过get_screenshot_as_file方法截取全屏图像并保存
self.driver.get_screenshot_as_file(img_path)
# 使用location 对element对象获取验证码左上角的坐标
location = code_img_ele.location # 验证码左上角坐标
# size获取验证码图片的长和宽
size = code_img_ele.size # 验证码长和宽(需要比例缩放)
"""
这里来想要在网页上截取一张图片需要知道这个图片的左上角坐标和右下角坐标,通过PIL的
Image方法进行获取,传入对象为rangle,rangle中需要含有验证码左上角坐标以及右下角坐标
的四个数值,下面为构造计算四个值得方法。可以看到我在每一个坐标值后面都乘了1.25,这里
是因为我的电脑缩放比例为125%,乘以多少根据个人情况而定,100%缩放比例时乘以1.
"""
rangle = (
int(location['x'] * 1.25), int(location['y'] * 1.25),
int(location['x'] * 1.25 + size['width'] * 1.25),
int(location['y'] * 1.25 + size['height'] * 1.25)
)
# 打开之前我们截取的全屏图像
i = Image.open(img_path)
# 定义验证码保存路径
base_path1 = 'images/验证码图片.png'
# 通过crop方法对全屏图像进行验证码的截取
frame = i.crop(rangle)
# 保存至本地
frame.save(base_path1)
运行结果:
可以看到,在images文件夹下生成了两张图:全屏图像.png、验证码图片.png,而我们需要的是【验证码图片.png】这张验证码图片。接下来将验证码图片.png上传到超级鹰进行打码并获取正确图片坐标点,代码:
chaojiying = Chaojiying_Client(setting.cjy_user, setting.cjy_pwd, '910269')
im = open(base_path1, 'rb').read()
x_y = chaojiying.PostPic(im, 9004)['pic_str']
all_list = []
if '|' in x_y:
list_1 = x_y.split('|')
count_1 = len(list_1)
for i in range(count_1):
xy_list = []
x = int(list_1[i].split(',')[0])
y = int(list_1[i].split(',')[1])
xy_list.append(int(x/1.25))
xy_list.append(int(y/1.25))
all_list.append(xy_list)
else:
xy_list = []
x = int(x_y.split(',')[0])
y = int(x_y.split(',')[1])
xy_list.append(int(x/1.25))
xy_list.append(int(y/1.25))
all_list.append(xy_list)
print('验证码坐标:', all_list)
运行结果:
验证码图片:
可以看到验证码图片中有两个蒸笼,所以验证码坐标点返回了两个坐标点,这两个坐标点就是我们需要进行点击验证的坐标位置。接下来进行验证码的点击验证:
for rangle in all_list:
x = rangle[0]
y = rangle[1]
ActionChains(self.driver).move_to_element_with_offset(code_img_ele, x, y).click().perform()
time.sleep(0.2)
time.sleep(0.3)
self.driver.find_element_by_xpath('//*[@id="J-login"]').click()
time.sleep(1)
运行效果:
图片点选验证搞定!!!!!当图片点选验证通过之后,会弹出一个滑块验证码,接下来就来搞一搞这个滑块。[/手动滑稽]
由于时间关系,现在要出门去干酒了,所以先发布这一版本,回来再将滑块补上。hhhhhhh
下一章节【python爬取12306列车信息自动抢票并自动识别验证码(三)购票篇】 敬请期待
码字不容易,如果不能篇文章对你有帮助请点赞,谢谢~
告辞,还有单子要写~,明天更新登录篇
需项目【12306-tiebanggg-master】源码请加v:tiebanggg 【注明来意】
*注:本文为原创文章,转载文章请附上本文链接,谢谢!