【selenium关键补充】——全栈开发——如桃花来

selenium验证码处理:

在selenium的控制下,我们手动输入验证码很可能被网站识别为爬虫,所以我们需要进行自动处理
验证码处理分为两种方式,一种是截图形式

截图:

数字&文字&字母验证码--------根据图片输入:

from selenium import webdriver
from PIL import Image
from requests_html import HTMLSession

session = HTMLSession()
import base64
import time
driver = webdriver.Chrome()
# 窗口最大化
driver.maximize_window()
start_url = 'http://www.jianjiaoshuju.com/path/login.htm'
driver.get(start_url)


#第一种:通过截图
driver.find_element_by_xpath('/html/body/div[2]/div/div[1]/ul/li[1]/input').send_keys('16607440667')
driver.find_element_by_xpath('/html/body/div[2]/div/div[1]/ul/li[2]/input').send_keys('songxu3523520')
#核心操作 (一):通过截图,获得验证码图片,直接复制照搬即可
'''
driver.save_screenshot('首页.png')
#获取验证码所在的标签
img = driver.find_element_by_xpath('/html/body/div[2]/div/div[1]/ul/li[3]/div/span/img')
#实例化标签对象
location = img.location
#获取标签大小
size = img.size
# 获取验证码上下左右的坐标
#该位置的坐标是根据电脑不同的分辨率计算的,后面+的数字可以直接删掉,如果二次截图截的不准确,就通过加值进行微调
left = location['x'] + 300
top = location['y'] + 110
right = left + size['width'] + 20
bot = top + size['height'] + 10
#打开首页.png图片,这里是二次截图
photo = Image.open('首页.png')
img_obj = photo.crop((left, top, right, bot))
img_obj.save('验证码.png')
#对接第三方平台,导入超级鹰等包
#操作省略
 """
# AppCode:	20B9054575C6917DE9BC05175DDAD2D2
# AppKey:	AKIDa0fac224bccad10c4ea86d9b73bd4f62
# AppSecret:	a5a51b5a2cff7dcd5fdc9cd82d11e7bd
#
# 
'''
#核心操作(二):直接获取验证码图片
# 定位验证码所在的标签位置
img_obj = driver.find_element_by_xpath('/html/body/div[2]/div/div[1]/ul/li[3]/div/span/img')
# 截图 ---- 直接截图
img_obj.screenshot('验证码2.png')
"""验证码图片base64加密字符串"""
with open('验证码2.png', 'rb')as f:
    base64_data = base64.b64encode(f.read()).decode()
img_url = 'http://apigateway.jianjiaoshuju.com/api/v_1/yzm.html'
headers = {
    'AppCode': '20B9054575C6917DE9BC05175DDAD2D2',
    'AppKey': 'AKIDa0fac224bccad10c4ea86d9b73bd4f62',
    'AppSecret': 'a5a51b5a2cff7dcd5fdc9cd82d11e7bd'
}

data = {
    'v_pic': base64_data,
    'v_type': 'ne4'
}

response = session.post(img_url, data=data, headers=headers).json()
img_code = response['v_code']
driver.find_element_by_xpath('/html/body/div[2]/div/div[1]/ul/li[3]/div/div/input').send_keys(img_code)
driver.find_element_by_xpath('/html/body/div[2]/div/div[1]/ul/li[4]/button').click()
time.sleep(1)
driver.find_element_by_xpath('//*[@id="layui-layer2"]/div[3]/a').click()

滑块验证码--------以豆瓣为例(对接打码平台计算滑动距离):

from selenium import webdriver
from requests_html import HTMLSession
import base64
session = HTMLSession()
import time
driver = webdriver.Chrome()
driver.implicitly_wait(10)
# 窗口最大化
driver.maximize_window()
start_url = 'https://accounts.douban.com/passport/login_popup?login_source=anony'
driver.get(start_url)
# 点击密码登录
driver.find_element_by_xpath('/html/body/div[1]/div[1]/ul[1]/li[2]').click()
driver.find_element_by_id('username').send_keys('16607440667')
driver.find_element_by_id('password').send_keys('aef123456')
driver.find_element_by_xpath('/html/body/div[1]/div[2]/div[1]/div[5]/a').click()
"""在登录之后会弹出验证码"""
time.sleep(10)
el_iframe_1 = driver.find_element_by_id('tcaptcha_iframe')
driver.switch_to.frame(el_iframe_1)
# 定位滑动验证码标签位置
img_obj = driver.find_element_by_css_selector('#slideBg')
print(img_obj)
# 保存验证码
img_obj.screenshot('豆瓣.png')
"""核心部分"""
headers = {
    'AppCode': '20B9054575C6917DE9BC05175DDAD2D2',
    'AppKey': 'AKIDa0fac224bccad10c4ea86d9b73bd4f62',
    'AppSecret': 'a5a51b5a2cff7dcd5fdc9cd82d11e7bd'
}
with open('豆瓣.png', 'rb')as f:
    base64_data = base64.b64encode(f.read()).decode()
img_url = 'http://apigateway.jianjiaoshuju.com/api/v_1/yzmCrd.html'
data = {
    'v_pic': base64_data,
    'v_type': 'sld'
}
response = session.post(img_url, headers=headers, data=data).json()
print(response)

图案点击验证码--------B站登录案例:

# !/usr/bin/env python
# -*- coding: utf-8 -*-
# ------------------------------

import time, base64, json, requests
from selenium import webdriver
from selenium.webdriver import ActionChains


# def main():
# 1、实例化 driver对象
driver = webdriver.Chrome()
driver.maximize_window()
driver.get(r'https://passport.bilibili.com/login')
driver.implicitly_wait(10)

# aef、定位 账号 和 密码标签
driver.find_element_by_id('login-username').send_keys(r'')
time.sleep(2)
driver.find_element_by_id('login-passwd').send_keys('')
time.sleep(2)
driver.find_element_by_css_selector('#geetest-wrap > div > div.btn-box > a.btn.btn-login').click()

# 3、获取弹窗验证图片
time.sleep(2)
driver_img = driver.find_element_by_css_selector('body > div.geetest_panel.geetest_wind > div.geetest_panel_box.geetest_no_logo.geetest_panelshowclick > div.geetest_panel_next > div')
driver_img.screenshot('验证码.png')
time.sleep(3)

# 4、对接打码平台
print(r'-----------------------------正在对接打码平台--------------------------------' + '\n')
with open('./验证码.png', 'rb') as f:
    base64_data = base64.b64encode(f.read())
    b64 = base64_data.decode()
data = {"username": '15675209157', "password": 'q6631801', "image": b64, 'typeid': 21}
result = json.loads(requests.post("http://api.ttshitu.com/imageXYPlus", json=data).text)
if result['success']:
    code_result = result["data"]["result"]
else:
    code_result = result["message"]
print(r'----------------识别成功:当前验证码识别结果为:{}---------'.format(code_result) + '\n')

# 5、获取验证字 定位
print(r'-----------------------------正在点击验证码----------------------------------' + '\n')
for code in code_result.split(r'|'):
    x = int(code.split(',')[0])
    y = int(code.split(',')[1])

    # 6、设置验证码点击方式
    ActionChains(driver).move_to_element_with_offset(driver_img, x, y).click().perform()
    time.sleep(1)
print(r'--------------------------------验证码点击完成---------------------------------' + '\n')

# 点击确定,登录账号
time.sleep(3)
driver.find_element_by_css_selector('body > div.geetest_panel.geetest_wind > div.geetest_panel_box.geetest_no_logo.geetest_panelshowclick > div.geetest_panel_next > div > div > div.geetest_panel > a > div').click()
print(r'---------------------------------账号登录成功----------------------------------')

京东登录案例(参考:精确度低)--------滑动验证<计算型>:

from 案例文件夹.selenium处理验证码 import pwd
from selenium.webdriver import ActionChains
from urllib import request
from selenium import webdriver
import numpy as np
import time, cv2


"""创建driver对象"""
driver = webdriver.Chrome()
driver.maximize_window()


"""准备起始的访问url地址"""
start_url = 'https://www.jd.com/'


"""访问"""
driver.get(start_url)
time.sleep(2)


"""跳转登录页面"""
driver.find_element_by_link_text('你好,请登录').click()
time.sleep(1.5)


"""账号密码登录"""
driver.find_element_by_link_text('账户登录').click()


"""账户密码输入"""
driver.find_element_by_id('loginname').send_keys('16607440667')
driver.find_element_by_id('nloginpwd').send_keys(pwd)


"""登录按钮点击"""
driver.find_element_by_id('loginsubmit').click()


"""获取验证码缺口图片url地址"""
# 背景缺口图链接
backimgUrl = driver.find_element_by_xpath(r'//div/div[@class="JDJRV-bigimg"]/img').get_attribute("src")
# 块状缺口链接
gapUrl = driver.find_element_by_xpath(r'//div/div[@class="JDJRV-smallimg"]/img').get_attribute("src")
request.urlretrieve(backimgUrl, "backing.png")
request.urlretrieve(gapUrl, "gap.png")


"""将图片灰度化"""
# 获取图片并灰度化
block = cv2.imread("gap.png", 0)
template = cv2.imread("backing.png", 0)
# 二值化后的图片名称
blockName = "block.jpg"
templateName = "template.jpg"
# 将二值化后的图片进行保存
cv2.imwrite(blockName, block)
cv2.imwrite(templateName, template)
block = cv2.imread(blockName)
block = cv2.cvtColor(block, cv2.COLOR_RGB2GRAY)
block = abs(255 - block)
cv2.imwrite(blockName, block)
block = cv2.imread(blockName)
template = cv2.imread(templateName)
# 获取偏移量
result = cv2.matchTemplate(block, template,
                           cv2.TM_CCOEFF_NORMED)  # 查找block在template中的位置,返回result是一个矩阵,是每个点的匹配结果
x, y = np.unravel_index(result.argmax(), result.shape)
print(x, y)


"""计算滑动距离"""
print("需要移动的距离", y)
track = []  # 移动轨迹
current = 0  # 当前位移
# 减速阈值
mid = y * 4 / 5  # 前4/5段加速 后1/5段减速
t = 0.2  # 计算间隔
v = 0  # 初速度
while current < y:
    if current < mid:
        a = 3  # 加速度为+3
    else:
        a = -3  # 加速度为-3
    v0 = v  # 初速度v0
    v = v0 + a * t  # 当前速度
    move = v0 * t + 1 / 2 * a * t * t  # 移动距离
    current += move  # 当前位移
    track.append(round(move))  # 加入轨迹


"""执行滑动"""
slider = driver.find_elements_by_xpath(r'//div[@class="JDJRV-slide-inner JDJRV-slide-btn"]')[0]
ActionChains(driver).click_and_hold(slider).perform()
for x in track:  # 只有水平方向有运动 按轨迹移动
    ActionChains(driver).move_by_offset(xoffset=x-20, yoffset=0).perform()
time.sleep(1)
ActionChains(driver).release().perform()  # 松开鼠标

图案点击&滑块双重验证--------12306登录案例:

from my_Spider import user_12306, pass_wd_12306
from selenium import webdriver
from selenium.webdriver import ActionChains
driver = webdriver.Chrome()
from requests_html import HTMLSession
session = HTMLSession()
import time, base64, random

start_url = 'https://kyfw.12306.cn/otn/resources/login.html'
# 窗口最大化
driver.maximize_window()
driver.get(start_url)
# 点击账号登录
driver.find_element_by_xpath('/html/body/div[2]/div[2]/ul/li[2]/a').click()
driver.find_element_by_id('J-userName').send_keys(user_12306)
driver.find_element_by_id('J-password').send_keys(pass_wd_12306)
# 由于验证码只显示一半,需要执行窗口向下滑动
js = 'scrollTo(0, {})'.format(500)
driver.execute_script(js)
time.sleep(1)
# 定位验证码所在的标签
img_obj = driver.find_element_by_xpath('//*[@id="J-loginImg"]')
img_obj.screenshot('12306验证码.png')
# 读取验证码然后base64加密
with open('12306验证码.png', 'rb')as f:
    base64_data = base64.b64encode(f.read()).decode()

img_url = 'http://apigateway.jianjiaoshuju.com/api/v_1/yzmCrd.html'
data = {
    'v_pic': base64_data,
    'v_type': 'crd'
}
headers = {
    'AppCode': '20B9054575C6917DE9BC05175DDAD2D2',
    'AppKey': 'AKIDa0fac224bccad10c4ea86d9b73bd4f62',
    'AppSecret': 'a5a51b5a2cff7dcd5fdc9cd82d11e7bd',
    'user-agent': ua.chrome
}
response = session.post(img_url, headers=headers, data=data).json()
print(response)
"""对接打码平台"""
headers = {
    'AppCode': '20B9054575C6917DE9BC05175DDAD2D2',
    'AppKey': 'AKIDa0fac224bccad10c4ea86d9b73bd4f62',
    'AppSecret': 'a5a51b5a2cff7dcd5fdc9cd82d11e7bd',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36'
}
post_url = 'http://apigateway.jianjiaoshuju.com/api/v_1/yzmCrd.html'
with open('验证码12306.png', 'rb')as f:
    base64_data = base64.b64encode(f.read()).decode()
data = {
    'v_pic': base64_data,
    'v_type': 'crd'
}
response = session.post(post_url, headers=headers, data=data).json()
print(response)
v_code = response['v_code']
for code in v_code.split('|'):
    # 获取x坐标
    x = int(code.split(',')[0])
    # 获取y坐标
    y = int(code.split(',')[1])
    # 执行点击                                        验证码的对象,x,y
    ActionChains(driver).move_to_element_with_offset(img, x, y).click().perform()
    # 每次停留0.5秒,模拟人的判断
"""点击登录"""
time.sleep(random.randint(1, 2))
driver.find_element_by_id('J-login').click()

"""处理滑块验证码"""
# 定位滑块验证码的长度
div_size_obj = driver.find_element_by_xpath('//*[@id="nc_1__scale_text"]/span')
# 获取宽高
div_size = div_size_obj.size
# 定位滑块按钮位置
button = driver.find_element_by_xpath('//*[@id="nc_1_n1z"]')
# 实例化
button_location = button.location
# 鼠标拖动操作
# 计算出拖动距离
y = button_location['y']
print(y)  # 332
# 鼠标的拖动操作:
# ActionChains:可以控制鼠标,鼠标按钮操作,上下文切换等等
"""第一种模式"""
action = ActionChains(driver)
action.click_and_hold(button).perform()
action.move_by_offset(332, 0)
action.release().perform()
"""第二种模式"""
ActionChains(driver).click_and_hold(button).move_by_offset(y, 0).perform()

selenium控制标签页的切换:

窗口切换:
    -获取所有标签页的窗口句柄
    -利用窗口句柄字切换到句柄指向的标签页
    -窗口句柄:指的是指向标签页对象的标识

解析:

1.获取当前所有的标签页的句柄构成的列表

​current_windows = driver.window_handles

2.根据标签页句柄列表索引下标进行切换

driver.switch_to.window(current_windows[0])

代码演示:

from selenium import webdriver
import time
# 创建driver对象
driver = webdriver.Chrome()
# 访问的起始的url地址
start_url = 'https://www.baidu.com'
# 访问
driver.get(url=start_url)
time.sleep(1)
driver.find_element_by_id('kw').send_keys('python')
time.sleep(1)
driver.find_element_by_id('su').click()
time.sleep(1)

# 通过执行js来新开一个标签页
js = 'window.open("https://www.csdn.net");'
driver.execute_script(js)
time.sleep(1)

# 1.获取所有浏览器窗口
windows = driver.window_handles

# 2.根据窗口索引进行切换
driver.switch_to.window(windows[0])
time.sleep(1)
driver.switch_to.window(windows[1])

selenium控制iframe的切换:

iframe是html中常用的一种技术,即一个页面中嵌套了另一个网页,selenium默认是访问不了frame中的内容的,对应的解决思路是driver.switch_to.frame(frame_element)

代码演示:

# 网易邮箱登录

from selenium import webdriver
import time


def login(user, password):
    driver = webdriver.Chrome()
    driver.get("https://email2.163.com/")
    # browser.maximize_window()
    driver.switch_to.frame(driver.find_element_by_xpath('//iframe[starts-with(@id,"x-URS")]'))
    time.sleep(1)

    driver.find_element_by_xpath('//input[@name="email"]').send_keys(user)
    driver.find_element_by_xpath('//input[@name="password"]').send_keys(password)
    driver.find_element_by_xpath('//*[@id="dologin"]').click()

    time.sleep(2)
    print(driver.page_source)
    driver.save_screenshot("163.png")
    time.sleep(3)
    # driver.quit()


if __name__ == '__main__':
    login('163邮箱帐号', '密码')

对于ifame的语法补充:

1. 恢复默认页面方法

在frame表单中操作其他页面,必须先回到默认页面,才能进一步操作

driver.switch_to.default_content() 
2. 跳回最外层的页面

切换到最外层(对于多层页面,可通过该方法直接切换到最外层

driver.switch_to.default_content()
3. 跳回上层的页面

进行向上的单层切换

driver.switch_to.parent_frame()
4. 切换到定位的frame标签嵌套的页面中
driver.switch_to.frame(通过find_element_by函数定位的frame、iframe标签对象)
5. 利用切换标签页的方式切出frame标签
windows = driver.window_handles
driver.switch_to.window(windows[0]

利用selenium获取cookie的方法:

获取cookie:

#返回列表,其中包含的是完整的cookie信息,需要转换为字典.
driver.get_cookies() 

字典推导式转换:

#返回的列表中有好几个字典,我们可能会需要遍历循环,并取出里面的name和value组成键值对。来构成cookie信息
cookies_dict = {cookie['name']: cookie['value'] for cookie in driver.get_cookies()}

删除cookie:

删除一条cookie:

driver.delete_cookie('cookie_name')

删除所有的cookie:

driver.delete_all_cookies()

selenium使用代理IP:

#实例化配置对象
options = webdriver.ChromeOptions()
#配置对象添加使用代理ip的命令
options.add_argument('--proxy-server=http://202.20.16.82:9527')
#实例化带有配置对象的driver对象
driver = webdriver.Chrome('./chromedriver', chrome_options=options)

代码演示:

from selenium import webdriver

# 1.创建一个配置对象
options = webdriver.ChromeOptions()
# 2.使用代理
options.add_argument('--proxy-server=http://192.168.129.130')
# 3.创建driver对象
driver = webdriver.Chrome(options=options)
# 4.设置起始的url地址
start_url = 'https://www.baidu.com'
# 访问
driver.get(url=start_url)

selenium替换user-agent:

#替换user-agent的方法
#实例化配置对象
options = webdriver.ChromeOptions()
#配置对象添加替换UA的命令
options.add_argument('--user-agent=Mozilla/5.0 HAHA')
#实例化带有配置对象的driver对象
driver = webdriver.Chrome('./chromedriver', chrome_options=options)

代码演示:

from selenium import webdriver
from fake_useragent import UserAgent
ua = UserAgent()
# 1.创建一个配置对象
options = webdriver.ChromeOptions()
# 2.使用代理
options.add_argument('--user-agent={}'.format(ua.chrome))
# ua = 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Mobile Safari/537.36'
# options.add_argument('user-agent' + ua)
# 3.创建driver对象
driver = webdriver.Chrome(options=options)
# 4.设置起始的url地址
start_url = 'https://www.baidu.com'
# 访问
driver.get(url=start_url)
# 验证
js = 'return navigator.userAgent'
aa = driver.execute_script(js)
print(aa)

拓展知识点:

selenium防检测:

第一种:

from selenium import webdriver
from selenium.webdriver import ChromeOptions
 
option = ChromeOptions()     #实例化一个ChromeOptions对象
option.add_experimental_option('excludeSwitches', ['enable-automation'])  #以键值对的形式加入参数
 
bro = webdriver.Chrome(executable_path='./chromedriver.exe',options=option)  #在调用浏览器驱动时传入option参数就能实现

第二种(直接添加上去即可):

driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", { "source": """ Object.defineProperty(navigator, 'webdriver', { get: () => undefined }) """ })

selenium禁止弹窗:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options


chrome_options = Options()

# 禁止弹窗
prefs = {
        'profile.default_content_setting_values':
            {
                'notifications': 2
            }
    }
# 禁止弹窗加入
chrome_options.add_experimental_option('prefs', prefs)
driver = webdriver.Chrome(chrome_options=chrome_options)
driver.get(url)
# 就可以访问无通知弹窗的浏览器了

selenium清空输入:

from selenium import webdriver
import time

browser = webdriver.Chrome()
browser.maximize_window()  # 设置浏览器大小:全屏
browser.get('https://www.baidu.com')

# 定位输入框
input_box = browser.find_element_by_id('kw')
try:
    # 输入内容:selenium
    input_box.send_keys('selenium')
    print('搜索关键词:selenium')
except Exception as e:
    print('fail')
# 输出内容:搜索关键词:selenium

# 定位搜索按钮
button = browser.find_element_by_id('su')
try:
    # 点击搜索按钮
    button.click()
    print('成功搜索')
except Exception as e:
    print('fail搜索')
# 输出内容:成功搜索

# clear():清空输入框
try:
    input_box.clear()
    print('成功清空输入框')
except Exception as e:
    print('fail清空输入框')
# 输出内容:成功清空输入框

selenium模拟回车:

from selenium import webdriver
import time

browser = webdriver.Chrome()
browser.maximize_window()  # 设置浏览器大小:全屏
browser.get('https://www.baidu.com')

# 定位输入框
input_box = browser.find_element_by_id('kw')
# 输入关键词:selenium
input_box.send_keys('selenium')
# 模拟回车操作
try:
    input_box.submit()
    print('成功回车')
except Exception as e:
    print('fail')
# 输出内容:成功回车

selenium下拉框选择:

# 导入需要的模块Select()类是用来管理下拉框的
from selenium import webdriver
from selenium.webdriver.support.select import Select
import time
# 创建浏览器对象
driver = webdriver.Chrome()
driver.maximize_window()
# 访问贴吧的高级搜素
driver.get('https://tieba.baidu.com/f/search/adv')

# 定位到下拉框元素
el_select = driver.find_element_by_name('rn')
# 创建一个下拉框对象
xialakuang = Select(el_select)

# 三种方法选择下拉框选项
# 第一、通过选项的索引来选定选项(索引从0开始算)
xialakuang.select_by_index(0)
time.sleep(1)
xialakuang.select_by_index(2)
time.sleep(1)
xialakuang.select_by_index(1)
time.sleep(1)

# 第二种方法:通过option标签的属性值选择
xialakuang.select_by_value('20')
time.sleep(1)
xialakuang.select_by_value('10')
time.sleep(1)
xialakuang.select_by_value('30')
time.sleep(1)

# 第三种:通过文本选择(下拉框的值)
xialakuang.select_by_visible_text('每页显示20条')
time.sleep(1)
xialakuang.select_by_visible_text('每页显示10条')
time.sleep(1)
xialakuang.select_by_visible_text('每页显示30条')
time.sleep(1)

# 打印选择的文本
# 查看第一个已选(若有多个已选则打印第一个,只有一个已选则打印一个)
print(xialakuang.first_selected_option.text)
# 打印所有已选的选项的文本
yixuan = xialakuang.all_selected_options
for i in yixuan:
    print('已选',i.text)
# 打印是否是多选
print(xialakuang.is_multiple)
# 打印所有选项(包括已选和未选的)
m_list = xialakuang.options
for a in m_list:
    print('选项',a.text)

# # 关闭浏览器
# driver.quit()

selenium鼠标悬停:

from selenium.webdriver.common.action_chains import ActionChains
# 定位到需要悬停的标签
move = driver.find_element_by_id("xpath语法")
# 开始悬停
ActionChains(self.driver).move_to_element(move).perform()
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

如桃花来

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值