Java模拟淘宝登录源码分析与实现

Java模拟淘宝登录源码分析与实现

本文还有配套的精品资源,点击获取

简介:本文深入探讨了如何使用Java的HTTPClient库来模拟淘宝网的登录过程,涵盖了网络请求、HTTP协议、Cookie管理及HTML解析技术。文章首先介绍了HTTPClient库的基础知识,然后详细分析了登录过程,包括初始化HTTPClient、构建GET和POST请求、解析HTML、设置Cookie策略、执行POST请求、处理响应以及安全性和验证码处理等方面。本项目展示了使用HTTPClient进行模拟登录的完整流程,并强调了安全性和注意事项。

1. HTTPClient库概述

1.1 HTTPClient库的定位

HTTPClient库是现代网络编程中不可或缺的工具,它为开发者提供了一种方便的方式来发送和接收HTTP请求。无论是在Web应用、移动应用还是桌面应用开发中,该库都扮演着重要的角色。它的主要作用是简化HTTP通信的复杂性,使得开发者可以将精力集中在业务逻辑上。

1.2 常用的HTTPClient库

在各种编程语言中,都有流行的HTTPClient库。例如在Python中,requests库被广泛使用,而在Java中,Apache HttpClient和OkHttp等库则受到了开发者的青睐。不同的库提供了不同的接口和特性,但它们共同的目标是提供一个强大、稳定且易于使用的HTTP通信机制。

1.3 HTTPClient库的基本原理

HTTPClient库的基本原理是基于HTTP协议,使用Socket通信进行数据的发送和接收。一个典型的HTTP请求包含请求行、请求头、空行和请求体。而HTTP响应则包括状态行、响应头、空行和响应体。库通常提供了封装好的API,允许用户以编程方式指定请求方法(如GET、POST等)、URL、头部信息以及请求体等,然后库会处理底层的Socket连接和HTTP协议细节。

import requests

response = requests.get('https://api.example.com/data')

print(response.status_code)

在上述Python代码示例中,使用requests库发起一个GET请求,并打印返回状态码。这展示了HTTPClient库使用上简洁直观的一面,而背后的工作流程涉及到网络连接、协议解析、SSL/TLS加密等复杂操作。在后续章节中,我们将深入探讨如何使用HTTPClient库来模拟登录,以及在该过程中如何优化和处理安全问题。

2. 登录流程解析

在了解了HTTPClient库的基础知识之后,让我们深入了解网络登录流程的解析,特别是针对像淘宝这样的大型电商平台。本章节将首先分析网站的登录机制,然后深入探讨淘宝登录的特殊性,并绘制相应的流程图,以及探讨HTTP请求与响应的交互。

2.1 网站登录机制分析

在开始模拟登录之前,理解网站的登录机制是至关重要的。无论是简单的网站还是像淘宝这样的复杂电商平台,登录机制大体上遵循相同的基本原则和步骤。

2.1.1 登录流程图解

为了解释登录机制,我们可以创建一个简化的流程图来表示用户登录网站的基本步骤。使用Mermaid流程图工具,我们可以形象地描述这个过程。

graph LR

A[用户输入用户名和密码] --> B[发送HTTP请求到服务器]

B --> C[服务器验证用户名和密码]

C -->|成功| D[服务器返回登录成功响应]

C -->|失败| E[服务器返回登录失败响应]

D --> F[浏览器保存登录状态]

2.1.2 HTTP请求与响应交互

在实际操作中,HTTP请求和响应是登录流程的核心。了解HTTP请求的不同部分,例如请求头、请求体、响应头和响应体,对于掌握登录机制是必要的。

请求示例

POST /login HTTP/1.1

Host: www.example.com

Content-Type: application/x-www-form-urlencoded

Cookie: session=GUID1234

username=exampleUser&password=examplePass

响应示例

HTTP/1.1 200 OK

Set-Cookie: session=GUID1234; path=/; HttpOnly

Content-Type: text/html; charset=UTF-8

...

...

在这个过程中,服务器会检查POST请求中的用户名和密码是否与存储的凭证匹配。如果登录成功,服务器会返回一个带有会话标识cookie的响应。之后的每个请求都将携带这个cookie,以维持登录状态。

2.2 淘宝登录特殊性分析

淘宝登录流程具有一定的特殊性,因为它是基于阿里集团的生态系统,并且提供了多种登录选项。以下几点详细介绍了这些特殊性。

2.2.1 第三方登录的特点

淘宝允许用户使用第三方账号登录,如微博、支付宝或淘宝账户。每个第三方登录选项都有其特定的认证流程,涉及OAuth协议等技术。

2.2.2 淘宝登录的协议和要求

淘宝登录机制遵循HTTP协议,并且使用加密措施保证传输过程的安全。例如,使用HTTPS协议加密传输密码,使用验证码防止自动化工具登录等。

登录要求

支持的HTTP方法: POST 必要的请求头: Content-Type , User-Agent , Referer 必要的请求参数: username , password , vcode , skey 必要的响应头: Set-Cookie , Location 应对的响应状态码: 200 OK 表示成功, 401 Unauthorized 表示验证失败

通过这样的分析,我们能更深入地了解如何利用HTTPClient库模拟登录淘宝网站,并且能够设计出符合要求的安全策略。在后续章节中,我们将探讨HTML解析技术、构建POST请求、Cookie管理策略,以及如何处理安全性和验证码问题。

3. HTML解析技术应用

3.1 HTML解析技术基础

3.1.1 DOM树的构建和遍历

HTML解析技术是Web自动化测试、数据抓取等领域的基础。文档对象模型(DOM)树是HTML文档在内存中的树状结构表示,它允许程序和脚本动态地读取和修改文档的结构、样式和内容。在构建DOM树时,浏览器会读取HTML文档,并将每个标签转换成一个节点,形成一个层级化的结构。

示例页面

这是一个标题

这是一个段落。

上述代码在浏览器中会被解析为:

html :根节点

head :子节点

title :子节点 body :子节点

h1 :子节点 p :子节点

遍历DOM树意味着从根节点开始,访问每一个节点,可以是深度优先遍历或者广度优先遍历。

遍历的过程中,可以使用JavaScript的 document 对象提供的方法,如 getElementById() , getElementsByClassName() , getElementsByTagName() 等来获取特定元素。

3.1.2 JavaScript在HTML解析中的作用

JavaScript对HTML文档的解析和操作至关重要。它不仅能够修改DOM树,还能够响应用户事件,执行异步请求等。通过JavaScript,开发者可以创建动态内容,并与DOM交互来改变页面的外观或行为。

// 获取标题并改变其内容

var heading = document.getElementsByTagName('h1')[0];

heading.textContent = '新标题';

// 通过id获取段落并添加新的内容

var p = document.getElementById('someParagraph');

p.innerHTML += '
新添加的行。';

上述JavaScript代码片段演示了如何通过DOM API与页面元素进行交互。它能够访问和修改HTML元素的属性,这在自动填充登录信息时非常有用。

3.2 模拟登录中HTML解析的应用

3.2.1 登录表单字段的提取

在模拟登录的过程中,通常需要解析HTML页面来提取登录表单的字段,如用户名、密码等。可以通过选择器定位到这些表单元素,并提取它们的name属性,这些属性通常对应于后端处理表单数据的键。

// 假设页面中有以下表单元素

//

//

var usernameField = document.querySelector('input[name="username"]');

var passwordField = document.querySelector('input[name="password"]');

// 提取字段名称

var usernameFieldName = usernameField.name;

var passwordFieldName = passwordField.name;

// 提取字段值(通常在实际应用中,这些值会被动态填充)

var usernameFieldValue = usernameField.value;

var passwordFieldValue = passwordField.value;

3.2.2 自动填充登录信息的技术实现

自动填充登录信息通常涉及到编写脚本,这些脚本会在页面加载完成后自动向登录表单字段中填充预设的用户名和密码。这可以通过监听页面加载事件,并在适当的时机使用JavaScript代码修改DOM元素的值来实现。

// 假定已有用户名和密码变量

var username = "预设用户名";

var password = "预设密码";

// 当文档加载完成后执行

document.addEventListener('DOMContentLoaded', function() {

// 自动填充表单

var usernameField = document.querySelector('input[name="username"]');

var passwordField = document.querySelector('input[name="password"]');

usernameField.value = username;

passwordField.value = password;

// 提交表单

var loginForm = document.querySelector('form[name="loginForm"]');

loginForm.submit();

});

上述代码片段展示了一个简化的自动登录脚本。在实际使用中,还需要处理一些安全性和兼容性问题,例如等待所有相关的JavaScript库加载完成,处理动态加载的表单元素等。此外,自动填充登录信息应该谨慎使用,并且遵守相关网站的服务条款。

4. POST请求构建与发送

4.1 POST请求的构建

4.1.1 构建登录表单数据

在进行模拟登录操作时,构建POST请求的第一步通常涉及到登录表单数据的组装。这一部分通常包括了用户输入的用户名和密码,有时也会涉及到其他安全令牌或者验证码信息。在编程实践中,这一过程可以通过手动编码构建或者使用现有的HTTP库提供的表单构建方法。

假设我们需要模拟登录一个网站,代码示例如下:

import requests

from urllib.parse import urlencode

# 登录信息

login_data = {

'username': 'user123',

'password': 'password123',

'csrf_token': 'random_csrf_token_value', # 防止CSRF攻击的令牌

}

# 将字典转换为URL编码的字符串

encoded_login_data = urlencode(login_data)

# 创建会话对象

session = requests.Session()

# 发送POST请求

response = session.post('https://example.com/login', data=encoded_login_data)

代码逻辑分析与参数说明:

requests 是Python的一个HTTP库,提供了简单的方法来发送HTTP请求。 urlencode 函数负责将包含表单数据的字典转换成适合HTTP POST请求的URL编码格式。 session 对象用于持久化会话,它会帮助我们处理Cookies等会话信息,以便维持登录状态。 post 方法用于发送POST请求,第一个参数是目标URL, data 参数用于传递POST请求体中的数据。

4.1.2 参数编码和消息摘要算法

在登录过程中,为了增加安全性,许多网站会对登录表单数据进行编码和签名。消息摘要算法如MD5、SHA1等可以用来生成数据的签名,而编码方式通常采用Base64。这些手段可以用来防止数据篡改和验证数据的完整性。

import hashlib

# 假设我们已有一个消息摘要函数

def create_signature(data, secret_key):

# 使用secret_key对数据进行哈希,生成签名

return hashlib.sha256((data + secret_key).encode()).hexdigest()

# 将表单数据和签名附加到POST请求中

login_data['signature'] = create_signature(encoded_login_data, 'secret_key_value')

response = session.post('https://example.com/login', data=login_data)

代码逻辑分析与参数说明:

create_signature 函数使用了SHA-256哈希函数对数据和密钥进行签名生成。 在实际应用中, secret_key_value 应该是一个保密的密钥。 签名被添加到POST数据中,之后一起发送给服务器进行验证。

4.2 POST请求的发送与处理

4.2.1 构建HTTPClient请求

构建HTTP请求时,可以使用HTTPClient库来创建请求对象,设置必要的HTTP头信息,如User-Agent、Content-Type以及任何需要的Cookies等。

// Java伪代码示例

HttpClient httpClient = HttpClient.newHttpClient();

HttpRequest request = HttpRequest.newBuilder()

.uri(URI.create("https://example.com/login"))

.header("Content-Type", "application/x-www-form-urlencoded")

.POST(BodyProcessor.ofString(encoded_login_data))

.build();

// 发送请求并获取响应

HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

代码逻辑分析与参数说明:

HttpClient 是Java中的一个HTTP客户端,它支持异步或同步HTTP请求。 .header 方法用于设置HTTP头信息,例如 Content-Type 表明了发送数据的格式。 .POST 方法用于构建POST请求,指定了请求体的内容。

4.2.2 处理服务器的响应数据

在发送POST请求后,服务器通常会返回一个响应。处理服务器响应是模拟登录过程中的重要一环,需要检查响应状态码,解析响应内容,提取Cookies等信息。

// 检查响应状态

if(response.statusCode() == 200) {

// 解析响应内容

String responseBody = response.body();

// 提取Cookies(假设服务器在登录成功后设置了一个名为"SESSIONID"的Cookie)

Set cookies = httpClient.cookieHandler().get().Cookies(URI.create("https://example.com"));

// 存储Cookies,以便后续请求使用

// ...

} else {

// 登录失败处理

// ...

}

代码逻辑分析与参数说明:

statusCode 方法用于检查HTTP响应的状态码。 body 方法用于获取响应的主体内容。 cookieHandler 方法用于获取和设置HTTP客户端的Cookie处理器。 Cookies 方法用于获取服务器设置的Cookies。

服务器返回的数据一般是一个HTML页面或者JSON格式的数据。根据返回数据的格式,开发者可能需要使用不同的解析方法来提取登录成功后需要的会话信息。在某些情况下,服务器可能会返回重定向响应,这种情况下,HTTP客户端通常会自动跟随重定向,并处理最终的登录结果。

5. Cookie管理策略

在Web开发和模拟登录过程中,Cookie管理是一个不可忽视的环节。它不仅涉及到用户会话的持久化,还关系到安全性的维护。本章将详细探讨Cookie的作用、管理方法,以及它们在模拟登录中的具体应用。

5.1 Cookie的作用和管理

5.1.1 Cookie的定义和属性

Cookie是由Web服务器创建并发送到客户端的小型文本文件,存储在客户端的计算机上。它通常包含服务器生成的键值对,用于在客户端和服务器之间传递状态信息。Cookie的属性包括名称、值、过期时间、域和路径等,这些都是确保正确处理Cookie的重要元数据。

例如,一个典型的Cookie看起来如下:

Set-Cookie: sessionid=123456; Path=/; Expires=Thu, 01 Jan 2023 00:00:00 GMT; Secure; HttpOnly

sessionid 是Cookie的名称, 123456 是对应的值。 Path=/ 表示Cookie的作用范围是整个域。 Expires 定义了Cookie的过期时间。 Secure 表示Cookie应该通过HTTPS协议传输。 HttpOnly 使得JavaScript无法访问此Cookie,增强安全性。

5.1.2 Cookie管理方法和实践

Cookie的管理主要包括创建、读取、修改和删除这几个操作。在模拟登录的场景中,管理Cookie的有效性至关重要,因为它直接关系到会话是否能够持久化。

在代码中管理Cookie的一种常见方法是使用 requests 库。下面是一个管理Cookie的示例:

import requests

# 创建一个Session对象,用于持久化会话

session = requests.Session()

# 使用Session对象发起登录请求

response = session.post('https://example.com/login', data={'username': 'user', 'password': 'pass'})

# 获取所有Cookie

cookies = session.cookies.get_dict()

print(cookies)

# 通过键值对直接访问特定的Cookie

sessionid = session.cookies.get('sessionid')

print(sessionid)

# 删除特定的Cookie

session.cookies.set('sessionid', '', domain='example.com', path='/')

# 清除所有Cookie

session.cookies.clear()

这段代码中,我们首先使用 requests.Session() 创建了一个会话对象。然后,我们发起登录请求,并获取所有存储在 session.cookies 中的Cookie。我们可以访问、修改或删除特定的Cookie,或者清除所有的Cookie。

5.2 模拟登录中Cookie的应用

5.2.1 保持会话状态的实现

在模拟登录过程中,我们需要保持用户的会话状态不丢失。Cookie是实现这一目的的关键。登录成功后,服务器通常会返回一个或多个Set-Cookie头部,我们需要在后续的请求中携带这些Cookie以维持会话。

# 模拟登录并获取Cookie

session = requests.Session()

login_response = session.post('https://example.com/login', data={'username': 'user', 'password': 'pass'})

# 携带Cookie发起另一个请求

other_request = session.get('https://example.com/other_page')

在这个例子中,当使用同一个 session 对象发起 other_request 请求时,之前登录时设置的Cookie会被自动附加到请求头中。

5.2.2 防止登录过期的策略

在模拟登录中,需要确保登录状态的持久性,避免因为Cookie过期而导致的重新登录。因此,处理Cookie过期时间是十分关键的。

# 获取Cookie的过期时间

exp_time = cookies['sessionid']['expires']

print(exp_time)

# 判断Cookie是否过期

import datetime

if datetime.datetime.now() > exp_time:

# 如果过期,则需要重新登录

session.post('https://example.com/login', data={'username': 'user', 'password': 'pass'})

这段代码通过比较当前时间与Cookie的过期时间,可以判断是否需要重新发起登录请求以更新Cookie。

总结

本章节深入探讨了Cookie在模拟登录中的作用,提供了Cookie的定义、属性以及管理方法。通过代码示例,本章演示了如何在Python中使用 requests 库来有效地管理Cookie,从而保持会话状态,并处理Cookie过期等问题。在接下来的章节中,我们将讨论安全性与验证码处理的策略。

6. 安全性与验证码处理

在现代网络应用中,安全性是一个不可忽视的问题。模拟登录作为一种常见的网络操作,尤其需要关注安全性问题,因为它不仅涉及到用户信息的保护,也关系到网络服务的正常运行。验证码的出现则是为了抵御自动化工具和机器人,为用户提供了一个额外的安全保障层。然而,验证码同时也为模拟登录过程带来了挑战。本章将深入探讨安全性问题和验证码的处理技术。

6.1 安全性问题分析

6.1.1 常见的网络攻击手段

在互联网中,模拟登录常遭受到多种网络攻击。了解这些攻击手段有助于采取相应的防护措施。

SQL注入 :攻击者通过在表单输入或URL查询字符串中输入特定的SQL代码片段,试图更改数据库查询的结构。 跨站脚本攻击(XSS) :在用户浏览器中执行恶意脚本,目的是盗取Cookie,或者其他敏感信息。 跨站请求伪造(CSRF) :攻击者通过诱使用户在已登录的网站上执行非本意的操作。 会话劫持和固定攻击 :攻击者通过窃取或预测用户的会话令牌(如Cookie),以获得用户的会话控制权。

6.1.2 加密算法在安全性中的作用

为了保护数据在传输过程中的安全,使用加密算法是不可或缺的。下面介绍几种常用的加密技术及其在安全性中的应用。

对称加密 :使用相同的密钥进行数据的加密和解密,例如AES(高级加密标准)。 非对称加密 :使用一对密钥,一个公钥用于加密,一个私钥用于解密,例如RSA。 哈希算法 :将任意长度的数据转换为固定长度(通常较短)的唯一值,用于验证数据完整性,如SHA-256。 数字签名 :结合非对称加密和哈希算法,用于验证消息的来源和完整性。

6.2 验证码的识别和处理

验证码是防止自动化登录的常用手段,随着技术的发展,验证码的样式和复杂度也在不断增加。验证码的识别和处理变得越来越困难,但并非无法克服。

6.2.1 机器学习在验证码识别中的应用

机器学习技术,特别是深度学习,在验证码识别领域展现了巨大的潜力。通常,验证码识别流程如下:

图像预处理 :包括灰度化、二值化、去噪、边缘增强等。 特征提取 :从预处理后的图像中提取用于分类的特征。 分类器设计 :使用机器学习算法训练分类器识别验证码字符。 后处理 :利用语境信息、字符间的可能连接等对识别结果进行优化。

一个常见的验证码识别流程如下所示:

from captcha.image import ImageCaptcha

import numpy as np

import string

# 创建验证码生成器实例

generator = ImageCaptcha(width=120, height=36)

# 随机生成一个字符串验证码

random_text = ''.join(np.random.choice(list(string.ascii_letters), size=6))

print(random_text)

# 生成验证码图片

image = generator.generate(random_text)

# 可以对image进行进一步处理,例如保存、显示等

# ...

6.2.2 第三方服务的验证码绕过技术

某些情况下,网站可能使用第三方验证码服务,如reCAPTCHA。绕过这些服务通常需要使用特定的库,如 pytesseract ,它是一个OCR(光学字符识别)工具,可以识别和读取图片中的文字。

使用 pytesseract 识别reCAPTCHA的过程可能涉及:

分析reCAPTCHA响应并提取包含图像数据的URL。 下载图像并使用 pytesseract 读取其中的文字。 使用得到的文字信息,模拟用户点击正确的图像。

import pytesseract

from PIL import Image

import requests

import io

# 假设我们已经有reCAPTCHA的图像响应URL

image_url = 'http://example.com/recaptcha-image-response'

# 下载并打开验证码图片

response = requests.get(image_url)

image = Image.open(io.BytesIO(response.content))

# 使用pytesseract识别图片中的文字

text = pytesseract.image_to_string(image)

# 输出识别结果

print(text)

# 注意:实际使用时,应遵守网站的使用条款

验证码处理是模拟登录中不可或缺的一环。通过结合机器学习和OCR技术,可以有效地绕过验证码,但这需要谨慎处理,以避免违反服务条款或进行不当行为。在本章中,我们深入了解了安全性和验证码处理的重要性及其相应的技术手段,接下来,我们将探讨如何在模拟登录过程中处理这些安全风险。

7. 模拟登录的安全风险与应对措施

在模拟登录中,安全性至关重要。开发者们在实施自动化登录流程的同时,需要对可能遇到的安全风险有所了解,并且采取相应的应对措施来保护用户信息,防止被恶意利用。

7.1 模拟登录的安全风险分析

7.1.1 非授权访问和身份冒用

模拟登录的一个主要风险是被未授权的第三方利用,进行非授权访问。攻击者可以尝试重现或拦截合法用户的登录过程,以冒用身份进行恶意操作。这不仅对用户本人造成损害,也可能给网站带来法律责任和声誉损失。

7.1.2 个人信息泄露的风险

在模拟登录过程中,可能会涉及到用户的敏感信息,如用户名、密码、个人地址等。这些信息一旦泄露,攻击者可以用于欺诈、身份盗窃等恶意行为,对用户个人造成严重威胁。

7.2 应对策略和最佳实践

7.2.1 使用代理和VPN防止IP封禁

为了避免由于重复登录尝试而导致IP地址被封禁,使用代理服务器或VPN是一个有效的解决方案。通过代理或VPN,可以更换IP地址,模拟不同的用户环境进行登录,有效分散IP地址的登录请求压力。

7.2.2 加强代码安全性审核和测试

为了减少安全风险,开发者需要对自动化登录脚本进行严格的安全性审核和测试。这包括检查代码中是否有敏感信息的泄露,对各种安全漏洞进行测试,以及审查外部库的使用。此外,使用安全编码标准和最佳实践,定期更新依赖库以修复已知的安全漏洞,也是确保安全性的重要措施。

7.2.3 实施定期密码更新策略

另一个防止个人信息泄露的有效策略是定期更新密码。这可以减少因密码泄露而带来的安全风险,同时也可以促使用户对安全性有更高的认识。

7.2.4 利用多因素认证提高安全性

许多网站和服务现在都支持多因素认证(MFA),这是一种强大的安全措施,它要求用户提供两种或多种验证方式,如密码加上短信验证码或生物识别信息。开发者可以考虑在模拟登录中实现这样的安全措施,以增强账户的安全性。

7.2.5 设定访问频率限制

设定登录请求的频率限制,可以帮助防止暴力破解攻击。如果检测到短时间内登录尝试过于频繁,服务器可以暂时锁定用户账户或IP地址,直到一定时间后才允许再次尝试。

通过上述策略,可以大大降低模拟登录过程中的安全风险,并保护用户和网站的安全。随着网络安全威胁的不断变化,采取这些措施也是开发者不断学习和适应安全环境的过程。

本文还有配套的精品资源,点击获取

简介:本文深入探讨了如何使用Java的HTTPClient库来模拟淘宝网的登录过程,涵盖了网络请求、HTTP协议、Cookie管理及HTML解析技术。文章首先介绍了HTTPClient库的基础知识,然后详细分析了登录过程,包括初始化HTTPClient、构建GET和POST请求、解析HTML、设置Cookie策略、执行POST请求、处理响应以及安全性和验证码处理等方面。本项目展示了使用HTTPClient进行模拟登录的完整流程,并强调了安全性和注意事项。

本文还有配套的精品资源,点击获取

相关推荐

京东金条怎么开通 京东金条开通条件有哪些
365bet赌场手机投注

京东金条怎么开通 京东金条开通条件有哪些

📅 07-15 👁️ 675
4月7日生日书(白羊座)
365bet赌场手机投注

4月7日生日书(白羊座)

📅 06-29 👁️ 2824
斗鱼卡卡如今在哪直播?平台变迁与现状深度评测
365bet赌场手机投注

斗鱼卡卡如今在哪直播?平台变迁与现状深度评测

📅 07-11 👁️ 4638
11岁年龄差无碍真爱!王菲与谢霆锋的传奇恋情回顾
远古腰带
日博365投注

远古腰带

📅 08-19 👁️ 8728
FIFA Online3 06亨利07亨利哪个好 06亨利07亨利模型数据对比
Nintendo Switch
日博365投注

Nintendo Switch

📅 06-27 👁️ 532
DNF灵魂猎者多久能做出来
百特365下载

DNF灵魂猎者多久能做出来

📅 09-30 👁️ 6803
腾达f9和ac6对比有什么区别?哪个好?(实践)
365bet赌场手机投注

腾达f9和ac6对比有什么区别?哪个好?(实践)

📅 09-02 👁️ 9902