Search For Free — 新闻资讯检索平台(二)

Search For Free — 新闻资讯检索平台

一. 项目概述

基于第一个项目爬虫爬取的数据,完成数据展示网站。

1.1 基本要求

1、用户可注册登录网站,非注册用户不可登录查看数据

2、用户注册、登录、查询等操作记入数据库中的日志

3、爬虫数据查询结果列表支持分页和排序

4、用Echarts或者D3实现3个以上的数据分析图表展示在网站中

5、实现一个管理端界面,可以查看(查看用户的操作记录)和管理(停用启用)注册用户。

1.2 扩展要求

1、实现对爬虫数据中文分词的查询

2、实现查询结果按照主题词打分的排序

3、用Elastic Search+Kibana展示爬虫的数据结果

1.3 技术需求

  1. python语言

  2. Django框架

  3. Jieba分词

  4. Bootstrap前端页面搭建

  5. Echarts数据分析展示

1.4 项目框架

网站总体设计为B/S架构,设计模式为MTV。由数据层、服务层和展示层组成。

二. demo展示

进入 project1 文件夹,输入python manage.py runserver,访问 http://127.0.0.1:8000/ 即可。

项目演示视频:

model


若上方视频无法观看,请进入这里 web 编程 demo 完整版 观看完整版演示视频~谢谢!

三. 数据库设计

日志表

日志表记录了系统中所有用户的注册,登陆,查询等操作,其包括操作id,具体操作operation,用户user,创建时间created,更新时间updated等属性。

class Userlog(models.Model):
    id = models.UUIDField('id',primary_key=True,default=uuid.uuid4)
    operation = models.CharField('操作',max_length=256,null=True,blank=True)
    user = models.ForeignKey(User,on_delete=models.CASCADE)

    created = models.DateTimeField('创建时间', auto_now_add=True)
    updated = models.DateTimeField('更新时间', auto_now=True)

各字段属性及样例
在这里插入图片描述

在这里插入图片描述

用户表

用户表存储着注册过的用户信息和用户属性,用户信息包括:用户id,注册密码password,是否是superuser,用户名,邮箱email,加入系统时间。用户属性包括:用户最后一次登陆时间last_login,是否活跃is_active等属性。

在这里插入图片描述
在这里插入图片描述

数据表

数据表存储的是爬取下来的网页内容,包括网页url,网页source_name,编码方式,爬取时间,作者author,关键词keyword,具体内容content等。

  • id_fetches为唯一主键PRIMARY KEY,表示新闻的唯一标识id

  • url也限制为唯一键UNIQUE KEY,表示新闻的链接

  • source_name表示新闻网站来源,在此项目中source_name包括三种value:人民网,网易新闻,中国新闻网

  • source_encoding表示编码方式,此项目中编码方式为:人民网 GBK; 网易新闻 utf-8 ;中国新闻网 utf-8

  • title表示新闻的标题

  • keywords表示新闻的关键词

  • author表示新闻的作者,编辑

  • publish_date表示新闻的出版时间

  • crawltime表示新闻的爬取时间

  • content表示新闻的具体内容

  • create time存储当前的时间戳

class China(models.Model):
    id_fetches = models.IntegerField(primary_key=True)
    url = models.CharField('url',max_length=256,null=True,blank=True)
    source_name = models.CharField(max_length=256,null=True,blank=True)
    source_encoding = models.CharField(max_length=256,null=True,blank=True)
    title = models.CharField(max_length=256,null=True,blank=True)
    keywords = models.CharField(max_length=256,null=True,blank=True)
    author = models.CharField(max_length=256,null=True,blank=True)
    publish_date = models.CharField(max_length=256,null=True,blank=True)
    crawltime = models.CharField(max_length=256,null=True,blank=True)
    content = models.TextField(null=True,blank=True)
    createtime = models.DateTimeField(auto_now_add=True)

各字段属性及样例

在这里插入图片描述

在这里插入图片描述

四. 网站设计

4.1 用户登陆

1. 前端设计

注册后的用户需要输入账号及其对应的密码,才可完成登陆系统。若输入账号在后端数据库无法找到,则提示用户注册,同样密码若与账号不匹配也无法完成登陆。

只有登陆成功的用户可以查看数据,非注册用户不可登录查看数据。

核心代码
<div id="login"
     class="login loginpage " style="text-align: center;margin-top: 200px">
    <h1 style="color: white">Search For Free — 新闻资讯检索平台</h1>
    <form name="loginform" id="loginform" action="{% url 'dashboard-login' %}" method="post">{% csrf_token %}
        <p style="margin-top: 50px">
            <label for="user_login"  style="color: white">账号
                <input type="text" name="username" id="user_login" class="input"  placeholder="请输入账号" style="width: 500px;height: 45px;border-radius: 20px;outline: none;color: black"/></label>
        </p>
        <p style="margin-top: 30px">
            <label for="user_pass"  style="color: white">密码
                <input type="password" name="password" id="user_pass" class="input"
                       placeholder="请输入密码" style="width: 500px;height: 45px;border-radius: 20px;outline: none;color: black"/></label>
        </p>
        <p class="submit" style="color: black">
            <input type="submit" name="wp-submit" id="wp-submit" class="btn btn-success btn-lg"
                   value="登录" style="width: 200px;margin-top: 20px;color: black"/>
        </p>
    </form>
    <p id="nav" style="color: white">
        如果您没有账号,请点击<a href="{% url 'dashboard-register' %}">注册</a>
    </p>
</div>

实现效果

在这里插入图片描述

2. 后端设计

获取前端用户输入的username和password字段内容,在数据库中匹配具体字段,并向前端返回不同情况下的提示内容。

核心代码
def user_login(request):
    username = None
    password = None
    if request.method == 'POST':
        if not request.POST.get('username'):
            messages.error(request, '请输入用户名')
        else:
            username = request.POST.get('username')
        if not request.POST.get('password'):
            messages.error(request, '请输入密码')
        else:
            password = request.POST.get('password')

        if username is not None and password is not None:
            try:
                user = authenticate(username=username, password=password)
                # user = User.objects.get(username=phone)
                if user is not None:
                    if user.check_password(password):
                        login(request, user)
                        userlog = Userlog(operation='登录',user=user)
                        userlog.save()

                        return HttpResponseRedirect('/index')
                    else:
                        messages.error(request, '无效的账号')
                else:
                    messages.error(request, '账号或密码错误,请您确认账号和密码')
            except:
                messages.error(request, '账号或密码错误,请您确认账号和密码')
    return render(request, 'dashboard/login.html', )

4.2 用户注册

1. 前端设计

未注册过的用户需要进行注册,我们会要求用户输入的两次密码一致防止密码的错输。

核心代码
<div style="margin-top: 150px" id="register"
     class="login loginpage col-lg-offset-4 col-lg-4 col-md-offset-3 col-md-6 col-sm-offset-3 col-sm-6 col-xs-offset-2 col-xs-8">
    <h1 style="color: white">Search For Free — 新闻资讯检索平台</h1>

    <form name="loginform" id="loginform" action="{% url 'dashboard-register' %}" method="post"
          enctype="multipart/form-data" style="color: white;margin-top: 100px">{% csrf_token %}
        <p>
            <label for="phone">账号<br/>
                <input type="text" class="form-control" placeholder="请输入账号"
                   style="height: 40px;width: 550px;opacity: .9 ;color: #0f0f0f" name="username">
            </label>
        </p>

        <p>
            <label for="password">密码<br/>
                <input type="password" class="form-control" placeholder="请输入密码"
                       style="height: 40px;width: 550px;opacity: .9 ;color: #0f0f0f" name="password"></label>
        </p>
        <p>
            <label for="confirm_password">确认密码<br/>
                <input type="password" class="form-control" placeholder="请确认密码"
                   style="height: 40px;width: 550px;opacity: .9;color: #0f0f0f " name="confirm_password"></label>
        </p>


        <p class="submit">
            <input type="submit" name="wp-submit" id="wp-submit" class="btn btn-orange"
                   value="注册" style="color: #0f0f0f"/>
        </p>
    </form>

    <p id="nav">
        <a class="pull-left" href="#" title="Password Lost and Found"  style="color: white">忘记密码</a>
        <a class="pull-right" href="{% url 'dashboard-login' %}" title="Sign Up" style="color: white">登录</a>
    </p>
    <div class="clearfix"></div>

</div>
实现效果

在这里插入图片描述

2. 后端设计
核心代码

获取前端内容,一方面确认改用户名是否已经被注册,另一方面确认两次输入的密码是否一致,并向前端返回提示信息。

def register(request):
    username = None
    password = None
    confirm_password = None
    flag = False
    if request.method == 'POST':
        if not request.POST.get('username'):
            messages.error(request, '请输入用户名')
        else:
            username = request.POST.get('username')

        if not request.POST.get('password'):
            messages.error(request, '请输入密码')
        else:
            password = request.POST.get('password')
        if not request.POST.get('confirm_password'):
            messages.error(request, '请再次输入密码')
        else:
            confirm_password = request.POST.get('confirm_password')
        if password is not None and confirm_password is not None:
            if password == confirm_password:
                flag = True
            else:
                messages.error(request, '两次输入的密码不一致,请重新输入')

        filter_result = User.objects.filter(username=username)
        if len(filter_result) > 0:
            messages.error(request, '对不起,您输入的账号已被注册')
            return HttpResponseRedirect('/register/')

        if username is not None and password is not None and confirm_password is not None and flag:
            user = User.objects.create_user(username=username, password=password, last_login=timezone.now())
            user.is_active = True

            user.save()
            userlog = Userlog(operation='注册', user=user)
            userlog.save()
            messages.success(request, '注册成功,请登录')
            return HttpResponseRedirect('/')
    return render(request, 'dashboard/register.html')

4.3 分页排序检索

1. 前端设计

分项搜索功能,可根据 title, keywords, author 进行新闻的搜索,采用字符串匹配的方法,将查询结果以表格形式展现出来。相比较期中项目,本次项目增添了分页和排序功能,优化搜索的查询结果。

以搜索标题中含有人民的新闻为例,查询结果如下:

在这里插入图片描述

2. 后端设计

根据前端输入跳转到相应路由,构建sql语句进行mysql数据库查询,结果以json格式返回。关键词搜索结果列表支持分页和排序。

代码中加入sql语句order_by(“publish_date”)实现搜索结果按出版时间排序。

同时引入Paginator实现分页查询,并可以实现跳转到上下页。

def search_for_keyword(request):
    keytype = None
    keyword = None
    if request.method == 'POST':
        keytype = request.POST.get('keytype')
        keyword = request.POST.get('keyword')
    else:
        keytype = request.GET.get('keytype')
        keyword = request.GET.get('keyword')
    user = request.user
    if keyword:
        if keytype == '1':
            china = China.objects.filter(title__contains=keyword).order_by('-publish_date')
        else:
            china = China.objects.filter(content__contains=keyword).order_by('-publish_date')
        paginator = Paginator(china, 10)
        page = int(request.GET.get('page', 1))
        try:
            china = paginator.page(page)
        except PageNotAnInteger:
            china = paginator.page(1)
        except EmptyPage:
            china = paginator.page(paginator.num_pages)
        userlog = Userlog(operation='关键字检索', user=user)
        userlog.save()
        return render(request, 'dashboard/search-for-keyword.html',
                      {'china': china, 'keytype': keytype, 'keyword': keyword})

    return render(request, 'dashboard/search-for-keyword.html')

4.4 数据统计分析

利用 Echarts 可视化出不同新闻来源的新闻数量分布。

核心代码
user = request.user
china = China.objects.all()
source_name = []
data = []
for c in china:
    if c.source_name is not None and c.source_name != 'None':
        source_name.append(c.source_name)
source_name_new = list(set(source_name))
for s in source_name_new:
    data.append(China.objects.filter(source_name=s).count())
userlog = Userlog(operation='数据统计查询', user=user)
userlog.save()
print(data,source_name_new)

return render(request,'dashboard/index.html',{'source_name':json.dumps(source_name_new),'data':data})
实现效果

在这里插入图片描述

4.5 时间序列分析

用 Echarts 可视化出随着时间各新闻网站新闻数量变化,并可以缩放进度条实现查看特定时间段内的新闻数量变化。

核心代码
def date_data(request):
    user = request.user
    china = China.objects.all().order_by('publish_date')
    date_list = []
    data = []
    data_list = []
    source_list = []
    for c in china:
        if c.publish_date:
            date_list.append(c.publish_date.strftime('%Y-%m-%d'))
            source_list.append(c.source_name)
    date_list_new = sorted(set(date_list),key=date_list.index)
    print(date_list_new)
    source_list_new = list(set(source_list))
    for s in source_list_new:
        if s:
            for d in date_list_new:
                if d:
                    data.append(China.objects.filter(publish_date=datetime.strptime(d, '%Y-%m-%d')).count())
        data_list.append(data)
    userlog = Userlog(operation='数据时间序列统计查询', user=user)
    userlog.save()
    return render(request,'dashboard/date.html',{'date_list':json.dumps(date_list_new),'data':data,'source_list':json.dumps(source_list_new),'data_list':data_list})
实现效果

在这里插入图片描述

4.6 关键词热度可视化

时间热度分析即时间维度上的含特定语义或关键词的新闻规模数量的变化情况,统计每个时间点含特定关键词的新闻的数量,以折线图和饼状图的形式可视化在页面中。

所以思路是根据输入的value,构建sql语句查询含该关键词的新闻,并按出版时间publish_date排序。构建字典word_freq,对于排序好的新闻,遍历每条新闻,对keywords先用replace方法去除一些无用的字符,再用正则表达式匹配出publish_date,搜索出keywords数量,添加到publish_date对应的word_freq上。遍历完成即可得到含特定关键词的新闻数量随时间维度变化的数值表示。再用echarts做出折线图和饼状图,定义好option中title,grid,x轴,y轴等属性,得到可视化效果展示在前端。

核心代码
  • 获取关键词随日期变化的出现次数
const regex_c = /[\t\s\r\n\d\w]|[\+\-\(\),\.。,!?《》@、【】"'::%-\/“”]/g;
var regex_d = /\w{3}\s(.*?) 2021/; 

var freqchange = function(vals, keyword) {
    var regex_k = eval('/'+keyword+'/g');
    var word_freq = {};

    vals.forEach(function (data){
        var content = data["keywords"].replace(regex_c,'');
        var publish_date = regex_d.exec(data['publish_date'])
        if(publish_date!=null){
            publish_date=publish_date[1];

            var freq = content.match(regex_k).length;// 直接搜这个词。
            word_freq[publish_date] = (word_freq[publish_date] + freq ) || 0;
        }
    });
    console.log(word_freq);
    return word_freq;

};
exports.freqchange = freqchange;

  • Echarts 作图,对于查询结果 data 按照作图数据格式{name,value}进行解析,并将可视化结果同时以折线图和饼状图展示出来。
let newdata = [];
for (var key in data) {
newdata.push({name:key,value:data[key]});
};
console.log(newdata);
var myChart = echarts.init(document.getElementById("main1"));
option = {
title: {
    text: '\"'+$("#analyze_text").val()+'\"'+'该词在新闻中的出现次数随时间变化图'+'                                                                            '+'\"'+$("#analyze_text").val()+'\"'+'该词在新闻中的出现次数饼状图',
    left:'6%'
},
grid:[
    {x:'2%',y:'20%',width:'25%',height:'48%'},
    {x2:'7%',y:'0%',width:'47%',height:'47%'},
],
xAxis: [
    {
        gridIndex:0,
        type: 'category',
        data: Object.keys(data)
    },
    
],
yAxis: [
    {
        gridIndex: 0,
        type: 'value',
    }
],
series: [{
    data: Object.values(data),
    type: 'line',
    itemStyle : { normal: {label : {show: true}}}
},
{
    name: '访问来源',
    type: 'pie',    // 设置图表类型为饼图
    radius: '55%',  // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
    data:newdata,

}],

};

if (option && typeof option === "object") {
myChart.setOption(option, true);
}
实现效果

在这里插入图片描述

4.7 分词词云检索

利用jieba分词作出新闻内容的wordcloud词云,对新闻内容用jieba的cut函数进行分词,并去除其中的停用词(stopwords),筛选掉无意义词,并对文本中出现频率较高的“关键词”予以视觉上的突出和可视化。

核心代码
@login_required
def hot(request):
    user= request.user
    data = China.objects.all()
    r = []
    for d in data:
        content = d.content
        r.append(content)
    seg_list = jieba.cut(str(r))
    c = Counter()
    for x in seg_list:
        if len(x) > 1 and x != '\r\n':
            c[x] += 1
    res = []
    for (k, v) in c.most_common(200):
        if all(map(lambda c: '\u4e00' <= c <= '\u9fa5', k)):
            o = dict()
            o['name'] = k
            o['value'] = v
            res.append(o)
    print(res)
    userlog = Userlog(operation='热词分析', user=user)
    userlog.save()
    return render(request, 'dashboard/hot.html',{'res':res})
@login_required
def hot_json(request):
    data = China.objects.all()
    r = []
    for d in data:
        content = d.content
        r.append(content)
    seg_list = jieba.cut(str(r))
    c = Counter()
    for x in seg_list:
        if len(x) > 1 and x != '\r\n':
            c[x] += 1
    res = []
    for (k, v) in c.most_common(300):
        if all(map(lambda c: '\u4e00' <= c <= '\u9fa5', k)):
            o = dict()
            o['name'] = k
            o['value'] = v
            res.append(o)
    return HttpResponse(json.dumps({
        "res": res
    }))
实现效果

在这里插入图片描述
点击高频关键词可以检索到包含关键词的新闻,实现对中文分词查询。
在这里插入图片描述

4.8 用户管理

管理界面,可以查看用户状态并管理注册用户。当我们停用某用户时,之后他将无法从登录页面成功登陆,只有再次激活才可以重新登陆。

核心代码
<div class="content-body">
    <div class="row">
        <div class="col-md-12 col-sm-12 col-xs-12">
            <table class="table table-hover">
                <thead>
                <tr>
                    <th style="text-align: center">序号</th>
                    <th style="text-align: center">用户名</th>
                    <th style="text-align: center">邮箱</th>
                    <th style="text-align: center">状态</th>
                    <th style="text-align: center">操作</th>
                </tr>
                </thead>
                <tbody>
                {% for c in res %}
                    <tr>
                        <td style="vertical-align: middle;text-align: center">{{ forloop.counter }}</td>
                        <td style="text-align: center">{{ c.username }}</td>
                        <td style="vertical-align: middle;text-align: center">{{ c.email }}</td>
                        <td style="vertical-align: middle;text-align: center">{{ c.status }}</td>
                        <td style="vertical-align: middle;text-align: center">
                            {% if c.status == '激活' %}
                            <a href="{% url 'dashboard-user-status' c.id '1' %}"
                               class="btn btn-danger btn-mini">停用</a>
                            {% else %}
                            <a href="{% url 'dashboard-user-status' c.id '0' %}"
                               class="btn btn-danger btn-mini">启用</a>
                            {% endif %}
                        </td>
                    </tr>
                {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
</div>
实现效果

在这里插入图片描述

4.9 日志管理

管理界面,可以查看用户操作记录。具体来说,用户可以看到user的操作时间和操作内容。

核心代码
<div class="content-body">
    <div class="row">
        <div class="col-md-12 col-sm-12 col-xs-12">
            <table class="table table-hover">
                <thead>
                <tr>
                    <th style="text-align: center">序号</th>
                    <th style="text-align: center">日志</th>
                    <th style="text-align: center">操作者</th>
                    <th style="text-align: center">时间</th>
                </tr>
                </thead>
                <tbody>
                {% for c in log %}
                    <tr>
                        <td style="vertical-align: middle;text-align: center">{{ forloop.counter }}</td>
                        <td style="text-align: center">{{ c.operation }}</td>
                        <td style="vertical-align: middle;text-align: center">{{ c.user }}</td>
                        <td style="vertical-align: middle;text-align: center">{{ c.created }}</td>

                    </tr>
                {% endfor %}
                </tbody>
            </table>
        <div class="metadata-pagination">
                        {% include 'dashboard/common/log.html' %}
                    </div>
        </div>
    </div>
实现效果

在这里插入图片描述

五. 总结

在学习和实践的过程中,我基于期中项目进行功能的增添和完善,由此完成了一个完整的新闻查询网站项目,这还是很有成就感的。从数据获取,数据处理,及数据可视化等步骤对数据在系统中的作用及转变流程有了更深一步认识和理解。

在项目中我实现了多种新闻的查询方式,一方面,我利用order_by和Paginator实现了支持分页和排序的数据查询,另一方面,在项目中我引入python的jieba分词对新闻进行分词处理,并将分词结果筛选出高频词,构建词云wordcloud实现高频词的可视化,可同时通过高频词list直接跳转到包含高频词的新闻,实现中文分词的查询。

另外,我增添了注册,登陆等功能,并搭建出用户管理界面进行用户状态和属性的管理查询,保证系统的可用性和信息的安全性。

最后,感谢本学期老师和助教学长学姐们的耐心教导和悉心帮助,让我通过理论和实践交融的方式对网站搭建的前后端逻辑及框架具体实现流程有了亲身理解和实践,收获颇丰!

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1.项目代码均经过功能验证ok,确保稳定可靠运行。欢迎下载体验!下载完使用问题请私信沟通。 2.主要针对各个计算机相关专业,包括计算机科学、信息安全、数据科学与大数据技术、人工智能、通信、物联网等领域的在校学生、专业教师、企业员工。 3.项目具有丰富的拓展空间,不仅可作为入门进阶,也可直接作为毕设、课程设计、大作业、初期项目立项演示等用途。 4.当然也鼓励大家基于此进行次开发。在使用过程中,如有问题或建议,请及时沟通。 5.期待你能在项目中找到乐趣和灵感,也欢迎你的分享和反馈! 【资源说明】 课程设计-基于Vue+Express实现的新闻聚合网项目源码+运行说明(含前端+后端).zip 本次项目是Web编程项目demo,为新闻聚合网(聚合了网易新闻/新浪新闻/新华网/人民网),在此网中有独立的热搜模块(较为简陋),四个新闻平台热点关键词词云及其数据量,同时您可以在网中进行筛选搜索,结果会以模态框形式弹出,点击对应的结果即可跳转到对应的新闻原URL,所有结果均为定时爬虫所爬取。 本使用了Vue3+NaiveUI作为前端框架与组件,使用了Nodejs+Express作为项目后端,阿里云MySQL数据库作为项目数据库。 项目运行 本项目前后端分离,前端为front文件夹,后端为back文件夹,进入前后端文件夹后分别运行 ```shell npm install ``` 下载相应的module文件(如果没有的话) 由于本项目为demo项目,因此并没有做过深的负载等考虑,为开发模式,仅作为演示,因此Vue项目并未打包,均为源码开发模式呈现。 在front文件夹下运行 ```shell npm run serve ``` 启动前端测试(默认运行在8080端口) 在back文件夹下运行 ```shell node main.js ``` 启动服务器(默认运行在8000端口) 然后打开浏览器访问http://localhost:8080/即可测试项目 项目组成 ### 前端 前端为单页面应用,所有交互均以模态框(或类模态框)进行,结构如下: ``` |-- front/src |-- main.js |-- App.vue |-- components | |-- Hot.vue | |-- Display.vue | |-- Result.vue |-- assets | ... ``` 其中App.vue负责整体页面(主页),Hot.vue负责热搜模态框,Display.vue负责展示模态框,Result.vue负责搜索结果展示模态框(包含分页)。 ### 后端 后端由于是第一次写nodejs后端,因此封装或者模块化都比较简陋,以后有兴趣的话可以将后端用Python或Java重写,结构如下: ``` |-- back |-- main.js |-- crawler | |-- common.js | |-- crawler.js | |-- websites | |-- wangyi.js | |-- xinlang.js | |-- xinhua.js | |-- renmin.js | ... ``` 主体部分还是在爬虫上,由于针对不同网的爬虫会有所不同,因此我将匹配的关键词放在了websites文件夹中的每个js文件中,种子页面处理放在crawler.js中,common.js用来放一些常用模块的次封装(或者测试的时候可以拿来用,比如我的连接数据库操作是放在main中的,其他地方没有数据库,因此测试某个网是否成功导入数据库中也可以在common中加入数据库连接操作并exports出来)。 其余定时器,search,热搜,展示的数据均在main.js中生成(这里是由于nodejs不太熟悉不会很好的封装,因此统一整合到了main中)

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值