滑动验证

虎x网

import time
import re
import requests
from io import BytesIO
from PIL import Image
import random
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


class Geek_Huxiu(object):

    def __init__(self):
        self.driver = webdriver.Chrome(r'F:\Python\视屏\10爬虫\包\chromedriver_win32\chromedriver.exe')
        self.driver.set_window_size(1366, 768)

    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"]')))
        login_btn = self.driver.find_element_by_xpath('//*[@class="js-register"]')
        login_btn.click()

        WebDriverWait(self.driver, 10).until(
            EC.element_to_be_clickable((By.XPATH, '//div[@class="gt_slider_knob gt_show"]')))

        # 模拟拖动
        self.analog_drag()

    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"]')
        full_image_url, full_location = self.get_image_url('//div[@class="gt_cut_fullbg_slice"]')
        # print(cut_image_url)
        # print(cut_location)

        # 根据坐标拼接图片
        cut_image = self.splicing_image(cut_image_url, cut_location)
        full_image = self.splicing_image(full_image_url, full_location)

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

        # 根据两个图片计算距离
        distance = self.get_distance(cut_image, full_image)

        # 开始移动
        self.start_move(distance)

        # 如果出现error
        try:
            WebDriverWait(self.driver, 5, 0.5).until(
                EC.element_to_be_clickable((By.XPATH, '//div[@class="gt_ajax_tip gt_error"]')))
            print("验证失败")
            return
        except TimeoutException as e:
            pass

        # 判断是否验证成功
        try:
            WebDriverWait(self.driver, 10, 0.5).until(
                EC.element_to_be_clickable((By.XPATH, '//div[@class="gt_ajax_tip gt_success"]')))
        except TimeoutException:
            print("again times")
            time.sleep(3)
            # 失败后递归执行拖动
            self.analog_drag()
        else:
            print("验证成功")

    def get_image_url(self, xpath):
        link = re.compile('background-image: url\("(.*?)"\); background-position: (.*?)px (.*?)px;')  # 为了获取url  x坐标  y坐标
        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)  # 正则匹配  style中内容

            url = groups[1]    # 获取url
            x_pos = groups[2]  # 获取x
            y_pos = groups[3]  # 获取y
            location.append((int(x_pos), int(y_pos)))  # (x,y) 坐标  t添加到列表
            if not image_url:  # 不存在 image_url时候
                image_url = url  # image_url = url
        return image_url, location  # 返回一个图片url   坐标列表

    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
        # 创建一张画布
        # print(image_upper)
        # print('- -' * 30)
        # print(image_down)
        new_img = Image.new("RGB", (260, img.height))
        for img in image_upper:
            new_img.paste(img, (x_offset, 58))
            print(img)
            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

    def get_distance(self, cut_image, full_image):

        # print(cut_image.size)
        threshold = 50
        for i in range(0, cut_image.size[0]):
            for j in range(0, cut_image.size[1]):
                pixel1 = cut_image.getpixel((i, j))
                pixel2 = full_image.getpixel((i, j))
                res_R = abs(pixel1[0] - pixel2[0])  # 计算RGB差
                res_G = abs(pixel1[1] - pixel2[1])  # 计算RGB差
                res_B = abs(pixel1[2] - pixel2[2])  # 计算RGB差

                if res_R > threshold and res_G > threshold and res_B > threshold:
                    return i  # 需要移动的距离

    # 移动滑块
    def start_move(self, distance):
        element = self.driver.find_element_by_xpath('//div[@class="gt_slider_knob gt_show"]')

        # 使用滑块的一半进行偏移设置
        distance -= element.size.get('width') / 2
        distance += 15

        # 按下鼠标左键
        ActionChains(self.driver).click_and_hold(element).perform()
        time.sleep(0.5)
        while distance > 0:
            if distance > 20:
                # 如果距离大于20,就让他移动快一点
                span = random.randint(5, 8)
            else:
                # 快到缺口了,就移动慢一点
                span = random.randint(2, 3)
            ActionChains(self.driver).move_by_offset(span, 0).perform()
            distance -= span
            time.sleep(random.randint(10, 60) / 100)

        ActionChains(self.driver).move_by_offset(distance, 1).perform()
        ActionChains(self.driver).release(on_element=element).perform()


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

 

posted @ 2019-05-10 17:52  洛丶丶丶  阅读(371)  评论(0编辑  收藏  举报