• 暑假闲着没事第一弹:基于Django的长江大学教务处成绩查询系统


     本篇文章涉及到的知识点有:Python爬虫,MySQL数据库,html/css/js基础,selenium和phantomjs基础,MVC设计模式,ORM(对象关系映射)框架,django框架(Python的web开发框架),apache服务器,linux(centos 7为例)基本操作。因此适合有以上基础的同学学习。

    声明:本博文只是为了纯粹的技术交流,敏感信息本文会有所过滤,大家见谅(由于任何缘故导致长江大学教务处网站出现问题,都与本人无关)。

    实现思路:在没有教务处数据接口的前提下(学生的信息安全),那也只有自己写爬虫去模拟登陆教务处,然后爬数据,为了防止教务处网站崩溃,导致爬虫失败,可以进行数据缓存,下次可以直接从自己的数据库中取数据,而我们要做的就是定时更新数据与教务处实现同步。

    技术架构:centos 7 + apache2.4 + mariadb5.5 + Python2.7.5 + mod_wsgi 3.4 + django1.11

    ------------------------------------------------------------------------

    一、Python爬虫:

    1、先看一下登录入口 

    我们这里用FireFox进行抓包分析,我们发现登录是post上去的,并且带有7个参数,发现有验证码,此时有两种解决办法,一种是运用现在很火的技术用DL做图片识别,一种是down下来让用户自己输。第一种成本比较高。。等不忙了可以试一下,记得Python有个库叫Pillow还是PIL可以做图片识别,,暑假用TF试一下。第二种很low就不说了。

    2、 还有种高大上的方式,,,可以不用管验证码,这里就不细说了,我们模拟登陆上去:

    #coding:utf8
    from bs4 import BeautifulSoup
    import urllib
    import urllib2
    import requests
    import sys
    
    reload(sys)
    sys.setdefaultencoding('gbk')
    
    loginURL = "教务处登陆地址"
    cjcxURL = "http://jwc2.yangtzeu.edu.cn:8080/cjcx.aspx"
    html = urllib2.urlopen(loginURL)
    soup = BeautifulSoup(html,"lxml")
    __VIEWSTATE = soup.find(id="__VIEWSTATE")["value"]
    __EVENTVALIDATION = soup.find(id="__EVENTVALIDATION")["value"]
    
    data = {
            "__VIEWSTATE":__VIEWSTATE,
            "__EVENTVALIDATION":__EVENTVALIDATION,
            "txtUid":"账号",
            "btLogin":"%B5%C7%C2%BC",
            "txtPwd":"密码",
            "selKind":"1"
            }
    header = {
    #        "Host":"jwc2.yangtzeu.edu.cn:8080",
            "User-Agent":"Mozilla/5.0 (Windows NT 10.0;… Gecko/20100101 Firefox/54.0",
            "Accept":"text/html,application/xhtml+x…lication/xml;q=0.9,*/*;q=0.8",
            "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
            "Accept-Encoding":"gzip, deflate",
            "Content-Type":"application/x-www-form-urlencoded",
    #        "Content-Length":"644",
            "Referer":"http://jwc2.yangtzeu.edu.cn:8080/login.aspx",
    #        "Cookie":"ASP.NET_SessionId=3zjuqi0cnk5514l241csejgx",
    #        "Connection":"keep-alive",
    #        "Upgrade-Insecure-Requests":"1",
            }
    
    UserSession = requests.session()
    Request = UserSession.post(loginURL,data,header)
    Response = UserSession.get(cjcxURL,cookies = Request.cookies,headers=header)
    soup = BeautifulSoup(Response.content,"lxml")
    print soup

    接下来我们可以看到:

    再来post(此代码接上面):

    __VIEWSTATE2 = soup.find(id="__VIEWSTATE")["value"]
    __EVENTVALIDATION2 = soup.find(id="__EVENTVALIDATION")["value"]
    
    AllcjData = {
                "__EVENTTARGET":"btAllcj",
                "__EVENTARGUMENT":"",
                "__VIEWSTATE":__VIEWSTATE2,
                "__EVENTVALIDATION":__EVENTVALIDATION2,
                "selYear":"2017",
                "selTerm":"1",
    #            "Button2":"%B1%D8%D0%DE%BF%CE%B3%C9%BC%A8"
            }
    AllcjHeader = {
    #       "Host":"jwc2.yangtzeu.edu.cn:8080",
            "User-Agent":"Mozilla/5.0 (Windows NT 10.0;… Gecko/20100101 Firefox/54.0",
            "Accept":"text/html,application/xhtml+x…lication/xml;q=0.9,*/*;q=0.8",
            "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
            "Accept-Encoding":"gzip, deflate",
            "Content-Type":"application/x-www-form-urlencoded",
    #        "Content-Length":"644",
            "Referer":"http://jwc2.yangtzeu.edu.cn:8080/cjcx.aspx",
    #        "Cookie":,
            "Connection":"keep-alive",
            "Upgrade-Insecure-Requests":"1",
            }
    Request1 = UserSession.post(cjcxURL,AllcjData,AllcjHeader)
    Response1 = UserSession.get(cjcxURL,cookies = Request.cookies,headers=AllcjHeader)
    soup = BeautifulSoup(Response1.content,"lxml")
    print soup

    发现不行。。。这次get的页面还是原来的页面。。。我觉得有两种原因导致这次post失败:一是asp.net的__VIEWSTATE和__EVENTVALIDATION变量导致post失败,二是一个form多个button用了js做判断,导致爬虫失败,对于动态加载的页面,普通爬虫还是不行。。。。

    3、再来点高大上的用selenium(web自动化测试工具,可以模拟鼠标点击)+ phantomjs(没有界面的浏览器,比chrome和Firefox都要快)

    selenium安装:pip install selenium

    phantomjs安装:

    (1)地址:http://phantomjs.org/download.html(我下载的是Linux 64位的)

    (2)解压缩:tar -jxvf phantomjs-2.1.1-linux-x86_64.tar.bz2 /usr/share/  

    (3)安装依赖:yum install fontconfig freetype libfreetype.so.6 libfontconfig.so.1

    (4)配置环境变量:export PATH=$PATH:/usr/share/phantomjs-2.1.1-linux-x86_64/bin

    (5)shell下输入phantomjs,如果能进入命令行,安装成功。

    请忽略我的注释:

    #coding:utf8
    from bs4 import BeautifulSoup
    from selenium import webdriver
    from selenium.webdriver.common.keys import Keys
    import time
    import urllib
    import urllib2
    import sys 
    
    
    reload(sys)
    sys.setdefaultencoding('utf8')
    
    driver = webdriver.PhantomJS();
    driver.get("教务处登录地址")
    driver.find_element_by_name('txtUid').send_keys('账号')
    driver.find_element_by_name('txtPwd').send_keys('密码')
    driver.find_element_by_id('btLogin').click()
    cookie=driver.get_cookies()
    driver.get("http://jwc2.yangtzeu.edu.cn:8080/cjcx.aspx")
    #print driver.page_source
    #driver.find_element_by_xpath("//input[@name='btAllcj'][@type='button']")
    #js = "document.getElementById('btAllcj').onclick=function(){__doPostBack('btAllcj','')}"
    #js = "var ob; ob=document.getElementById('btAllcj');ob.focus();ob.click();)"
    #driver.execute_script("document.getElementById('btAllcj').click();")
    #time.sleep(2)                            #让操作稍微停一下
    #driver.find_element_by_link_text("全部成绩").click() #找到‘登录’按钮并点击
    #time.sleep(2)
    #js1 = "document.Form1.__EVENTTARGET.value='btAllcj';"
    #js2 = "document.Form1.__EVENTARGUMENT.value='';"
    #driver.execute_script(js1)
    #driver.execute_script(js2)
    #driver.find_element_by_name('__EVENTTARGET').send_keys('btAllcj')
    #driver.find_element_by_name('__EVENTARGUMENT').send_keys('')
    #js = "var input = document.createElement('input');input.setAttribute('type', 'hidden');input.setAttribute('name', '__EVENTTARGET');input.setAttribute('value', '');document.getElementById('Form1').appendChild(input);var input = document.createElement('input');input.setAttribute('type', 'hidden');input.setAttribute('name', '__EVENTARGUMENT');input.setAttribute('value', '');document.getElementById('Form1').appendChild(input);var theForm = document.forms['Form1'];if (!theForm) {    theForm = document.Form1;}function __doPostBack(eventTarget, eventArgument) {    if (!theForm.onsubmit || (theForm.onsubmit() != false)) {        theForm.__EVENTTARGET.value = eventTarget;        theForm.__EVENTARGUMENT.value = eventArgument;        theForm.submit();    }   }__doPostBack('btAllcj', '')"
    #js = "var script = document.createElement('script');script.type = 'text/javascript';script.text='if (!theForm) {    theForm = document.Form1;}function __doPostBack(eventTarget, eventArgument) {    if     (!theForm.onsubmit || (theForm.onsubmit() != false)) {        theForm.__EVENTTARGET.value = eventTarget;        theForm.__EVENTARGUMENT.value = eventArgument;        theForm.submit();  }}';document.body.appendChild(script);"
    #driver.execute_script(js)
    driver.find_element_by_name("Button2").click()
    html=driver.page_source
    soup = BeautifulSoup(html,"lxml")
    print soup
    tables = soup.findAll("table")
    for tab in tables:
      for tr in tab.findAll("tr"):
        print "--------------------"
        for td in tr.findAll("td")[0:3]:
          print td.getText()

     

    现在只能拿到必修课成绩。。。。。因为全部成绩是ASP生成的js触发的。。。而不是直接submit。。。正在寻找解决的办法。下面开始我们数据库的设计。。。

    二、Mariadb学生数据库设计,,,这里引用了我们SQL server数据库原理上机的内容。。。

     

    我的建库语句:

    create database jwc character set utf8;
    
    use jwc;
    
    create table Student(
        Sno char(9) primary key,
        Sname varchar(20) unique,
        Sdept char(20),
        Spwd char(20)
    );
    create table Course(
        Cno   char(2) primary key,
        Cname varchar(30) unique,
        Credit  numeric(2,1)
    );
    create table SC( 
        Sno char(9) not null,
        Cno char(2) not null,
        Grade int check(Grade>=0 and Grade<=100),
        primary key(Sno,Cno),
        foreign key(Sno) references Student(Sno),
        foreign key(Cno) references Course(Cno)
    );

    三、Python web环境的搭建(LAMP):

    1、因为这次选的http服务器时apache,所以要安装mod_wsgi(python通用网关接口)来实现apache和Python程序的交互。。。如果用nginx就要安装配置uwsgi。。。类似java的servlet和PHP的php-fpm。

    安装:yum install mod_wsgi

    配置:vim /etc/httpd/conf/httpd.conf

     这个配置花费了我不少心思和时间。。。网上的有很多错误。。。最标准的Python web django开发配置。。。拿走不谢。

    #config python web
    LoadModule wsgi_module modules/mod_wsgi.so  
    <VirtualHost *:8080>
        ServerAdmin root@Vito-Yan
        ServerName www.yuol.onlne
        ServerAlias yuol.online
    
        Alias /media/ /var/www/html/jwc/media/
        Alias /static/ /var/www/html/jwc/static/
        <Directory /var/www/html/jwc/static/>    
            Require all granted
        </Directory>
        
        WSGIScriptAlias / /var/www/html/jwc/jwc/wsgi.py 
    #    DocumentRoot "/var/www/html/jwc/jwc"
        ErrorLog "logs/www.yuol.online-error_log"
        CustomLog "logs/www.yuol.online -access_log" common
        
        <Directory "/var/www/html/jwc/jwc">
            <Files wsgi.py>
                AllowOverride All 
                Options Indexes FollowSymLinks Includes ExecCGI
                Require all granted
            </Files>    
        </Directory>
    </VirtualHost>

     2、下面来安装django。。。pip install django。。。。搞定。

    查看django的版本:python -m django --version

    官网地址:https://www.djangoproject.com

    新建项目:django-admin.py startproject jwc(我的是在/var/www/html下建的,apache的网站根目录)

    3、apcehe的配置:就不贴了,把上面的jwc改成jwc2,然后端口改成9000,然后Listen 9000(为什么用9000呢,第一个项目jwc用的是8080,django自带的服务器用python manage.py runserver可以开启,它的默认端口是8000,所以不用8000,以免冲突,我的jsp项目的tomcat服务器用的是9090端口,以免冲突,最好不用,常见的就9000端口了,其他不敢乱用)。

    4、 settings.py的配置:

    DEBUG = True 调试开启

    ALLOWED_HOSTS = ['192.168.47.128'] 添加主机

    5、wsgi.py配置,不要问我为什么。。。我也不知道。。用apache服务器启动django项目这样做就行了。。。如果用django自带的server就不用改了。。。

    """
    WSGI config for jwc2 project.
    
    It exposes the WSGI callable as a module-level variable named ``application``.
    
    For more information on this file, see
    https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/
    """
    
    #import os
    
    #from django.core.wsgi import get_wsgi_application
    
    #os.environ.setdefault("DJANGO_SETTINGS_MODULE", "jwc2.settings")
    
    #application = get_wsgi_application()
    
    import os    
    from os.path import join,dirname,abspath    
    PROJECT_DIR = dirname(dirname(abspath(__file__)))    
    
    import sys    
    sys.path.insert(0,PROJECT_DIR)
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "jwc2.settings")    
    
    from django.core.wsgi import get_wsgi_application
    application = get_wsgi_application()

    然后就大功告成。。。。Python web环境算是搭建完成。。。

    四、开启我们的第一个django项目应用。。。

     1、新建成绩查询的应用 python manage.py startapp cjcx

    2、在settings.py中添加应用

    3、在views.py里写下写下第一行代码。。。。

    # -*- coding: utf-8 -*-
    from __future__ import unicode_literals
    from django.http import HttpResponse
    from django.shortcuts import render
    
    # Create your views here.
    
    def index(request):
        return HttpResponse("Hello,YUOL!")

    4、在urls.py下添加url

    from django.conf.urls import url 
    from django.contrib import admin
    import cjcx.views as cj
    
    urlpatterns = [ 
        url(r'^admin/', admin.site.urls),
        url(r'^cjcx/',cj.index),
    ]

    5、Hello,YUOL!

    6、刚刚上面的4还可以换种方法。。。。

    在cjcx应用下面新建urls.py

    from django.conf.urls import url 
    from . import views
    
    urlpatterns = [ 
        url(r'^$', views.index),
    ]

    修改jwc2下面的urls.py(项目根路径)

    from django.conf.urls import url, include
    from django.contrib import admin
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^cjcx/', include('cjcx.urls')),
    ]

    7、写前端页面。。。。。

    在cjcx应用下面新建templates文件夹放我们的html文件(请暂时忽略动态加载的代码,我懒得删了)

    <html>
    
    <head>
        <title>YUOL成绩查询系统</title>
        <style type="text/css">
            #border {
                margin: 0 auto;
                width: 500px;
                min-height: 500px;
                background-color: #FFFFFF;
                border: 1px solid #000000;
            }   
    
            #button {}
        </style>
    </head>
    
    <body style="text-align:center">
        <div id="border">
            <h1>YUOL成绩查询系统</h1><br/>
            <form action="" method="post"> 账号:
                <input type="text" id="xuehao" name="Sno" /><br/> 密码:
                <input type="password" id="pwd" name="Spwd" /><br/><br/>
                <input type="submit" value="查询" id="submit" /><br/>
                <div style="text-align:left;padding-left:50px;">
                    -----------------------------------------------------------<br/> 
                    姓名:{{ student.Sname }}<br/>
                     学号:{{ student.Sno}}<br/>
                      班级:{{ student.Sdept }}<br/>
                </div>
                -----------------------------------------------------------<br/>
                <div>
                   &nbsp;&nbsp; &nbsp;&nbsp;
                    <br>
                    <div style="display:inline-block;150px;">
                         科目:<br>
                        {{ course.Cname }}
                    </div>
                    <div style="display:inline-block;150px;">
                        成绩:<br>
                        {{ sc.Grade }}
                    </div>
                    <div style="display:inline-block;150px;">
                         学分:<br>
                        {{ course.Credit }}
                    </div>
    
                </div>
            </form>
        </div>
    </body>
    
    </html>

    修改views.py:

    # -*- coding: utf-8 -*-
    from __future__ import unicode_literals
    from django.http import HttpResponse
    from django.shortcuts import render
    
    # Create your views here.
    
    def index(request):
        return render(request, 'jwcjcx.html')

    然后就成这样了。。。。。

    8、根据jwc数据库设计Models。。。。

    django默认支持的是sqllite,,现在换成 mariadb,修改settings.py

    DATABASES = { 
        'default': {
    #        'ENGINE': 'django.db.backends.sqlite3',
    #        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'jwc2',
            'USER':'root',
            'PASSWORD':'你的密码',
            'HOST':'localhost',
            'PORT':'3306',
         }   
    }

    9、去models.py下面建表吧。。。。

    # -*- coding: utf-8 -*-
    from __future__ import unicode_literals
    
    from django.db import models
    
    # Create your models here.
    
    class Student(models.Model):
        Sno=models.CharField(max_length=9,primary_key=True)
        Sname=models.CharField(max_length=20,unique=True)
        Sdept=models.CharField(max_length=20)
        Spwd=models.CharField(max_length=20)
    
    class Course(models.Model):
        Cno=models.CharField(max_length=2,primary_key=True)
        Cname=models.CharField(max_length=30,unique=True)
        Credit=models.DecimalField(max_digits=2, decimal_places=1)
    
    class SC(models.Model):
        Sno=models.CharField(max_length=9)
        Cno=models.CharField(max_length=2)
        Grade=models.IntegerField()
    
        def __unicode__(self):
            return self.Sno

    这种ORM免去了写sql语句的麻烦,直接把表封装成一个类继承model.Model,查询字段直接‘点’操作。。。很方便。

    然后生成数据模型表:python manage.py makemigrations 

    再将数据表迁移到mariadb数据库:python manage.py migrate

    生成cjcx_三个表,其他是django默认的不用管,另外数据库要自己先建(create database jwc2 charset=utf8;)

    10、使用django admin做数据管理。。。。Admin真心好用这是django框架最显著的一个优势。。。

    创建用户:python manage.py createsuperuser

    然后在主机后面加/admin就可以登录。。。我们发现它的css和img丢失了

    解决办法:

    在jwc2下面建一个静态文件夹:static

    修改settings.py。。。在最后一行添加STATIC_ROOT = "/var/www/html/jwc2/static/",LANGUAGE_CODE = 'zh-Hans'(改成中文的admin)

    执行命令 :python manage.py collectstatic  

    上面apache的静态文件配置取消注释。。。

    这样进去看不到数据表,需要修改admin.py引入models

    # -*- coding: utf-8 -*-
    from __future__ import unicode_literals
    
    from django.contrib import admin
    import models
    # Register your models here.
    admin.site.register(models.Student)
    admin.site.register(models.Course)
    admin.site.register(models.SC)

    可以直接操作数据库了。。。django的强大之处。。

    11、下面开始我们最重要的业务逻辑。。

    数据入库(MVC中的M,models):我这里把Course表的Cno给删了,把SC表的Cno换成Cname了。。。和上面有所不同,只需要把库删了重新生成数据表即可。。。

    #encoding=utf-8
    from bs4 import BeautifulSoup
    from selenium import webdriver
    from selenium.webdriver.common.keys import Keys
    import MySQLdb
    import time
    import urllib
    import urllib2
    import sys 
    
    
    reload(sys)
    sys.setdefaultencoding('utf8')
    
    conn= MySQLdb.connect(
            host='localhost',
            port = 3306,
            user='root',
            passwd='密码',
            db ='jwc2',
            charset='utf8'
            )   
    cur = conn.cursor()
    
    driver = webdriver.PhantomJS();
    driver.get("教务处登录入口")
    driver.find_element_by_name('txtUid').send_keys('账号')
    driver.find_element_by_name('txtPwd').send_keys('密码')
    driver.find_element_by_id('btLogin').click()
    cookie=driver.get_cookies()
    driver.get("http://jwc2.yangtzeu.edu.cn:8080/cjcx.aspx")
    driver.find_element_by_name("Button2").click()
    html=driver.page_source
    #html = open("btAllcj.html","r")
    soup = BeautifulSoup(html,"lxml")
    Sno = str(soup.find(id="lbXH").getText())
    Sname = str(soup.find(id="lbXm").getText())
    Sdept =  str(soup.find(id="lbBj").getText())
    Student = (Sno,Sname,Sdept,'12345678')
    sql = "insert into cjcx_student values(%s,%s,%s,%s)" 
    cur.execute(sql,Student)
    id = 0
    tables = soup.findAll("table")
    for tab in tables[1:2]:
        for tr in tab.findAll("tr")[1:]:
            count = 0 
            for td in tr.findAll("td"):
                count += 1
                if count==1:
                    Cname = td.getText()
                if count==2:
                    Grade = td.getText()
              id += 1 sql
    = "insert into cjcx_sc values(%s,%s,%s,%s)" SC = (id,Sno,Cname,Grade) cur.execute(sql,SC) if count==3: Credit = td.getText() sql = "insert into cjcx_course values(%s,%s)" Course = (Cname,Credit) cur.execute(sql,Course) conn.commit() cur.close() conn.close()

    业务逻辑views.py(MVC中的V,views)

    # -*- coding: utf-8 -*-
    from __future__ import unicode_literals
    from django.http import HttpResponse
    from django.shortcuts import render
    from . import models
    
    # Create your views here.
    
    def index(request):
        return render(request, 'jwcjcx.html')
    
    def search_action(request):
        Sno = request.POST['Sno']
        Spwd = request.POST['Spwd']
    #这里放爬虫和数据入库的代码。。。。。
        student = models.Student.objects.get(Sno=Sno)
        pwd = student.Spwd
        if Spwd==pwd:
            sc = models.SC.objects.filter(Sno=Sno)
    #       course = models.Course.objects.filter(Cname=sc.Cname)
            return render(request,'jwcjcx.html',{'student':student, 'sc':sc})

    修改urls.py(MVC中的C,Controller)

    jwc2项目urls:

    from django.conf.urls import url,include
    from django.contrib import admin
    
    urlpatterns = [ 
        url(r'^admin/', admin.site.urls),
        url(r'^cjcx/',include('cjcx.urls', namespace='cjcx')),
    ]

    cjcx应用urls:

    from django.conf.urls import url 
    from . import views
    
    urlpatterns = [ 
        url(r'^$', views.index),
        url(r'^search/$',views.search_action,name='search_action'),
    ]

    12、前端数据渲染。。。。

    <html>
    
    <head>
        <title>YUOL成绩查询系统</title>
        <style type="text/css">
            #border {
                margin: 0 auto;
                 500px;
                min-height: 500px;
                background-color: #FFFFFF;
                border: 1px solid #000000;
            }   
    
            #button {}
        </style>
    </head>
    
    <body style="text-align:center">
        <div id="border">
            <h1>YUOL成绩查询系统</h1><br/>
            <form action="{% url 'cjcx:search_action' %}" method="post">{% csrf_token %} 账号:
                <input type="text" id="xuehao" name="Sno" /><br/> 密码:
                <input type="password" id="pwd" name="Spwd" /><br/><br/>
                <input type="submit" value="查询" id="submit" /><br/>
                <div style="text-align:left;padding-left:50px;">
                    -----------------------------------------------------------<br/> 
                    姓名:{{ student.Sname }}<br/>
                     学号:{{ student.Sno}}<br/>
                      班级:{{ student.Sdept }}<br/>
                </div>
                -----------------------------------------------------------<br/>
                <div>
                   &nbsp;&nbsp; &nbsp;&nbsp;
                    <br/>
                    <div style="display:inline-block;200px;">
                         科目:<br/>
                        {% for sc in sc %}
                        {{ sc.Cname }}<br/>
                        -------------------<br/>
                        {% endfor %}
                    </div>
                    <div style="display:inline-block;100px;">
                        成绩:<br/>
                        {% for sc in sc %}
                        {{ sc.Grade }}<br/>
                        ------<br/>
                        {% endfor %}
                    </div>
                    <div style="display:inline-block;150px;">
                         学分:<br/>
                        {% for course in course %}
                        {{ course.Credit }}
                        {% endfor %}
                    </div>
    
                </div>
            </form>
        </div>
    </body>
    
    </html>
                                                                    

     收工。。。。。。

    写了两天两夜,实在卡不住了,后面学分就没写了。。。。。。。。。爬虫还不稳定,逻辑判断几乎没写。。。只是简单实现了功能。。。

    最后附上一张照片:

  • 相关阅读:
    Loading CSS without blocking render
    总结Web应用中基于浏览器的安全漏洞
    React Native通信机制详解
    HTML Imports
    编程语言和它们的创造者
    USB Transfer and Packet Sizes
    灰色心情
    c++ 深入理解虚函数
    在VS2012中采用C++中调用DLL中的函数(4)
    在C++中调用DLL中的函数(3)
  • 原文地址:https://www.cnblogs.com/Vito-Yan/p/7101132.html
Copyright © 2020-2023  润新知