在使用selenium访问网站,爬取相应内容时,经常需要模拟登陆,现在基本每个网站登陆都具有验证码了,虽然验证码识别可以利用第三方来完成,但是我们还是需要先获取验证码的图片才可以借助第三方来识别,而在selenium如果你先访问获取验证码后在进行二次访问验证,验证码是会刷新的,所以我们需要获取实时的验证码。下面是获取识别验证码的两种方法。
一、利用urllib库来直接获取验证码
首先需要安装urllib库,然后利用selenium访问相应网站,对网站进行解析,获取验证码的url访问连接,利用urllib库通过刚刚的url来获取图片的二进制数据并进行储存。
page_img = urllib.request.urlopen(img_src).read()
这样就获取了图片的二进制数据了,这是较为简单的,注意利用这个方法的时候还需要导入requests库,不然会报错。
下面是我利用该方法获取12306网站的验证码例子的代码:
from selenium import webdriver
from lxml import etree
import requests
import urllib
from time import sleep
#指定Chrome浏览器位置
option = webdriver.ChromeOptions()
option.binary_location = 'E:\\Google Chrome浏览器\\Google\\Chrome\\Application\\chrome.exe'
#进行伪装
option.add_experimental_option('excludeSwitches',['enable-automation'])
#生成浏览器对象
bro = webdriver.Chrome(executable_path=r'E:\chrome浏览器驱动程序\chromedriver_win32\chromedriver',options=option)
bro.get('https://kyfw.12306.cn/otn/resources/login.html')
sleep(1)
#定位到账号密码登录标签
a_tag = bro.find_element_by_xpath('/html/body/div[2]/div[2]/ul/li[2]/a')
#点击切换为账号密码登录才有验证码
a_tag.click()
sleep(1)
#获取页面源码
page_text = bro.page_source
#生成etree对象
tree = etree.HTML(page_text)
#获取验证码的下载地址
img_src = tree.xpath('//*[@id="J-loginImg"]/@src')[0]
#利用图片地址获取图片二级制数据
page_img = urllib.request.urlopen(img_src).read()
#将获取的二级制数据进行持久化存储
with open('img.jpg','wb') as fp:
fp.write(page_img)
二、利用selenium库截图获取验证码
该方法比第一种麻烦一点,首先还是利用selenium访问网站,注意这样要设置浏览器窗口最大化,不然会出现偏差。
#设置浏览器全屏化
bro.maximize_window()
然后进行全局截图,利用页面解析定位到验证码的标签处,调用location方法获取验证码的左上角坐标,再调用size方法获取验证码的宽度和高度,最后得到右下角坐标。然后利用PIL库中的Image类来打开刚刚截取的全局图片,根据获取的左上角坐标和右下角坐标对截图进行裁剪从而获取验证码图片。
location = code_png_lel.location
print('location',location)
#获取验证码的长宽
size = code_png_lel.size
print('size',size)
#location获取是根据百分之百缩放的,而我电脑的缩放是百分之125所以出现偏差
#图片左上角和右下角的xy坐标
rangle = (
int(location['x']), int(location['y']), int(location['x']+size['width']), int(location['y']+size['height'])
)
print('rangle',rangle)
#对全局页面进行截图获取局部验证码
i = Image.open('./aa.png')
#按照给定xy坐标裁剪
frame = i.crop(rangle)
但是我这样截图还是出现偏差了,在网上一查才发现location方法获取的坐标是按显示100%时得到的,而截图所使用的坐标却是需要根据显示缩放比例缩放后对应的图片所确定的,因此就出现了偏差。
这就与计算机的缩放显示有关了,windows可以在桌面右键-->显示设置-->缩放与布局。
若是百分之100就不会有偏差,我的是百分之125所以有偏差。
1、将其调整为100%会运行就不会报错了。但是100%看着不舒服所以我用了第二种方法。
2、将裁剪的坐标全部乘以缩放的比例,即左上角和右下角的x,y轴坐标全部乘以1.25.
location = code_png_lel.location
print('location',location)
#获取验证码的长宽
size = code_png_lel.size
print('size',size)
#location获取是根据百分之百缩放的,而我电脑的缩放是百分之125所以出现偏差
k=1.25
#图片左上角和右下角的xy坐标
rangle = (
int(location['x'])*k, int(location['y'])*k, int(location['x']+size['width'])*k, int(location['y']+size['height'])*k
)
print('rangle',rangle)
#对全局页面进行截图获取局部验证码
i = Image.open('./aa.png')
#按照给定xy坐标裁剪
frame = i.crop(rangle)
下面是我利用该方法获取12306的验证码:
from selenium import webdriver
from lxml import etree
from PIL import Image
from time import sleep
#给定Chrome浏览器的位置和进行伪装
option = webdriver.ChromeOptions()
option.binary_location = 'E:\\Google Chrome浏览器\\Google\\Chrome\\Application\\chrome.exe'
option.add_experimental_option('excludeSwitches',['enable-automation'])
#生成浏览器对象
bro = webdriver.Chrome(executable_path=r'E:\chrome浏览器驱动程序\chromedriver_win32\chromedriver',options=option)
#设置浏览器全屏
bro.maximize_window()
bro.get('https://kyfw.12306.cn/otn/resources/login.html')
sleep(1)
#定位到账号密码的位置
a_tag = bro.find_element_by_xpath('/html/body/div[2]/div[2]/ul/li[2]/a')
#点击账号密码登录
a_tag.click()
sleep(2)
#利用save_screenshot()将当前页面解析截图并保留
bro.save_screenshot('aa.png')
#定位到验证码的标签所在
sleep(0.4)
code_png_lel = bro.find_element_by_id('J-loginImg')
#获取验证码的左上角坐标x,y
sleep(0.4)
location = code_png_lel.location
print('location',location)
#获取验证码的长宽
size = code_png_lel.size
print('size',size)
#location获取是根据百分之百缩放的,而我电脑的缩放是百分之125所以出现偏差
k=1.25
#图片左上角和右下角的xy坐标
rangle = (
int(location['x'])*k, int(location['y'])*k, int(location['x']+size['width'])*k, int(location['y']+size['height'])*k
)
print('rangle',rangle)
#对全局页面进行截图获取局部验证码
i = Image.open('./aa.png')
#按照给定xy坐标裁剪
frame = i.crop(rangle)
frame.save('./code.png')
设置睡眠时间是因为怕网站还没将验证码显示出来便截图了。
参考文章:https://www.cnblogs.com/ddd98dy/p/13586055.html