草庐IT

Python + selenium 解决验证码问题思路(超详细)

官麒 2025-04-24 原文

提示:这里提供 selenium 破解验证码的思路,使用打码平台从而破解验证码

文章目录

文章目录

一、第一步剖析平台验证码类型

二、编写selenium代码

1.引入库 所需要的模块

2. 定义一个初始属性

3.找到账户登录的元素然后点击

4.短信验证登录

5.找到手机号输入框

6.输入手机号之后会有这样类型的验证码

7.找到验证码1图片的url地址

8.找到验证码2图片的url地址

9. 现在可以按照思路编写代码了

10.获取到两张验证码的url 下载它们

11.合成两张图片为一张图片

         12.合成图片之后就变成了

13.接入打码平台 然后把合成好的图片上传到接口

14.处理好坐标数据之后就模拟人的操作来点击验证码​编辑

15. from yun import base64_api 是打码平台的文件

        三 、总结:下面是全部代码


一、第一步剖析平台验证码类型

这里我用唯品会做案例,我们先分析登录接口有没有 frame页面。

 

通过元素定位发现 body标签下都没有frame,这样子可以判定直接可以定位网站登录的元素,不用切换到frame子页面。

 

 

二、编写selenium代码

1.引入库 所需要的模块

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import requests
import time
from PIL import Image
from selenium.webdriver.common.action_chains import ActionChains
from yun import base64_api

2. 定义一个初始属性

class Get_url(object):
    def __init__(self):
        # 初始化谷歌驱动
        self.driver = webdriver.Chrome()
        self.url = 'https://passport.vip.com/login?src=https%3A%2F%2Forder.vip.com%2Forder%2Forderlist'

3.找到账户登录的元素然后点击

我这边使用xpath定位,找到账户登录的元素然后使用selemiun点击

 

4.短信验证登录

找到短信验证登录的元素然后使用selemiun点击


 

5.找到手机号输入框

使用xpath定位元素

 

6.输入手机号之后会有这样类型的验证码

现在的思路是要找到图片的url地址

 7.找到验证码1图片的url地址

8.找到验证码2图片的url地址

9. 现在可以按照思路编写代码了

因为程序运行的太快所以要让程序休眠2秒钟,这个方法的目的就是获取验证码1,验证码2的url地址

    def run(self):
        img_url = []
        # 访问wph url
        self.driver.get(self.url)
        # 找到账户登录 然后模拟点击
        self.driver.find_element(By.XPATH, '/html/body/div[2]/div/div[1]/div[1]/div/div[1]/div[2]').click()
        time.sleep(2)

        # 点击短信验证
        self.driver.find_element(By.XPATH, '//*[@id="J_login_form"]/div[5]/div/div/div[1]/a').click()
        time.sleep(2)

        # 输入手机号
        self.driver.find_element(By.XPATH, '//*[@id="J_mobile_login_phone"]').send_keys(输入自己的手机号)
        time.sleep(3)

        # 获取验证码图片1 url
        aa = self.driver.find_element(By.XPATH, '//div[@class="c-tab-content"]/div[2]/div[2]/div/div[3]/div/div/div/div/div/div/img').get_attribute('src')
        # 把url添加到列表
        img_url.append(aa)
        time.sleep(1)
        # 获取验证码图片2
        bb = self.driver.find_element(By.XPATH, '//div[@class="vipsc_code_pop vipsc_d_hide"]/div/img').get_attribute('src')
        # 把图片二添加到列表
        img_url.append(bb)
        # 返回列表
        return img_url

 10.获取到两张验证码的url 下载它们

    # requests 下载两张图片
    def get_conten(self, img_url):
        # 用 enumerate函数遍历 index返回url_deta坐标
        for index, url_date in enumerate(img_url):
            # 下载图片 图片以下标命名 保存到本目录下
            res = requests.get(url_date).content
            with open(f'{index}.jpg', mode='wb') as f:
                f.write(res)
                print('写入完成')

11.合成两张图片为一张图片

因为后面要上传验证码到打码平台,所以要把条件验证码 和 验证码 合成一张图片

    # 合成两张照片
    def blend_two_images2(self):
        # 打开需要点击的验证码图片
        img1 = Image.open("1.jpg")

        img1 = img1.convert('RGBA')

        # 打开条件的验证码图片
        img2 = Image.open("0.jpg")

        img2 = img2.convert('RGBA')

        r, g, b, alpha = img2.split()

        alpha = alpha.point(lambda i: i > 0 and 204)

        img = Image.composite(img2, img1, alpha)

        img.show()
        # 保存合成后的图片并命名为wph.png
        img.save("wph.png")

        return

12.合成图片之后就变成了

把条件验证码合成到了里面

 13.接入打码平台 然后把合成好的图片上传到接口

上传之后接口会返回   11|21,31|41,51|61  这样的坐标我们需要处理一下数据

    def obtain_xy(self):
        # 云打码 解析图片路径  (获取图片之后提交给打码平台)
        img_path = 'wph.png'
        # 写入平台的账户名 密码 然后传入照片 选择验证码类型
        rrr = base64_api(uname=(输入平台的用户名), pwd=(输入平台的密码), img=img_path, typeid=20)
        # 接收平台返回的信息 然后分割处理成自己想要的信息格式 ['11,21','31,41','51,61']的格式
        xydate = rrr.split('|')

        list_xy = []
        # 循坏遍历数据 然后放到列表
        for i in xydate:
            list_xy.append(i)
        # 传入参数到click方法
        # res.click(list_xy)
        return list_xy

14.处理好坐标数据之后就模拟人的操作来点击验证码

    #  定位验证码图片位置
    def run_tow(self):
        element = self.driver.find_element(By.XPATH, '//div[@class="ui-form-item-group"]/div/div/div/div/div/img')
        # 把鼠标悬停到该元素 验证码2才会出来
        ActionChains(self.driver).move_to_element(element).perform()

    # 解析坐标列表 ['1,2','3,4','5,6']的格式分析
    def click(self, i):
        # 这是'1,2'坐标格式
        xy1 = i[0].split(',')
        # 这是'3,4'
        xy2 = i[1].split(',')
        # '5,6'
        xy3 = i[2].split(',')

        # 定位验证码2的元素
        click1 = self.driver.find_element(By.XPATH, '//div[@class="ui-form-item-group"]/div/div/div/div[2]/div/img')
        # 使用动作链完成验证码点击坐标1 并让程序延迟1秒执行
        ActionChains(self.driver).move_to_element_with_offset(click1, xy1[0], xy1[1]).click().perform()
        time.sleep(1)
        # 使用动作链完成验证码点击坐标2 并让程序延迟1秒执行
        ActionChains(self.driver).move_to_element_with_offset(click1, xy2[0], xy2[1]).click().perform()
        time.sleep(1)
        # 使用动作链完成验证码点击坐标3 并让程序延迟1秒执行
        ActionChains(self.driver).move_to_element_with_offset(click1, xy3[0], xy3[1]).click().perform()
        time.sleep(1)
        # 点击获取验证码
        self.driver.find_element(By.XPATH, '//div[@class="sms-component-wrap"]/div/div/div/div/div/a').click()
        # 点击登录
        self.driver.find_element(By.XPATH, '//*[@id="J_mobile_login_submit"]').click()

 

15. from yun import base64_api 是打码平台的文件

读者可以找打码平台的文件下来,作者这边用的是云打码平台

以下是云打码文件的内容

import base64
import json
import requests
# 一、图片文字类型(默认 3 数英混合):
# 1 : 纯数字
# 1001:纯数字2
# 2 : 纯英文
# 1002:纯英文2
# 3 : 数英混合
# 1003:数英混合2
#  4 : 闪动GIF
# 7 : 无感学习(独家)
# 11 : 计算题
# 1005:  快速计算题
# 16 : 汉字
# 32 : 通用文字识别(证件、单据)
# 66:  问答题
# 49 :recaptcha图片识别
# 二、图片旋转角度类型:
# 29 :  旋转类型
#
# 三、图片坐标点选类型:
# 19 :  1个坐标
# 20 :  3个坐标
# 21 :  3 ~ 5个坐标
# 22 :  5 ~ 8个坐标
# 27 :  1 ~ 4个坐标
# 48 : 轨迹类型
#
# 四、缺口识别
# 18 : 缺口识别(需要2张图 一张目标图一张缺口图)
# 33 : 单缺口识别(返回X轴坐标 只需要1张图)
# 五、拼图识别
# 53:拼图识别
def base64_api(uname, pwd, img, typeid):
    with open(img, 'rb') as f:
        base64_data = base64.b64encode(f.read())
        b64 = base64_data.decode()
    data = {"username": uname, "password": pwd, "typeid": typeid, "image": b64}
    result = json.loads(requests.post("http://api.ttshitu.com/predict", json=data).text)
    if result['success']:
        return result["data"]["result"]
    else:
        return result["message"]
    return


if __name__ == "__main__":
    img_path = 'wph.png'
    result = base64_api(uname='nameguan', pwd='1111', img=img_path, typeid=27)
    print(result)

三 总结:下面是全部代码

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import requests
import time
from PIL import Image
from selenium.webdriver.common.action_chains import ActionChains
from yun import base64_api

"""
思路: 1找到能发验证码url网址然后 selenium自动化点击手机验证

"""

class Get_url(object):
    def __init__(self):
        # 初始化谷歌驱动
        self.driver = webdriver.Chrome()
        self.url = 'https://passport.vip.com/login?src=https%3A%2F%2Forder.vip.com%2Forder%2Forderlist'

    # 输入手机号
    def run(self):
        img_url = []
        # 访问wph url
        self.driver.get(self.url)
        self.driver.maximize_window()
        # 找到账户登录 然后点击
        self.driver.find_element(By.XPATH, '/html/body/div[2]/div/div[1]/div[1]/div/div[1]/div[2]').click()
        time.sleep(2)

        # 点击短信验证
        self.driver.find_element(By.XPATH, '//*[@id="J_login_form"]/div[5]/div/div/div[1]/a').click()
        time.sleep(2)

        # 输入手机号
        self.driver.find_element(By.XPATH, '//*[@id="J_mobile_login_phone"]').send_keys('110')
        time.sleep(3)

        # 获取验证码图片1 url
        aa = self.driver.find_element(By.XPATH, '//div[@class="c-tab-content"]/div[2]/div[2]/div/div[3]/div/div/div/div/div/div/img').get_attribute('src')
        # 把url添加到列表
        img_url.append(aa)
        time.sleep(1)
        # 获取验证码图片2
        bb = self.driver.find_element(By.XPATH, '//div[@class="vipsc_code_pop vipsc_d_hide"]/div/img').get_attribute('src')
        # 把图片二添加到列表
        img_url.append(bb)
        # 返回列表
        return img_url

    # requests 下载两张图片
    def get_conten(self, img_url):
        # 用 enumerate函数遍历 index返回url_deta坐标
        for index, url_date in enumerate(img_url):
            # 下载图片 图片以下标命名 保存到本目录下
            res = requests.get(url_date).content
            with open(f'{index}.jpg', mode='wb') as f:
                f.write(res)
                print('写入完成')

    # 合成两张照片
    def blend_two_images2(self):
        # 打开需要点击的验证码图片
        img1 = Image.open("1.jpg")

        img1 = img1.convert('RGBA')

        # 打开条件的验证码图片
        img2 = Image.open("0.jpg")

        img2 = img2.convert('RGBA')

        r, g, b, alpha = img2.split()

        alpha = alpha.point(lambda i: i > 0 and 204)

        img = Image.composite(img2, img1, alpha)

        img.show()
        # 保存合成后的图片并命名为wph.png
        img.save("wph.png")

        return

    def obtain_xy(self):
        # 云打码 解析图片路径  (获取图片之后提交给打码平台)
        img_path = 'wph.png'
        # 写入平台的账户名 密码 然后传入照片 选择验证码类型
        rrr = base64_api(uname='nameguan', pwd='11111', img=img_path, typeid=20)
        # 接收平台返回的信息 然后分割处理成自己想要的信息格式 ['11,21','31,41','51,61']的格式
        xydate = rrr.split('|')

        list_xy = []
        # 循坏遍历数据 然后放到列表
        for i in xydate:
            list_xy.append(i)
        # 传入参数到click方法
        # res.click(list_xy)
        return list_xy

    #  定位验证码图片位置
    def run_tow(self):
        element = self.driver.find_element(By.XPATH, '//div[@class="ui-form-item-group"]/div/div/div/div/div/img')
        # 把鼠标悬停到该元素 验证码2才会出来
        ActionChains(self.driver).move_to_element(element).perform()

    # 解析坐标列表 ['1,2','3,4','5,6']的格式分析
    def click(self, i):
        # 这是'1,2'坐标格式
        xy1 = i[0].split(',')
        # 这是'3,4'
        xy2 = i[1].split(',')
        # '5,6'
        xy3 = i[2].split(',')

        # 定位验证码2的元素
        click1 = self.driver.find_element(By.XPATH, '//div[@class="ui-form-item-group"]/div/div/div/div[2]/div/img')
        # 使用动作链完成验证码点击坐标1 并让程序延迟1秒执行
        ActionChains(self.driver).move_to_element_with_offset(click1, xy1[0], xy1[1]).click().perform()
        time.sleep(1)
        # 使用动作链完成验证码点击坐标2 并让程序延迟1秒执行
        ActionChains(self.driver).move_to_element_with_offset(click1, xy2[0], xy2[1]).click().perform()
        time.sleep(1)
        # 使用动作链完成验证码点击坐标3 并让程序延迟1秒执行
        ActionChains(self.driver).move_to_element_with_offset(click1, xy3[0], xy3[1]).click().perform()
        time.sleep(1)
        # 点击获取验证码
        self.driver.find_element(By.XPATH, '//div[@class="sms-component-wrap"]/div/div/div/div/div/a').click()
        # 点击登录
        self.driver.find_element(By.XPATH, '//*[@id="J_mobile_login_submit"]').click()



if __name__ == '__main__':
    res = Get_url()
    img_url = res.run()
    # 把img传入
    res.get_conten(img_url)
    res.blend_two_images2()

    i = res.obtain_xy()
    # 把i传入
    res.run_tow()
    res.click(i)

提示:这里对文章进行总结:

以上的思路总结是:

需要找到平台的验证码然后下载处理后上传至打码平台,然后打码平台返回坐标,之后就用selenium处理坐标然后点击

有关Python + selenium 解决验证码问题思路(超详细)的更多相关文章

  1. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  2. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  3. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  4. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

  5. ruby - 通过 rvm 升级 ruby​​gems 的问题 - 2

    尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub

  6. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  7. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  8. ruby - 通过 RVM (OSX Mountain Lion) 安装 Ruby 2.0.0-p247 时遇到问题 - 2

    我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search

  9. ruby - Fast-stemmer 安装问题 - 2

    由于fast-stemmer的问题,我很难安装我想要的任何ruby​​gem。我把我得到的错误放在下面。Buildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingfast-stemmer:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcreatingMakefilemake"DESTDIR="cleanmake"DESTDIR=

  10. ruby-on-rails - 如何将验证与模型分开 - 2

    我有一些非常大的模型,我必须将它们迁移到最新版本的Rails。这些模型有相当多的验证(User有大约50个验证)。是否可以将所有这些验证移动到另一个文件中?说app/models/validations/user_validations.rb。如果可以,有人可以提供示例吗? 最佳答案 您可以为此使用关注点:#app/models/validations/user_validations.rbrequire'active_support/concern'moduleUserValidationsextendActiveSupport:

随机推荐