Экстремальный проверочный код взломал селен

Python рептилия Selenium

Эта статья была написана давно.Поскольку скорость распознавания была очень низкой, нет возможности показать ее всем, поэтому она была скрыта.Сегодня я, наконец, могу показать ее, чтобы увидеть солнце.

Привет всем, я Xingxing Online, я снова здесь, сегодня я приношу вам метод взлома селена кода подтверждения, вы немного взволнованы, друзья не могут ждать, давайте поторопимся. точка.

Регистрация в сети Tiger Sniffing

На этот раз мы беремтигр нюхаетПри открытии операции, при регистрации аккаунта, нужно сдвинуть картинку в положение пробела, с таким проверочным кодом мы сейчас сталкиваемся часто, так что подробно представлять это нет необходимости.

фигура 1

Для этого кода проверки мы сначала определили использование селена для имитации метода скользящего взлома.Движение мыши, щелчок и перетаскивание селена относительно просты, поэтому вопрос в том, как далеко перетаскивать, глаза выглядят очень интуитивно понятными, но как получить программа? Используя распознавание изображений... гм, я могу только думать об этом. Лучше посмотреть исходный код веб-страницы или запросить информацию, чтобы увидеть, есть ли какая-либо достоверная информация.

Просмотр информации о веб-странице

Щелкните правой кнопкой мыши на изображении, чтобы просмотреть элемент

фигура 2

Картинка в этот момент, к счастью, моя рука единорога не практиковалась зря больше 20 лет.Посмотрим, что увидят стихии.

изображение 3

Это выглядит немного странно, есть ссылка на изображение и информация о местоположении, и их так много, сначала скопируйте ссылку на изображение в браузер и перейдите по ней.

Рисунок 4

ВФ, что это за хрень? Заметили, что 6 выглядит как хвост свиньи? Также есть маленькая стрелка, по сравнению с полным изображением выше, и обнаружено, что перемещение стрелки в сторону маленькой 6, хвост свиньи успешно. Конечно, если присмотреться, есть и другие похожие вещи, такие как текст. Тогда мы можем подтвердить, что эта картинка должна быть зашифрована.Если мы сможем собрать ее вместе, будет ли она ближе к вычислению положения разрыва. Теперь мы должны обратить внимание на информацию о позиции за представлением элемента, настолько, что кажется, что она должна иметь какое-то отношение к этому беспорядочному порядку. Давайте удостоверимся. Моя идея такова, так как это положение связано с головоломкой, и посмотрите на изображение нашей руки единорога выше, я снова отмечу его.

Рисунок 5

Когда мы нажимаем для просмотра элемента, браузер нам его выделяет.Изначально я нажимал на изображение для его просмотра.По моей идее, разве он не должен выделяться на всем изображении? Кажется, что это не так, есть только небольшая часть, и на ней есть информация об элементе, имена классов ширины и высоты, вернитесь и посмотрите на рисунок 3, в координатах положения спереди должен быть x- ось, тыльная сторона это ось y, а ось y Всего 58 и 0. Согласно рисунку 2 картинка разделена на верхнюю и нижнюю части.Посчитайте количество дивов.Имеется 26 штук,каждая с ширина 10x высота 58. Согласно этому расчету, тогда ширина всей картинки равна 260, а высота 116. Используйте инструмент скриншота, чтобы подтянуть ширину и высоту картинки, что в принципе совпадает.

Изображение 6

Следующий шаг – определить, как бороться.Простите, что говорю всем здесь, что свиньи больше нет.Когда я написал это здесь и пошел просматривать веб-страницу, картинка уже была обновлена. Так что следующие скрины могут быть другими, тут я вам заранее объясню. В любом случае, это найти характерные точки, они должны быть на каждой картинке. Сначала случайным образом найдите характерную точку, посмотрите на элемент, убедитесь, что он расположен в этом элементе div, а затем посмотрите на позицию сзади. В основном это так, поэтому, поскольку мы ищем изображения, связанные с позицией, нам лучше выбрать некоторые места с очевидными позициями, например, середину или обе стороны.

Рисунок 7

Это почти среднее положение, неважно, если вы его немного проверите.

Рисунок 8

Пойду, это... Это не совсем то, что я думал, давайте найдем еще два, чтобы посмотреть, репрезентативность очень сильная

Рисунок 9
Рисунок 10
Рисунок 11
Рисунок 12

Для того, чтобы кто-то не сказал, что у меня водные слова, в двух других углах не будет скринов. В этот момент некоторые люди могут задаться вопросом, почему? Вы только что сказали, что ширина картинки 260. Почему в координате фигурирует такая координата, как 289? Разве это не превышение стандарта? В начале у меня тоже были такие сомнения.Может мы увидели,что картинка меньше реальной,а может кто-то оставил рамку за пределами картинки.Я сначала так и думал. Но эта координата является координатой изображения в предыдущем URL-адресе, а затем я взглянул на рисунок 4.

Рисунок 13

Эта картинка относительно большая, и у задачи координат есть ответ, но какое это имеет отношение к 260? Зашифрованное изображение больше, а написанное по буквам меньше, так как же оно пишется? К счастью, мы увидели более полезную информацию

Видите это -1px? Это удачно привлекло мое внимание, потому что по моей задумке, если вынуть часть пазла, чтобы получилась законченная картинка, то вынутая крайняя слева картинка должна быть из (0,0), (0,58 ) , но мы видим (1,0), (1,58), значение y все еще соответствует нашим ожиданиям, первая часть начинается с 0, максимум 58, а вторая часть начинается с 58. Но есть проблема со значением х. Согласно 1 как начальная точка, второй должен быть 11, потому что ширина 10, что точно, давайте искать его

Это 13. Есть ли лишний пиксель перед каждым маленьким блоком? В соответствии с этим должно быть также 12. Таким образом, мы продолжаем находить остальные.Путем анализа мы обнаруживаем, что +12 для каждого маленького блока используется в качестве отправной точки для следующего маленького блока. В этом случае слева и справа удалено по одному пикселю, разве ширина не 10? И каждый маленький кусочек равен 12, 26 — это 312, что похоже на размер головоломки, которую мы видели, что указывает на то, что наш анализ верен. В соответствии с координатами, указанными в элементе, примите размер ширины равным 10. Далее проанализируем значение этих координат.

Координатный анализ

Давайте проанализируем скриншоты с рисунка 9 по рисунок 12. Прежде всего, поговорим о рисунке 9. Я изначально думал, что его x и y должны быть равны 0. Даже если это не 0, это должны быть числа. 58. Это вторая половина картинки.Площади больше нет, x равно 157, бегущей полузащиты нет. На рисунке 11 ваш x должен быть около 300, а y должен быть выше 100. Результат равен 0. В первом тайме x равен 205. После полузащиты до вратаря еще далеко. Что за чертовщина? Однако мы обнаружили, что первым в элементе является рисунок 9, а последним в элементе — рисунок 11. Значения y перед объединенными координатами — все 58, а значения y сзади — все 0, что соответствует нижней половине нашей первой половины.Идея абзаца меняется на противоположную, а затем вы посмотрите на элементы в правой части рисунка 9/слева на рисунке 11, и вы обнаружите что порядок такой же, как порядок элементов div в элементе. Почти готово.

Подводя итог: финальная картинка состоит в том, чтобы вырезать пазл, а именно рисунок 4, согласно x=157, y=58, w=10, h=58, и поместить его в первую позицию верхней части, x= 145, y=58 , w=10, h=58 вырезаются и помещаются во вторую позицию верхней половины, рядом с первой и так далее, чтобы получилась цельная картина.

Рисунок 14

Это то, что я объяснила, эм, очень хороший, очень хороший мальчик. Но, кажется, что-то не так, зазор. Присмотритесь к элементам веб-страницы

Рисунок 15

Оказывается, один fullbg, а другой cutbg.Имя очень многозначительное.Это хорошо.Напишем по буквам cutbg и посмотрим.

Рисунок 16
картина

Прямо на этот раз. Теперь возникает вопрос, как рассчитать позицию гэпа.

Положение выемки

Я думаю, может быть способ вычислить разные положения двух картинок, Ду Ньянг отправит его, а затем получит.Фактический бой Python === Используйте Python, чтобы сравнить разницу между двумя картинками, а потом нашел интерфейс ImageChops.difference.Как вы понимаете, он не точный.Зачем вы его зажимаете? Посмотрите внимательно на две собранные картинки, кроме щели, есть и другие места, которые отличаются. Тень за выемкой на рисунке 16 бросает тень на мое сердце. Когда я смотрю на другие изображения, они в основном похожи. Что мне делать? Это можно будет сказать потом, если он впереди, то засчитается в тени. Было бы здорово, если бы был допуск для этого сравнения.У меня такое было, когда я пользовался мастером кнопок.Разве это не умно? Поскольку это пиксель сравнения, я могу просто взять пиксель и сравнить его, и я не использую для него ==, а задаю диапазон.Если разница в цвете находится в этом диапазоне, она будет такой же. нет ли толерантности? Этот разрыв обычно очень заметен, а тень и фон очень размыты, что вполне возможно. Идея состоит в том, чтобы получить ширину и высоту изображения, а затем пройти и сравнить его попиксельно.

Хроматическая аберрация

Как определяется эта цветовая разница? Один из способов — отладка, что более проблематично, а другой способ — получить несколько изображений, полных изображений и изображений дефектов, а затем использовать инструмент выбора цвета, чтобы получить значение цвета соответствующей позиции, чтобы определить приблизительный диапазон. Расстояние определено, следующий шаг - двигаться

селен имитировать мобильный

Операция моделирования селена широко представлена ​​в Интернете, здесь нам просто нужно подтвердить, какие интерфейсы нужны. Метод ActionChains:

  • move_to_element(to_element) - подвести мышь к элементу
  • click_and_hold(on_element =None) - нажать левую кнопку мыши, не отпуская
  • move_by_offset(xoffset, yoffset) - переместить мышь из текущей позиции в определенную координату
  • release(on_element = None) — отпустить левую кнопку мыши на элементе
  • perform() - выполнить действие, помните, что это очень важно, после вызова вышеупомянутого метода вы должны выполнить выполнение, чтобы фактически выполнить

Подробно описывать работу селена не буду, здесь используется простое употребление.

Принципиальный разбор закончен, на этот раз код надо выложить, иначе многие не смогут его доделать, что тоже способствует всеобщему пониманию.

# -*- coding: utf-8 -*-
import random
import time, 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
from PIL import Image
import requests
from io import BytesIO

class HuXiu(object):
    def __init__(self):
        chrome_option = webdriver.ChromeOptions()
        # chrome_option.set_headless()

        self.driver = webdriver.Chrome(executable_path=r"/usr1/webdrivers/chromedriver", chrome_options=chrome_option)
        self.driver.set_window_size(1440, 900)

    def visit_index(self):
        self.driver.get("https://www.huxiu.com/")

        WebDriverWait(self.driver, 10, 0.5).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, 0.5).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"]')

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

        # 保存图片方便查看
        cut_image.save("cut.jpg")
        full_image.save("full.jpg")

        # 根据两个图片计算距离
        distance = self.get_offset_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(5)
            # 失败后递归执行拖动
            self.analog_drag()
        else:
            # 成功后输入手机号,发送验证码
            self.register()

    # 获取图片和位置列表
    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)))
            image_url = url
        return image_url, location

    # 拼接图片
    def mosaic_image(self, image_url, location):
        resq = requests.get(image_url)
        file = BytesIO(resq.content)
        img = Image.open(file)
        image_upper_lst = []
        image_down_lst = []
        for pos in location:
            if pos[1] == 0:
                # y值==0的图片属于上半部分,高度58
                image_upper_lst.append(img.crop((abs(pos[0]), 0, abs(pos[0]) + 10, 58)))
            else:
                # y值==58的图片属于下半部分
                image_down_lst.append(img.crop((abs(pos[0]), 58, abs(pos[0]) + 10, img.height)))

        x_offset = 0
        # 创建一张画布,x_offset主要为新画布使用
        new_img = Image.new("RGB", (260, img.height))
        for img in image_upper_lst:
            new_img.paste(img, (x_offset, 58))
            x_offset += img.width

        x_offset = 0
        for img in image_down_lst:
            new_img.paste(img, (x_offset, 0))
            x_offset += img.width

        return new_img

    # 判断颜色是否相近
    def is_similar_color(self, x_pixel, y_pixel):
        for i, pixel in enumerate(x_pixel):
            if abs(y_pixel[i] - pixel) > 50:
                return False
        return True

    # 计算距离
    def get_offset_distance(self, cut_image, full_image):
        for x in range(cut_image.width):
            for y in range(cut_image.height):
                cpx = cut_image.getpixel((x, y))
                fpx = full_image.getpixel((x, y))
                if not self.is_similar_color(cpx, fpx):
                    img = cut_image.crop((x, y, x + 50, y + 40))
                    # 保存一下计算出来位置图片,看看是不是缺口部分
                    img.save("1.jpg")
                    return x

    # 开始移动
    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 > 10:
                # 如果距离大于10,就让他移动快一点
                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,50)/100)
        
        ActionChains(self.driver).move_by_offset(distance, 1).perform()
        ActionChains(self.driver).release(on_element=element).perform()

    def register(self):
        element = self.driver.find_element_by_xpath('//input[@id="sms_username"]')
        element.clear()
        element.send_keys("手机号")

        ele_captcha = self.driver.find_element_by_xpath('//span[@class="js-btn-captcha btn-captcha"]')
        ele_captcha.click()

if __name__ == "__main__":
    h = HuXiu()
    h.visit_index()

Это move_by_offset, мое предыдущее значение y также случайное [-5,5], я думаю, что эта симуляция будет более реалистичной, она всегда будет трястись вверх и вниз, результат в том, что это соображение слишком человеческое, скорость распознавания очень низкая , я менял очень много диапазонов, больше и меньше, и результат в итоге не сместился, а скорость распознавания была крайне высокой. TMD подумал, что это слишком по-человечески, чтобы распознать его, и я тоже был пьян. Наконец, давайте опубликуем эффект выполнения.


Если вы считаете мою статью приемлемой, вы можете подписаться на мой публичный аккаунт в WeChat:Боевая дорога на гусеничном ходу Python

WeChat.QQ.com/Day/Q IQ B мужчина0…(автоматическое распознавание QR-кода)