Selenium之模拟登录铁路12306的示例代码


Posted in Python onJuly 31, 2020

最近接触了一些selenium模块的相关知识,觉得还挺有意思的,于是决定亲自尝试写一些爬虫程序来强化selenium模块(一定要多尝试、多动手、多总结)。本文主要使用python爬虫来模拟登录铁路12306官网。这儿得吐槽一句,铁路12306网站的反爬机制做的还是比较好。

话不多说,下面跟小墨一起来学习如何通过爬虫来实现铁路12306的登录。

一、 验证码破解

当我们输入账号和密码后,在点击登录按钮之前,还需要对验证码进行操作。对验证码的识别,已经有相关的处理平台,我们只需要借助第三方平台即可。

1.注册并登录超级鹰账号:点击链接进行注册https://www.chaojiying.com/user/login/;
2.点击购买题分,并进行充值;
3.点击软件id,创建一个软件Id(程序中会用到);
4.下载示例代码(开发文档—>选择相应的语言?>下载示例demo),python示例代码如下所示:

class Chaojiying_Client(object):
 def __init__(self, username, password, soft_id):
 self.username = username
 password = password.encode('utf8')
 self.password = md5(password).hexdigest()
 self.soft_id = soft_id
 self.base_params = {
  'user': self.username,
  'pass2': self.password,
  'softid': self.soft_id,
 }
 self.headers = {
  'Connection': 'Keep-Alive',
  'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
 }
 def PostPic(self, im, codetype):
 """
 im: 图片字节
 codetype: 题目类型 参考 http://www.chaojiying.com/price.html
 """
 params = {
  'codetype': codetype,
 }
 params.update(self.base_params)
 files = {'userfile': ('ccc.jpg', im)}
 r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files, headers=self.headers)
 return r.json()
 def ReportError(self, im_id):
 """
 im_id:报错题目的图片ID
 """
 params = {
  'id': im_id,
 }
 params.update(self.base_params)
 r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers)
 return r.json()

二、Selenium功能简介

Selenium模块和爬虫之间的关联:
?便捷的获取网站中的动态加载数据
?便捷实现模拟登录

Selenium模块的使用流程:
?环境安装:pip install selenium
?下载浏览器的驱动程序(谷歌浏览器):
?下载路径:http://chromedriver.storage.googleapis.com/index.html
? 驱动程序和浏览器的映射关系:映射链接
?将下载好的驱动程序放在当前项目目录下

Selenium模块的相关方法:https://3water.com/article/192259.htm

上述内容完成后,我们就可以正式进入正题了,是不是很期待,那就跟着小墨往下走吧。

三、模拟登录

1. 进入官网

#创建对象
#executable_path=path:下载好的驱动程序的路径
bro = webdriver.Chrome(executable_path='chromedriver.exe')
#12306的登录网址
bro.get('https://kyfw.12306.cn/otn/resources/login.html')
#窗口最大化
bro.maximize_window()

2、进入登录界面并获取验证码

#save_screenshot就是将当前页面进行截图且保存
bro.save_screenshot('aa.png')
#确定验证码图片对应的左上角和右下角的坐标(裁剪的区域就确定)
code_img_ele = bro.find_element_by_xpath('//*[@id="J-loginImg"]')
location = code_img_ele.location # 验证码图片左上角的坐标 x,y
#print('location:',location)
size = code_img_ele.size #验证码标签对应的长和宽
#print('size:',size)
#左上角和右下角坐标
rangle = (
int(location['x']), int(location['y']), int(location['x'] + size['width']), int(location['y'] + size['height']))
#至此验证码图片区域就确定下来了
i = Image.open('./aa.png')
code_img_name = './code.png'
#crop根据指定区域进行图片裁剪
frame = i.crop(rangle)
frame.save(code_img_name)
#将验证码图片提交给超级鹰进行识别
chaojiying = Chaojiying_Client('########', '#######', '#######')	#用户账号>>密码>>软件ID 
im = open('code.png', 'rb').read()									#本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
id=chaojiying.PostPic(im, 9004)['pic_id']    #截取的验证码照片以及验证码的类别代号
result = chaojiying.PostPic(im, 9004)['pic_str']   #识别结果
all_list = [] #要存储即将被点击的点的坐标 [[x1,y1],[x2,y2]]
#识别错误后,会返回题分,示例代码并没有这个,就是想让你花钱
chaojiying.ReportError(id)
if '|' in result:
 list_1 = result.split('|')
 print(list_1)
 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(x)
 xy_list.append(y)
 all_list.append(xy_list)
else:
 x = int(result.split(',')[0])
 y = int(result.split(',')[1])
 xy_list = []
 xy_list.append(x)
 xy_list.append(y)
 all_list.append(xy_list)
#遍历列表,使用动作链对每一个列表元素对应的x,y指定的位置进行点击操作
for l in all_list:
 x = l[0]
 y = l[1]
 ActionChains(bro).move_to_element_with_offset(code_img_ele, x, y).click().perform()
 time.sleep(0.5)

这样我们就实现了验证码的识别操作。

3、输入账号和密码,并点击登录按钮

#输入账号和密码
 put1=bro.find_element_by_id('J-userName')
 #当验证码识别错误后,需要清空账号重新输入
 put1.clear()
 #输入账号
 put1.send_keys('########')
 time.sleep(1)
 put2=bro.find_element_by_id('J-password')
 put2.clear()
 #输入密码
 put2.send_keys('##########')
 time.sleep(1)
 #点击登录按钮
 bro.find_element_by_id('J-login').click()

点击登录按钮后,会出现如下图所示的弹框

Selenium之模拟登录铁路12306的示例代码

因此,我们需要定位到该提示框,并实现滑块的向右滑动

4、滑块滑动

#处理提示框
time.sleep(0.5)
span=bro.find_element_by_xpath('//*[@id="nc_1_n1z"]')
action = ActionChains(bro)
#点击长按指定的标签
action.click_and_hold(span).perform()
action.drag_and_drop_by_offset(span,400,0).perform()

有的时候,当滑块移动后,会出现如下图所示的情况:

Selenium之模拟登录铁路12306的示例代码

因此,我们需要点击刷新,并重新进行滑块的移动,所以对代码做稍微的改动:

while True:
 try:
  info=bro.find_element_by_xpath('//*[@id="J-slide-passcode"]/div/span').text
  print(info)
  if info=='哎呀,出错了,点击刷新再来一次':
  	 #点击刷新
  bro.find_element_by_xpath('//*[@id="J-slide-passcode"]/div/span/a').click()
  time.sleep(0.2)
  #重新移动滑块
  span = bro.find_element_by_xpath('//*[@id="nc_1_n1z"]')
  action = ActionChains(bro)
  # 点击长按指定的标签
  action.click_and_hold(span).perform()
  action.drag_and_drop_by_offset(span, 400, 0).perform()
  time.sleep(7)
 except:
  print('ok!')
  break

至此,我们便实现了铁路12306的登录,如下图所示

Selenium之模拟登录铁路12306的示例代码

是不是觉得很简单啊。

5、完整代码

# -*- coding: utf-8 -*-

#验证码识别示例
import requests
from hashlib import md5
class Chaojiying_Client(object):
 def __init__(self, username, password, soft_id):
 self.username = username
 password = password.encode('utf8')
 self.password = md5(password).hexdigest()
 self.soft_id = soft_id
 self.base_params = {
  'user': self.username,
  'pass2': self.password,
  'softid': self.soft_id,
 }
 self.headers = {
  'Connection': 'Keep-Alive',
  'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
 }
 def PostPic(self, im, codetype):
 """
 im: 图片字节
 codetype: 题目类型 参考 http://www.chaojiying.com/price.html
 """
 params = {
  'codetype': codetype,
 }
 params.update(self.base_params)
 files = {'userfile': ('ccc.jpg', im)}
 r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files, headers=self.headers)
 return r.json()
 def ReportError(self, im_id):
 """
 im_id:报错题目的图片ID
 """
 params = {
  'id': im_id,
 }
 params.update(self.base_params)
 r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers)
 return r.json()

#使用selenium打开登录页面
from selenium import webdriver
import time
from PIL import Image
from selenium.webdriver import ActionChains
from selenium.webdriver.support import expected_conditions as EC, wait

#创建对象
#executable_path=path:下载好的驱动程序的路径
bro = webdriver.Chrome(executable_path='chromedriver.exe')
#12306的登录网址
bro.get('https://kyfw.12306.cn/otn/resources/login.html')
#窗口最大化
bro.maximize_window()
#点击账号登录
bro.find_element_by_xpath('/html/body/div[2]/div[2]/ul/li[2]/a').click()
time.sleep(1)
while True:
 try:
 #save_screenshot就是将当前页面进行截图且保存
 bro.save_screenshot('aa.png')
 #确定验证码图片对应的左上角和右下角的坐标(裁剪的区域就确定)
 code_img_ele = bro.find_element_by_xpath('//*[@id="J-loginImg"]')
 location = code_img_ele.location # 验证码图片左上角的坐标 x,y
 #print('location:',location)
 size = code_img_ele.size #验证码标签对应的长和宽
 #print('size:',size)
 #左上角和右下角坐标
 rangle = (
 int(location['x']), int(location['y']), int(location['x'] + size['width']), int(location['y'] + size['height']))
 #至此验证码图片区域就确定下来了
 i = Image.open('./aa.png')
 code_img_name = './code.png'
 #crop根据指定区域进行图片裁剪
 frame = i.crop(rangle)
 frame.save(code_img_name)
 #将验证码图片提交给超级鹰进行识别
 chaojiying = Chaojiying_Client('#####', '#######', '######')	#用户账号>>密码>>软件ID
 im = open('code.png', 'rb').read()									#本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
 id=chaojiying.PostPic(im, 9004)['pic_id']    #截取的验证码照片以及验证码的类别代号
 result = chaojiying.PostPic(im, 9004)['pic_str']   #识别结果
 all_list = [] #要存储即将被点击的点的坐标 [[x1,y1],[x2,y2]]
 #识别错误后,会返回题分,官网给的demo并没有这一句,哈哈哈,坑吧,就是让你多花钱
 chaojiying.ReportError(id)
 if '|' in result:
  list_1 = result.split('|')
  print(list_1)
  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(x)
  xy_list.append(y)
  all_list.append(xy_list)
 else:
  x = int(result.split(',')[0])
  y = int(result.split(',')[1])
  xy_list = []
  xy_list.append(x)
  xy_list.append(y)
  all_list.append(xy_list)
 #遍历列表,使用动作链对每一个列表元素对应的x,y指定的位置进行点击操作
 for l in all_list:
  x = l[0]
  y = l[1]
  ActionChains(bro).move_to_element_with_offset(code_img_ele, x, y).click().perform()
  time.sleep(0.5)
 #输入账号和密码
 put1=bro.find_element_by_id('J-userName')
 #当验证码识别错误后,需要清空账号重新输入
 put1.clear()
 put1.send_keys('username') #你的账号
 time.sleep(1)
 put2=bro.find_element_by_id('J-password')
 put2.clear()
 put2.send_keys('password') #你的密码
 time.sleep(1)
 bro.find_element_by_id('J-login').click()
 #处理提示框
 time.sleep(3)
 span=bro.find_element_by_xpath('//*[@id="nc_1_n1z"]')
 action = ActionChains(bro)
 #点击长按指定的标签
 action.click_and_hold(span).perform()
 action.drag_and_drop_by_offset(span,400,0).perform()
 time.sleep(8)
 while True:
  try:
  info=bro.find_element_by_xpath('//*[@id="J-slide-passcode"]/div/span').text
  print(info)
  if info=='哎呀,出错了,点击刷新再来一次':
   bro.find_element_by_xpath('//*[@id="J-slide-passcode"]/div/span/a').click()
   time.sleep(0.2)
   span = bro.find_element_by_xpath('//*[@id="nc_1_n1z"]')
   action = ActionChains(bro)
   # 点击长按指定的标签
   action.click_and_hold(span).perform()
   action.drag_and_drop_by_offset(span, 400, 0).perform()
   time.sleep(7)
  except:
  print('ok!')
  break
 #释放动作链
 action.release()
 break
 except:
 time.sleep(3)
time.sleep(12)
#登录成功
bro.find_element_by_link_text('确定').click()
time.sleep(0.5)
bro.find_element_by_link_text('首页').click()
#输入起点、终点以及时间,查询车票
start_city='北京'
end_city='上海'
date='2020-08-05'
#选择起点
bro.find_element_by_xpath('//*[@id="fromStationText"]').click()
time.sleep(2)
#这只遍历了热门城市,要是想遍历其他城市,自己写一个循环就行
city_list=bro.find_elements_by_xpath('//*[@id="ul_list1"]/li')
for city in city_list:
 if city.text==start_city:
 city.click()
 break
time.sleep(2)
#选择终点
bro.find_element_by_xpath('//*[@id="toStationText"]').click()
for city in city_list:
 if city.text==end_city:
 city.click()
 break
time.sleep(2)
js = "$('input[id=train_date]').removeAttr('readonly')"
bro.execute_script(js)
dt=bro.find_element_by_id('train_date')
dt.clear()
dt.send_keys(date)
time.sleep(2)
bro.find_element_by_xpath('/html/body/div[3]/div[2]/div/div[1]/div/div[1]/ul/li[1]/a').click()
time.sleep(0.5)
bro.find_element_by_xpath('//*[@id="isStudentDan"]/i').click()
time.sleep(2)
bro.find_element_by_id('search_one').click()
time.sleep(2)

到此这篇关于Selenium之模拟登录铁路12306的示例代码的文章就介绍到这了,更多相关Selenium 模拟登录12306内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python生成器(Generator)详解
Apr 13 Python
python输出指定月份日历的方法
Apr 23 Python
Python实现完整的事务操作示例
Jun 20 Python
python excel使用xlutils类库实现追加写功能的方法
May 02 Python
python bmp转换为jpg 并删除原图的方法
Oct 25 Python
Django数据库连接丢失问题的解决方法
Dec 29 Python
Python数据可视化教程之Matplotlib实现各种图表实例
Jan 13 Python
selenium处理元素定位点击无效问题
Jun 12 Python
python二进制文件的转译详解
Jul 03 Python
Python多线程获取返回值代码实例
Feb 17 Python
利用Python实现最小二乘法与梯度下降算法
Feb 21 Python
Python爬虫爬取全球疫情数据并存储到mysql数据库的步骤
Mar 29 Python
python的flask框架难学吗
Jul 31 #Python
使用PyCharm安装pytest及requests的问题
Jul 31 #Python
django和flask哪个值得研究学习
Jul 31 #Python
Windows下PyCharm配置Anaconda环境(超详细教程)
Jul 31 #Python
Python如何输出百分比
Jul 31 #Python
PyCharm配置anaconda环境的步骤详解
Jul 31 #Python
Pycharm及python安装详细教程(图解)
Jul 31 #Python
You might like
德劲1104的电路分析与改良
2021/03/01 无线电
PHP+AJAX实现无刷新注册(带用户名实时检测)
2007/01/02 PHP
php将数据库中所有内容生成静态html文档的代码
2010/04/12 PHP
php中选择什么接口(mysql、mysqli)访问mysql
2013/02/06 PHP
jQuery 1.9.1源码分析系列(十三)之位置大小操作
2015/12/02 Javascript
TinyMCE汉化及本地上传图片功能实例详解
2016/05/31 Javascript
vue.js加载新的内容(实例代码)
2017/06/01 Javascript
javascript数组定义的几种方法
2017/10/06 Javascript
Angular 4中如何显示内容的CSS样式示例代码
2017/11/06 Javascript
React Native react-navigation 导航使用详解
2017/12/01 Javascript
Javascript Promise用法详解
2018/05/10 Javascript
基于js Canvas实现二次贝塞尔曲线
2018/12/25 Javascript
vue实现整屏滚动切换
2020/06/29 Javascript
JavaScript 实现下雪特效的示例代码
2020/09/09 Javascript
[04:38]完美世界携手游戏风云打造 卡尔工作室饰品系统篇
2013/04/25 DOTA
linux系统使用python监控apache服务器进程脚本分享
2014/01/15 Python
Python基本语法经典教程
2016/03/11 Python
Python实现带参数与不带参数的多重继承示例
2018/01/30 Python
Python3.6.0+opencv3.3.0人脸检测示例
2018/05/25 Python
python实现图片彩色转化为素描
2019/01/15 Python
Pycharm最新激活码2019(推荐)
2019/12/31 Python
python上传时包含boundary时的解决方法
2020/04/08 Python
Python如何获取文件指定行的内容
2020/05/27 Python
HTML5之SVG 2D入门11—用户交互性(动画)介绍及应用
2013/01/30 HTML / CSS
ECCO爱步加拿大官网:北欧丹麦鞋履及皮具品牌
2017/07/08 全球购物
澳洲网红粉泥面膜:Sand & Sky
2019/08/13 全球购物
北承题目(C++)
2012/05/16 面试题
WINDOWS域的具体实现方式是什么
2014/02/20 面试题
计算机专业个人求职信范例
2013/09/23 职场文书
上班迟到检讨书
2014/01/10 职场文书
环境保护与污染治理求职信
2014/07/16 职场文书
综合测评个人总结
2015/03/03 职场文书
2015年乡镇信访工作总结
2015/04/07 职场文书
基于flask实现五子棋小游戏
2021/05/25 Python
Java基于字符界面的简易收银台
2021/06/26 Java/Android
源码分析Redis中 set 和 sorted set 的使用方法
2022/03/22 Redis