selenium模拟携程旅行自动登录

携程旅行实现自动登录还是有点麻烦的,我们先看官网:

 

  不用多说,肯定需要先进行标签定位,定位到红框处,通过click()实现跳转,来到了下面的页面:

 

   这里的话,先标签定位到输入用户名和密码的地方,然后通过send_keys()可以输入用户名和密码,这里很简单,然后定位到滑块,定义个动作链,再通过click_and_hold()将滑块拖动到最右,这里也简单,本以为这样模拟登陆成功,但麻烦的来了,它又弹出了一个验证方式!!!

  

 

   其实,它的出现让我比较意外,但有一说一不难操作的,先将当前页面截图,然后定位验证码区域,获取location和size,然后计算右下角的位置,然后用crop()就可以对验证码区域进行截图,接着把该截图放到超级鹰中进行检测,接着存储验证码的坐标,最后使用动作链对每一个列表元素对应的x,y指定的位置进行点击操作,最后再点击提交按钮,当前验证就成功结束了。

  最后,再勾选同意协议的框,模拟登录就算成功,但接下来问题来了:

  首先,贴出我之前的代码:

  1 # -*- coding:utf-8 -*-
  2 # @Time : 2022/1/24 0024 11:33
  3 # @Author : Tzy0425
  4 # @File : 模拟登录携程旅行.py
  5 
  6 from selenium import webdriver
  7 from selenium.webdriver.chrome.service import Service
  8 from selenium.webdriver.common.by import By
  9 from selenium.webdriver import ActionChains
 10 # 裁剪特定区域需要事先导包
 11 from PIL import Image
 12 from time import sleep
 13 from selenium.webdriver import ChromeOptions
 14 from hashlib import md5
 15 import requests
 16 
 17 #实现规避检测
 18 options = ChromeOptions()
 19 options.add_experimental_option('excludeSwitches', ['enable-automation'])
 20 
 21 # 超级鹰
 22 class Chaojiying_Client(object):
 23 
 24     def __init__(self, username, password, soft_id):
 25         self.username = username
 26         password =  password.encode('utf8')
 27         self.password = md5(password).hexdigest()
 28         self.soft_id = soft_id
 29         self.base_params = {
 30             'user': self.username,
 31             'pass2': self.password,
 32             'softid': self.soft_id,
 33         }
 34         self.headers = {
 35             'Connection': 'Keep-Alive',
 36             'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
 37         }
 38 
 39     def PostPic(self, im, codetype):
 40         """
 41         im: 图片字节
 42         codetype: 题目类型 参考 http://www.chaojiying.com/price.html
 43         """
 44         params = {
 45             'codetype': codetype,
 46         }
 47         params.update(self.base_params)
 48         files = {'userfile': ('ccc.jpg', im)}
 49         r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files, headers=self.headers)
 50         return r.json()
 51 
 52     def ReportError(self, im_id):
 53         """
 54         im_id:报错题目的图片ID
 55         """
 56         params = {
 57             'id': im_id,
 58         }
 59         params.update(self.base_params)
 60         r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers)
 61         return r.json()
 62 
 63 s = Service(r'./chromedriver.exe')
 64 driver = webdriver.Chrome(service=s,options=options)
 65 driver.get('https://www.ctrip.com/')
 66 sleep(1)
 67 
 68 login_href = driver.find_element(By.XPATH,'//*[@id="nav-bar-set-login-person-text"]/span')
 69 login_href.click()
 70 sleep(2)
 71 
 72 userName_tag = driver.find_element(By.ID,'nloginname')
 73 userName_tag.click()
 74 userName_tag.send_keys('15110403732')
 75 sleep(1)
 76 
 77 passWord_tag = driver.find_element(By.ID,'npwd')
 78 passWord_tag.click()
 79 passWord_tag.send_keys('080015yuan...')
 80 sleep(1)
 81 
 82 slider_btn = driver.find_element(By.XPATH,'//*[@id="sliderddnormal"]/div[1]/div[2]')
 83 action = ActionChains(driver)
 84 action.click_and_hold(slider_btn)
 85 action.move_by_offset(300,0).perform()
 86 sleep(1)
 87 
 88 refresh_btn = driver.find_element(By.XPATH,'//*[@id="sliderddnormal-choose"]/div[2]/div[4]/div/a')
 89 refresh_btn.click()
 90 
 91 # 对当前页面进行截图并保存
 92 driver.save_screenshot('whole.png')
 93 
 94 # 验证码图片左上角和右下角的坐标(裁剪的区域就确定)
 95 code_ele = driver.find_element(By.XPATH,'//*[@id="sliderddnormal-choose"]/div[2]')
 96 
 97 # 获取验证码图片左上角的坐标 x,y
 98 location = code_ele.location
 99 
100 # 获取验证码图片的长和宽
101 size = code_ele.size
102 print('location',location)
103 # print('size',size)
104 
105 # 计算右下角坐标,之后就确定好了验证码区域
106 rangle = (
107     int(location['x']),int(location['y']),
108     int(location['x'] + size['width']),int(location['y'] + size['height'])
109 )
110 
111 # 通过crop()对验证码区域进行裁剪
112 i = Image.open('./whole.png')
113 code_img_name = './code.png'
114 frame = i.crop(rangle)
115 frame.save(code_img_name)
116 
117 # 将验证码图片提交给超级鹰进行识别
118 chaojiying = Chaojiying_Client('yyy666', 'a123456789', '928028')  # 用户名称、密码、软件ID
119 im = open('./code.png', 'rb').read()  # 本地图片文件路径
120 print(chaojiying.PostPic(im, 9005)['pic_str'])
121 result = chaojiying.PostPic(im,9005)['pic_str']
122 
123 # 存储要被点击的验证码的坐标[[x1,y1],[x2,y2],[x3,y3]]
124 all_list = []
125 if '|' in result:
126     list_1 = result.split('|')
127     for i in range(len(list_1)):
128         x = list_1[i].split(',')[0]
129         y = list_1[i].split(',')[1]
130         xy_list = []
131         xy_list.append(x)
132         xy_list.append(y)
133         all_list.append(xy_list)
134 else:
135     x = int(result.split(',')[0])
136     y = int(result.split(',')[1])
137     xy_list = []
138     xy_list.append(x)
139     xy_list.append(y)
140     all_list.append(xy_list)
141 print(all_list)
142 
143 # 遍历列表,使用动作链对每一个列表元素对应的x,y指定的位置进行点击操作
144 for l in all_list:
145     x = l[0]
146     y = l[1]
147     action = ActionChains(driver)
148     # move_to_element_with_offset()在验证码的区域上根据x与y进行偏移定位(作用域先由当前页面调整到验证码区域)
149     # move_by_offset()在当前页面直接进行偏移定位即可
150     action.move_to_element_with_offset(code_ele,x,y).click().perform()
151     sleep(0.5)
152 sleep(1)
153 
154 submit_btn = driver.find_element(By.XPATH,'//*[@id="sliderddnormal-choose"]/div[2]/div[4]/a')
155 submit_btn.click()
156 sleep(1)
157 
158 agree_checkbox = driver.find_element(By.XPATH,'//*[@id="normalview"]/p/input')
159 agree_checkbox.click()
160 sleep(1)
161 
162 login_btn = driver.find_element(By.ID,'nsubmit')
163 login_btn.click()
164 sleep(1)
165 
166 driver.quit()

  事先说明,95行的xpath路径是我直接在浏览器的控制台复制的:

   按道理运行后验证码区域应该可以成功截取下来,但我运行后确实这样的(图1为当前页面的截图,图2为验证码区域的截图):

 

 

 

 

   后面通过自己一遍又一遍的测试,最后发现,通过标签定位获取的location和size,并不是验证码区域左上角的坐标,也不是验证码区域的长宽,理由如下:

 1 # 对当前页面进行截图并保存
 2 driver.save_screenshot('whole.png')
 3 
 4 # 验证码图片左上角和右下角的坐标(裁剪的区域就确定)
 5 # code_ele = driver.find_element(By.XPATH,'//*[@id="sliderddnormal-choose"]/div[2]')
 6 
 7 # 获取验证码图片左上角的坐标 x,y
 8 # location = code_ele.location
 9 location = {'x':448,'y':260}
10 
11 # 获取验证码图片的长和宽
12 # size = code_ele.size
13 print('location',location)
14 # print('size',size)
15 
16 # 计算右下角坐标,之后就确定好了验证码区域
17 rangle = (
18     int(location['x']),int(location['y']),
19     int(location['x'] + 380),int(location['y'] + 405)
20 )
21 
22 # 通过crop()对验证码区域进行裁剪
23 i = Image.open('./whole.png')
24 code_img_name = './code.png'
25 frame = i.crop(rangle)
26 frame.save(code_img_name)
27 
28 # 将验证码图片提交给超级鹰进行识别
29 chaojiying = Chaojiying_Client('yyy666', 'a123456789', '928028')  # 用户名称、密码、软件ID
30 im = open('./code.png', 'rb').read()  # 本地图片文件路径
31 print(chaojiying.PostPic(im, 9005)['pic_str'])
32 result = chaojiying.PostPic(im,9005)['pic_str']
33 
34 # 存储要被点击的验证码的坐标[[x1,y1],[x2,y2],[x3,y3]]
35 all_list = []
36 if '|' in result:
37     list_1 = result.split('|')
38     for i in range(len(list_1)):
39         x = list_1[i].split(',')[0]
40         y = list_1[i].split(',')[1]
41         xy_list = []
42         xy_list.append(x)
43         xy_list.append(y)
44         all_list.append(xy_list)
45 else:
46     x = int(result.split(',')[0])
47     y = int(result.split(',')[1])
48     xy_list = []
49     xy_list.append(x)
50     xy_list.append(y)
51     all_list.append(xy_list)
52 print(all_list)
53 
54 # 遍历列表,使用动作链对每一个列表元素对应的x,y指定的位置进行点击操作
55 for l in all_list:
56     x = l[0]
57     y = l[1]
58     action = ActionChains(driver)
59     # move_to_element_with_offset()在验证码的区域上根据x与y进行偏移定位(作用域先由当前页面调整到验证码区域)
60     # move_by_offset()在当前页面直接进行偏移定位即可
61     action.move_to_element_with_offset(code_ele,x,y).click().perform()
62     sleep(0.5)
63 sleep(1)

  第9行和第19行都是自己测试出来的数据,成功截取到了验证码区域:

 

 

  可接下来问题又来了,move_to_element_with_offset()第一个参数就需要把作用域调整到验证码区域,但由于我的验证码区域是自己写死的并没有通过标签定位获取,导致这里的参数一我没法传参,于是这里又再次报错......

  最后,我想说我知道把location和size直接写死在代码中是不对的,应该用传统的标签定位然后获取location的方法,但很明显那样的话,验证码的区域并没有成功截取,why???

   如果有大佬看到这篇博客还请赐教:

 

posted @ 2022-01-24 17:18  Sunshine_y  阅读(549)  评论(0编辑  收藏  举报