python爬虫学习:验证码之滑动验证码
2019-05-30 15:29
555 查看
前面两个文章提到了普通图片的验证码识别,且尤其对于机器学习的识别方式精度相对会比较高。但是,现在开始流行滑动验证码,所以这里作者提及一点简单的滑动验证码识别技巧。
打开火狐浏览器,按下
F12,输入
url为 http://www.gsxt.gov.cn/index.html ,可以打开 国家企业信用信息公示系统 ,输入关键词 中国联通 ,点击搜索会弹出一个滑动验证码出来,本文就是主要识别这个网址的滑动验证码。
识别这样的滑动验证码主要运用
selenium库,判断图片中需要将按钮滑动到正确位置的距离。首先需要打开浏览器,设置最大的加载时间为
90秒,如果超过
90秒那么久直接调用
js去停止加载,最后判断网页是否加载完毕,如果没有,则重新加载:
[code]from selenium import webdriver # 打开浏览器 ''' 遇到python不懂的问题,可以加Python学习交流群:1004391443一起学习交流,群文件还有零基础入门的学习资料 ''' def openbrowser(url): global browser # 声明谷歌浏览器 browser = webdriver.Chrome() # 限制加载时间不能超过90秒 browser.set_page_load_timeout(90) try: # 输入网址 browser.get(url) if "400 Bad request" in browser.page_source: browser.get(url) except: # 超过90秒强制停止加载 browser.execute_script('window.stop()') if "400 Bad request" in browser.page_source: browser.get(url) else: pass time.sleep(5)
利用
F12可以知道输入框的
id=keyword,查询框的
id=btn_query:
[code]# 输入关键字并查询 def inputKeyword(keyword): # 清空输入框 browser.find_element_by_id("keyword").clear() # 输入查找的关键字 browser.find_element_by_id("keyword").send_keys(keyword) time.sleep(5) # 点击查询按钮 browser.find_element_by_id("btn_query").click() time.sleep(5)
而
selenium可以控制鼠标操作,调用库即可。输入中国联通进行查询,出现滑动验证码识别,由此可以知道横拉滑块的
classname=gt_slider_knob,设置一个函数,输入拖动的横距离和纵距离:
[code]from selenium.webdriver.common.action_chains import ActionChains # 拖放滑块 def drag_and_drop(x_offset, y_offset): # 找到滑块并滑动 source = browser.find_element_by_class_name("gt_slider_knob") # 调用鼠标操作并且拖动 ActionChains(browser).drag_and_drop_by_offset(source, x_offset, y_offset).perform() time.sleep(8)
下面这里是重点!识别滑动验证码的核心是,判断原图和验证码图片
RGB值的变化,假设原来验证码的图片是:
然后用鼠标轻轻拉动下方的滑块,就会出现滑动验证码的图片:
一般我们都知道每张图片都是用很多像素点构成的:
每一个像素点都会有一个
RGB值,这个值代表的是改像素点图片的颜色,而这里生成的验证码的图片很明显是有一个凹下去的区域,这个区域的颜色和原图不一样。所以我们主要是判断:
- 在什么地方原图和验证码图片的
RGB值相差很大- 相差很大的这个点的横纵坐标是多少,横坐标即为需要进行滑动的距离
在浏览器中找到验证码图片的位置,即为
classname=gt_box:
获取这个图片的
left、
top、
right、
bottom,这里需要解释一下,
top和
right相当于一张图片左上角的坐标,
right是距离左上角这个点向右的宽度,
bottom是距离左上角这个点向下的宽度:
定位到这张图片的位置,截取图片保存到内存中:
[code]import io ''' 遇到python不懂的问题,可以加Python学习交流群:1004391443一起学习交流,群文件还有零基础入门的学习资料 ''' # 截取验证码图片 def screenShotImage(): try: # 定位到验证码的框 captchaElement = browser.find_element_by_class_name("gt_box") except: inputKeyword(keyword) # 定位到验证码的框 captchaElement = browser.find_element_by_class_name("gt_box") locations = captchaElement.location sizes = captchaElement.size left = int(locations["x"]) top = int(locations["y"]) right = left + int(sizes["width"]) bottom = top + int(sizes['height']) # 截图 screenshot = browser.get_screenshot_as_png() screenshot = Image.open(io.BytesIO(screenshot)) png = screenshot.crop((left, top, right, bottom)) png.save(str(int(time.time())) + ".png") time.sleep(1) return png
在对原图和验证码图片进行对比的时候,要排除掉拼图的干扰,拼图也就是这张图片,它和原图也是不一样的:
如何排除这张图片的干扰呢?本文首先找到这张图片的宽度:
[code]# 获取滑块的图片,是为了得到滑块的宽度 def getWidth(): # 找到滑块并滑动 slider = browser.find_element_by_class_name("gt_slice") sizes = slider.size width = sizes["width"] return width
由于该滑块总是出现在左边,所以在对比
RBG值的时候跳过这个宽度。
将原图的每个像素点和验证码的每个像素点做差,如果差值都小于60则认为这个像素点出现 明显差异 ,即认定为验证码凹陷位置的起点。由于观察验证码图片的时候发现,滑块左边其实是有5个位移是空白的,所以最后的位移值要减掉5。而如果没有找到正确的偏移值,则返回一个假的偏移值55,防止程序中断:
[code]# 获取滑动偏移量 def getOffset(): img1 = screenShotImage() drag_and_drop(x_offset=5, y_offset=0) img2 = screenShotImage() w1, h1 = img1.size w2, h2 = img2.size print("wh") print(w1, h1, w2, h2) if w1 != w2 or h1 != h2: return False slider = getWidth() print("开始循环", w3, h3) for x in range(slider, w3): print(x) for y in range(0, h3): pix1 = img1.getpixel((x, y)) pix2 = img2.getpixel((x, y)) # 如果相差超过70则就认为找到了缺口的位置 if abs(pix1[0]-pix2[0]) < 60 and abs(pix1[1]-pix2[1]) < 60 and abs(pix1[2]-pix2[2]) < 60: # 滑块左边其实是有5个位移是空白的,所以要减掉 return x-5 # 如果没有找到正确的偏移值,则返回一个假的偏移值,防止程序中断 return 55
但是不管临界值选取60还是其他值效果都非常差,所以可以利用图片库比较两张图片有什么不同:
[code]# 判断两张图片不同的地方 img3 = ImageChops.difference(img1, img2) img3.save(str(int(time.time())) + ".png")
可以判断这张图片如果底色不是黑色,即
RBG(0,0,0),且像素颜色鲜艳,颜色鲜艳即
RBG的某个值大于70,那么就认为找到了凹陷地方的边界,更改代码增加挑选条件:
[code]# 获取滑动偏移量 def getOffset(): img1 = screenShotImage() drag_and_drop(x_offset=5, y_offset=0) img2 = screenShotImage() # 判断两张图片不同的地方 img3 = ImageChops.difference(img1, img2) img3.save(str(int(time.time())) + ".png") w1, h1 = img1.size w2, h2 = img2.size w3, h3 = img3.size print("wh") print(w1, h1, w2, h2) if w1 != w2 or h1 != h2: return False slider = getWidth() print("开始循环", w3, h3) for x in range(slider, w3): print(x) for y in range(0, h3): pix1 = img1.getpixel((x, y)) pix2 = img2.getpixel((x, y)) pix3 = img3.getpixel((x, y)) print(pix3[0],pix3[1],pix3[2]) # 如果相差超过70则就认为找到了缺口的位置 if pix3[0] > 70 or pix3[1] > 70 or pix3[2] > 70 and abs(pix1[0]-pix2[0]) < 60 and abs(pix1[1]-pix2[1]) < 60 and abs(pix1[2]-pix2[2]) < 60: # 滑块左边其实是有5个位移是空白的,所以要减掉 return x-5 # 如果没有找到正确的偏移值,则返回一个假的偏移值,防止程序中断 return 55
最后代入运行能准确的找到滑块验证码的位置:
相关文章推荐
- Python爬虫入门教程 57-100 python爬虫高级技术之验证码篇3-滑动验证码识别技术
- python爬虫学习日记(1)--获取验证码
- python爬虫之验证码篇3-滑动验证码识别技术
- python爬虫学习第二十四天
- python爬虫学习(1)--关于正则表达式输入和提取中文
- 学习Python爬虫(三):Requests库入门级使用
- python学习(十八)爬虫中加入cookie
- Python爬虫学习
- 使用python2.7学习网络爬虫,问题锦集
- python爬虫学习之re正则表达式
- python爬虫学习
- Python学习之路 (四)爬虫(三)HTTP和HTTPS
- python爬虫学习笔记五:Re库的介绍和使用
- Python3.6 学习爬虫入门篇
- 爬虫学习3.2 HTTP请求的python实现--urllib2/urllib实现
- Mac学习python爬虫:python3.6安装wordcloud
- python爬虫学习笔记
- Python基础学习-爬虫小试3爬知乎用户小测
- Python爬虫学习1
- Python3 爬虫学习笔记(三)正则表达式