• <sup id="mk476"></sup>
    <dl id="mk476"></dl>
  • <progress id="mk476"><tr id="mk476"></tr></progress>
    <div id="mk476"><tr id="mk476"></tr></div>
    <sup id="mk476"><ins id="mk476"></ins></sup>
  • <progress id="mk476"></progress>
    <div id="mk476"></div>
    <div id="mk476"><tr id="mk476"></tr></div>
  • <div id="mk476"></div>
    <dl id="mk476"><s id="mk476"></s></dl><dl id="mk476"></dl><div id="mk476"></div>
  • <div id="mk476"></div>
    <dl id="mk476"><ins id="mk476"></ins></dl>

    Python爬虫入门教程 58-100 python爬虫高级技术之验证码篇4-极验证识别技术之一

    @

    验证码类型

    今天要搞定的验证码属于现在使用非常多的验证码的一种类型---极验证滑动验证码,关于这个验证码的详细说明查阅他的官网,https://www.geetest.com/ 把验证码做到这个地步,必须点赞了。

    海量验证码

    官网最新效果

    官方DEMO最新的效果如下,按照验证码的更新频率,基本博客看完,验证码也更新了,不过套路依旧是相同的,反爬只能增加爬虫编写的成本,并不能完全杜绝爬虫。
    在这里插入图片描述
    这类验证码,常规解决办法,模拟人为操作,图像比对,查找缺口,移动覆盖缺口。

    找个用极验证的网站

    今天看新闻,随意找了一下,虎嗅使用的是直接拖拽,没有用最新的点击+拖拽方式,可以直接看一下如何操作。
    虎嗅验证码
    这种验证码除了打码?#25945;?#20197;外,直接selenium搞起

    拼接验证码图片

    当你在谷歌浏览器使用F12进行查找元素的时候,随意的去缺口图片上面点击一下,在控制台DOM结构中出现如下代码,有前端经验的童鞋知道,这个使用的是背景局部显示技术,是可以通过这个拼接成一个。

    在这里插入图片描述
    注意两个地方:

    1. https://static.geetest.com/pictures/gt/8bc4cb7fa/8bc4cb7fa.webp 图片地址
    2. background-position:后面的坐标
      在这里插入图片描述
      查阅图片之后,发现是一张碎掉的图片,你要做的第一步是将这个图片进行还原,我们通过selenium进行实现。这个地方需要?#32570;?#27880;一下图片的尺寸,后面用size = 312x116
      在这里插入图片描述

    在这里插入图片描述

    编写自动化代码

    使用selenium执行的操作,模拟人的点击行为即可

    最初,我们导入一些selenium的基本模块与方法

    import time
    import re
    
    from selenium import webdriver
    from selenium.common.exceptions import TimeoutException
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.wait import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.common.action_chains import ActionChains
    

    基本模块的作用如下
    webdriver 核心驱动
    selenium.common.exceptions 异常类 TimeoutException 超时异常
    selenium.webdriver.common.by 按照什么方式进行元素的查找 例如 By.ID,By.ClassName,By.XPATH
    selenium.webdriver.support.wait 等待页面加载某些元素
    from selenium.webdriver.support import expected_conditions 场景判断用的,一般和上面的等待加载元素一起使用
    selenium.webdriver.common.action_chains 鼠标执行的动作链

    主方法测试入口

    if __name__ == '__main__':
        h = Geek_Huxiu()
        h.run()

    构造方法,实现对部分参数的初始化操作

        def __init__(self):
            self.driver = webdriver.Chrome()  
            self.driver.set_window_size(1366,768)

    webdriver.Chrome() 启动谷歌浏览器,这个地方需要你提前配置好chromedriver.exe
    set_window_size(1366,768) 初始化浏览器大小

    核心run方法

        def run(self):
            self.driver.get("https://www.huxiu.com/")  # 打开浏览器
        
            WebDriverWait(self.driver,10).until(EC.element_to_be_clickable((By.XPATH,'//*[@class="js-register"]')))
    
            reg_element = self.driver.find_element_by_xpath('//*[@class="js-register"]')
            reg_element.click()
    
            WebDriverWait(self.driver,10).until(EC.element_to_be_clickable((By.XPATH,'//div[@class="gt_slider_knob gt_show"]')))
    
            # 模拟拖动
            self.analog_drag()

    WebDriverWait 方法

    说明

    driver: 传入WebDriver?#36947;?#21363;我们上例中的driver
    timeout: 超?#31508;?#38388;,等待的最长时间(同时要考虑隐性等待时间)
    poll_frequency: 调用until或until_not中的方法的间隔时间,默认是0.5秒
    ignored_exceptions: 忽略的异常,如果在调用until或until_not的过程中抛出这个元组中的异常, 则不中断代码,继续等待;
    如果抛出的是这个元组外的异常,则中断代码,抛出异常。默?#29616;?#26377;NoSuchElementException。

    基本使用方法

    WebDriverWait(driver, 超?#31508;背? 调用频率, 忽略异常).until(可执行方法, 超?#31508;?#36820;回的信息)

    模拟拖动方法

        def analog_drag(self):
            # 鼠标移动到拖动按钮,显示出拖动图片
            element = self.driver.find_element_by_xpath('//div[@class="gt_slider_knob gt_show"]')
            ActionChains(self.driver).move_to_element(element).perform()
            time.sleep(3)
    
    
            # 刷新一下极验证图片
            element = self.driver.find_element_by_xpath('//a[@class="gt_refresh_button"]')
            element.click()
            time.sleep(1)
    
            # 获取图片地址和位置坐标列表
            cut_image_url,cut_location = self.get_image_url('//div[@class="gt_cut_bg_slice"]')
    
            print(cut_image_url)
            print(cut_location)
    

    行为链

    ActionChains(self.driver).move_to_element(element).perform()

    模拟人移动鼠标到指定DOM元素

    图片处理方法

        def get_image_url(self,xpath):
            link = re.compile('background-image: url\("(.*?)"\); background-position: (.*?)px (.*?)px;')
            elements = self.driver.find_elements_by_xpath(xpath)
            image_url = None
    
            location = list()
    
            for element in elements:
                style = element.get_attribute('style')
                groups = link.search(style)
    
                url = groups[1]
                x_pos = groups[2]
                y_pos = groups[3]
                location.append((int(x_pos), int(y_pos)))
                if not image_url:
                    image_url = url
            return image_url, location
    

    使用正则表达式进行匹配的时候,需要将所有的DIV匹配出来 ,采用find_elements_by_xpath 方法,尤其注意elements

    WebElement 具备一些常用的方法和属性

    • size:返回元素尺寸
    • text :返回元素文本
    • get_attribute(name):获得属性值
    • is_dispalyed() :该元素是否用户可见

    初步运行结果

    在这里插入图片描述

    拼接图

    看下图,注意一些基本元素,拼接的图片由N个小矩形构成,分为上下两个部分,小矩形的宽度和高度为10x58

    核心由上下两部分构成,每部分都是26个小矩形
    在这里插入图片描述
    因为,整体宽度为2610 = 260px ,整体高度为582=116px

    但是,还记得博客开始的时候,你记录的那个宽度和高度么? 312x116 高度一致,但是宽度出现偏差

    312-260 = 52px
    52个像素去除以26个矩形,发现每个矩形差2px,这两个像素也就是下面我们拼接图片的重点了

        def splicing_image(self,image_url,location):
            res = requests.get(image_url)
            file = BytesIO(res.content)
            img = Image.open(file)
            image_upper = []
            image_down = []
            for pos in location:
                if pos[1] == 0:
                    # y值为0的坐标  属于图片上半部分,高度58
                    image_upper.append(img.crop((abs(pos[0]), 0, abs(pos[0]) + 10, 58)))
                else:
                    # y值为58的坐标 属于图片上半部分,高度58
                    image_down.append(img.crop((abs(pos[0]), 58, abs(pos[0]) + 10, img.height)))
            # 画布的x轴偏移量
            x_offset = 0 
            # 创建一张画布
            new_img = Image.new("RGB", (260, img.height))
            for img in image_upper:
                new_img.paste(img, (x_offset, 58))
                x_offset += img.width
    
            x_offset = 0
            for img in image_down:
                new_img.paste(img, (x_offset, 0))
                x_offset += img.width
    
            return new_img

    说明

    • requests.get(image_url) 下载图片到本地
    • BytesIO(res.content) 将字节转换成二进制文件流
    • Image.open(file) 获取图片
    • img.crop ?#20204;型?#29255; left, upper, right, lower
    • Image.new("RGB", (260, img.height)) 创建一个空白的图片,将图片序列中的元素,依次的拼接到里面

    最终实现效果

    在这里插入图片描述

    图片存储到本地

            # 将图片存储到本地
            cut_image.save("cut.jpg")
            full_image.save("full.jpg")

    好了,今天博客?#25302;?#25226;图片处理到位,明天着手拼接部分。

    欢迎关注「非本科程序员」 回复 【0412】获取本篇博客源码

    posted @ 2019-04-12 15:20 梦想橡皮擦 阅读(...) 评论(...) 编辑 收藏
    江苏11选5软件