Selenium是一款基于浏览器自动化的工具,使用它可以模拟浏览器进行网页访问,对于爬取一些动态加载数据的网站算是一个非常好用的工具了。
今天练习的项目就是基于Selenium对12306进行模拟登陆,并对其中的登陆验证码通过调用第三方平台超级鹰来进行自动识别点击,完成自动登陆。
一、首先,先对要爬取的网站12306进行一个分析。官方地址:https://www.12306.cn/index
二、分析完网站结构后,开始编写代码.总体可分为3个步骤。(1.跳转至登陆界面。2.使用第三方对验证码进行识别点击。3.输入参数进行模拟登陆)
先使用Selenium对12306网页进行点击到登陆界面
from selenium import webdriver
from selenium.webdriver import ActionChains #用于浏览器执行图片点击等操作通过动作链调用
import time #对于一些网页元素需要加载时间,以及正常速度访问这里通过简单的time.sleep()进行等待
from PIL import Image #对于后续对验证码图片需要进行保存读取的操作
from chaojiying import chaojiying #第三方工具超级鹰的调用代码
browser = webdriver.Chrome(executable_path='./chromedriver')
#起始方法
def start_get():
url = 'https://www.12306.cn/index/'
browser.get(url)
#1、从首页点击登陆按钮--->登陆界面
account_btn = browser.find_element_by_css_selector('#J-header-login > a:nth-child(1)')
time.sleep(2)
#点击进入到登陆界面
account_btn.click()
time.sleep(3)
#点击到账户密码登陆界面
browser.find_element_by_css_selector(
'body > div.login-panel > div.login-box > ul > li.login-hd-account > a').click()
time.sleep(2)
#2、先做验证码识别的操作
code_distinguish()
#3、在登陆界面点击账户密码登陆,然后输入账户密码
login_page()
2.首先可先分为以下3个大步骤,以及每个步骤之中的细节分析
ActionChains(browser).move_to_element_with_offset(code_img,x,y).click().perform()
#2、先做验证码识别的操作
def code_distinguish():
#拿到验证码图片的节点定位
code_img = browser.find_element_by_css_selector('#J-loginImg')
#2.1这里的location是获取这张图片的左上角的左边,返回的是字典封装的x,y的值.基于整个网页返回给你的值
loca = code_img.location#x,y{'x': 856, 'y': 284}
#1.所以,一般还需要拿到这张图片的尺寸,即长和宽
size = code_img.size #{'height': 188, 'width': 300}
#2.2接下来,就是需要做截屏。
#1.需要定位左上角和右下角2个点的左边,即共4个.保存在元祖中
code_position = (int(loca['x']), int(loca['y']), int(loca['x']+size['width']),int(loca['y']+size['height']))
#2.调用截图功能,将图片截取下去。这个功能在无头浏览器中应用的比较多,比如你想验证无头浏览器是否访问到了你想要的页面,就可以使用截图来测试观看
#3.截取当前浏览器打开的这张页面的整个图像(记住,是整个浏览器打开的页面的图像)
browser.save_screenshot('./12306/aa.png')
#4.用Image包打开这张截图
i = Image.open('./12306/aa.png')
#5.给要截取的验证码图片取名
code_img_name = './12306/code.png'
#6.调用crop函数,在这大的图片里面通过2个点对其内部的内容进行截图
frame = i.crop(code_position)
#7.将截取下来的图片存到目录中,并取名
frame.save(code_img_name)
#2.3调用超级鹰进行识别,拿到返回的结果
im = open('./12306/code.png', 'rb').read()
#{'err_no': 0, 'err_str': 'OK', 'pic_id': '3095313233818200001', 'pic_str': '25,143|260,134', 'md5': '29c583678bdf3eb09ece5726fcfaa285'}
result = chaojiying.PostPic(im, 9004)['pic_str']
#1.解析超级鹰返回的数据
#先声明一个数组用来存储所有的图片坐标,想要的是这种结果[[25,143],[260,134]]
all_list = []
if '|' in result:
list1 = result.split('|') #-->['25,143', '260,134']
count_list = len(list1)
for i in range(count_list):
xy = []
x = int(list1[i].split(',')[0])
y = int(list1[i].split(',')[0])
xy.append(x)
xy.append(y)
all_list.append(xy)
#针对的是只有一组图片符合的数据['25,143']
else:
xy = []
x = int(result.split(',')[0])
y = int(result.split(',')[1])
xy.append(x)
xy.append(y)
all_list.append(xy)
#2.4拿到返回结果后,需要调用动作链,以此点击选中的图片坐标.
action = ActionChains(browser)
for i in all_list:
x = i[0]
y = i[1]
#2.4.1:这样使用move_to_element_with_offset。表示选中一个区域再进行移动。因为返回的坐标数值是以发送的图片作为参照,而我们需要进行点击是要在整张页面中。为了解决这个问题,需要把范围先切换到页面中的图片上
ActionChains(browser).move_to_element_with_offset(code_img,x,y).click().perform()
time.sleep(5)
3.输入用户名和密码进行登陆提交
#3、在登陆界面点击账户密码登陆,然后输入账户密码
def login_page():
#2.拿到用户名和密码输入框
username_input = browser.find_element_by_css_selector('#J-userName')
username_input.send_keys('')
time.sleep(3)
password_input = browser.find_element_by_css_selector('#J-password')
password_input.send_keys('')
time.sleep(3)
#4.点击登陆按钮
login_btn = browser.find_element_by_css_selector('#J-login').click()
if __name__ == '__main__':
start_get()
超级鹰调用代码如下:
#!/usr/bin/env python
# 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()
chaojiying = Chaojiying_Client('user_name', 'pass_word', 'ID') #用户中心>>软件ID 生成一个替换 96001
此篇文章是通过学习b站2019老男孩全栈18期 爬虫+数据分析参考所总结。在此表示感谢。感兴趣的同学也自行观看,讲的还是比较细,对初学者也是比较友好的。b站传送门:https://www.bilibili.com/video/av53878299?p=1