利用代码自动登录12306官网是爬虫领域的经典行为,整个过程中的难点在于网站验证码的自动化突破,整个过程需要突破两个验证码的阻碍,一是文字选图,二是滑块。其中文字选图较为麻烦。但是还是有方法能够顺利进行网站的登录,代码一执行,直接会运行到登录后的界面。
首先需要实例化一个brower对象,用于驱动浏览器
browser = webdriver.Firefox(executable_path=r'D:\python\python安装\Scripts\geckodriver.exe')
browser.get('https://kyfw.12306.cn/otn/resources/login.html')
script = 'Object.defineProperty(navigator,"webdriver",{get:()=>undefined,});'
browser.execute_script(script)
前两行就不说了,后两行的目的在于防止12306网站检测出我们是个爬虫程序,如果没有这两行,在后面通过滑动验证码时会通不过,让用户一直刷新,所以需要把它加上
我们是账号密码登录,需要点击账号登陆,操作如下
account_login = browser.find_element_by_xpath('/html/body/div[2]/div[2]/ul/li[2]/a')
account_login.click()
首先需要定位到这四个字所在的位置,利用xpath进行定位,之后进行点击
其次将自己的用户名和密码输入到下方的文本框中,操作如下
username = browser.find_element_by_id('J-userName')
username.send_keys('你的用户名')
password = browser.find_element_by_id('J-password')
password.send_keys('你的密码')
前面都比较简单,接下来突破文字识图验证才是整个过程的难点
这个验证码是需要识别出文字,在下面的图中进行点击,选中后才能点击登录,这就需要借助第三方平台超级鹰,它的使用请参考小编的上一篇文章,利用超级鹰突破验证码识别。
我们要做的就是将这个验证码的图片提交给从超级鹰平台上下载的代码,我们采用截图的方式对这个验证码进行截取,将获取验证码的方法封装成一个函数get_image()
seleium中有将整个网页截图的方法,我们将整个网页截图之后,如上图,利用id定位到验证码,以页面左上角为原点,用location的方法会得到验证码的x,y,利用size的方法会得到验证码的宽和高,单位都为像素。图中有两个绿色的点,我们用这两个点就可以利用PIL中的Image--crop方法截取此验证码,此函数代码如下:
def get_image(browser):
browser.save_screenshot('screen_shot.png')#页面截图
img_page = Image.open('screen_shot.png')
img_element = browser.find_element_by_id('J-loginImg')
location = img_element.location
print(location)
size = img_element.size
print(size)
left = location['x'] * 1.5 #乘以1.5是因为电脑显示设置中 缩放比例设为了150%
top = location['y'] * 1.5
right = left + size['width'] * 1.5
bottom = top + size['height'] * 1.5
img_code = img_page.crop((left, top, right, bottom))
img_code.save('verification.png')#验证码截图
print(left, top, right, bottom)
return
将页面的截图和裁剪后的验证码的截图分别保存在了代码的当前路径下,在这里需要注意的是,每个人的电脑对屏幕的缩放不一样
例如我的电脑是150%,在代码中同样需要对坐标的数字进行处理,这个因电脑而异,不处理是无法精确定位到需要的地方,截图会偏移
接下来需要把裁剪下来的验证码的图传入超级鹰,刚刚程序中已经将验证码的图保存下来了,直接将其上传即可,需要注意识别的类型为9005。直接把超级鹰的代码复制到程序中,然后调用即可,出入验证码和识别类型,观察返回字典的pic_str,这里面是我们需要点击的坐标(以验证码左上角为原点)
返回后,以上图为例,需要我们点击两个坐标的位置(395,108)和(304,201)
按照“|”将其分开,进行循环,横坐标设置为x,纵坐标设置为y,此时需要将x和y的值进行float浮点处理,除以电脑的缩放比例,否则实际点击的位置会偏移,如果电脑的缩放比例为100%,则忽略这一步
接下来就是模拟鼠标对上述坐标进行点击,此时需要用到ActionChains这个方法
这一阶段的代码如下
for i in location_code.split('|'):
x = i.split(',')[0]
x = float(x)
x = x / 1.5
y = i.split(',')[1]
y = float(y)
y = y / 1.5
position = ActionChains(browser).move_to_element_with_offset(img_element, x, y)
position.click().perform()
time.sleep(0.5)
此时代码会模拟鼠标点击通过验证码需要点击的位置。
之后,就该点击登录按钮,先定位再点击。
到了最后一步,滑块验证,这个就简单了
找到这个滑块的元素,复制其xpath路径,向右偏移大概400个像素的位置即可,代码如下
box = browser.find_element_by_xpath('//*[@id="nc_1_n1z"]')#定位滑块
ActionChains(browser).click_and_hold(box).perform()#摁住不放
move = ActionChains(browser).drag_and_drop_by_offset(box, 400, 0)#定义向右移动
move.perform()#执行此动作
至此,整个登录过程就结束了
下面附上源码和运行视频
from selenium import webdriver
from selenium.webdriver import ActionChains
from PIL import Image
import requests
from hashlib import md5
import time
def get_image(browser):
browser.save_screenshot('screen_shot.png')
img_page = Image.open('screen_shot.png')
img_element = browser.find_element_by_id('J-loginImg')
location = img_element.location
print(location)
size = img_element.size
print(size)
left = location['x'] * 1.5 #乘以1.5是因为电脑显示设置中 缩放比例设为了150%
top = location['y'] * 1.5
right = left + size['width'] * 1.5
bottom = top + size['height'] * 1.5
img_code = img_page.crop((left, top, right, bottom))
img_code.save('verification.png')
print(left, top, right, bottom)
return
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()
def chaojiying(img,imgtype):
chaojiying = Chaojiying_Client(username,password,ID)
im = open(img,'rb').read()
return chaojiying.PostPic(im,imgtype)
browser = webdriver.Firefox(executable_path=r'D:\python\python安装\Scripts\geckodriver.exe')
browser.get('https://kyfw.12306.cn/otn/resources/login.html')
script = 'Object.defineProperty(navigator,"webdriver",{get:()=>undefined,});'
browser.execute_script(script)
browser.maximize_window()
time.sleep(0.2)
account_login = browser.find_element_by_xpath('/html/body/div[2]/div[2]/ul/li[2]/a')
account_login.click()
time.sleep(0.2)
username = browser.find_element_by_id('J-userName')
username.send_keys(你的12306账号)
password = browser.find_element_by_id('J-password')
password.send_keys(你的12306密码)
get_image(browser)
username= 你的超级鹰账号
password = 你的超级鹰密码
ID = 你的超级鹰软件ID
result = chaojiying('verification.png',9005)
print(result)
location_code = result['pic_str']
print(location_code)
img_element = browser.find_element_by_xpath('//*[@id="J-loginImg"]')
for i in location_code.split('|'):
x = i.split(',')[0]
x = float(x)
x = x / 1.5
print('x:' ,x, type(x))
y = i.split(',')[1]
y = float(y)
y = y / 1.5
print('y:', y, type(y))
# ActionChains(browser).move_to_element_with_offset(img_element, x, y).click().perform()
position = ActionChains(browser).move_to_element_with_offset(img_element, x, y)
position.click().perform()
time.sleep(0.5)
login_btn = browser.find_element_by_xpath('//*[@id="J-login"]')
login_btn.click()
time.sleep(0.5)
box = browser.find_element_by_xpath('//*[@id="nc_1_n1z"]')
ActionChains(browser).click_and_hold(box).perform()
move = ActionChains(browser).drag_and_drop_by_offset(box, 400, 0)
move.perform()
大家把代码中的83、85、90、91、92换成自己的账户即可
下面附上效果视频
QQ录屏20210718102147