记录一次从零开始的nodejs爬虫开发以及网页展示

零web编程基础开发一个nodejs爬虫

目标:

爬取目标网站所有新闻并存入本地文件/mysql,搭建简单网页完成对爬取结果的搜索与展示分析。
目标网站:
新浪新闻:https://news.sina.com.cn/
网易新闻:https://news.163.com/
搜狐新闻:http://news.sohu.com/
(本篇采用图文结合,对于其中的代码作用,部分直接说明,部分在代码注释中说明)
①分析网站首页结构在这里插入图片描述
找到新闻部分对应url
在这里插入图片描述
分析编写锁定新闻url的正则表达式

var url_reg = /\/(\d{4})\-(\d{2})\-(\d{2})\/doc\-(\w{8})(\d{7})\.shtml/;

②分析新闻页面内容

在这里插入图片描述
找出所需title、author、keywords等信息,记录其class、id,准备相应代码
备注:新浪新闻部分新闻页面没有提供作者信息,或者为无题、关键字页面,之后进行录入时若网页未提供,则相关栏目留空白。

var source_name = "新浪";//来源
var myencoding = "utf-8";//解码
var seedurl = 'https://news.sina.com.cn/';//主页面
var seedurl_format = "$('a')";//寻找子页面
var keywords_format = " $('meta[name=\"keywords\"]').eq(0).attr(\"content\")";//关键词
var title_format = "$('.main-title').text()";//标题
var date_format = "$('.date').text()";//日期
var author_format = "$('.show_author').text()";//编辑
var content_format = "$('.article').text()";//文章
var des_format = " $('meta[name=\"description\"]').eq(0).attr(\"content\")";//摘要

③引入爬取所需的nodejs包

var fs = require('fs');//文件储存用
var myrequest = require('request');//访问页面用
var mycheerio = require('cheerio');//解析html用
var myiconv = require('iconv-lite');//编码用
var mysql = require('./mysql.js');//mysql存储用
require('date-utils');//日期工具类,用于格式化日期

④伪装访问(此处使用win环境的safari)

var headers = 
{
    'User-Agent': 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50'
}

⑤构建request回调函数

function request(url, callback) {
    var options = {
        url: url,
        encoding: null,
        headers: headers,
        timeout: 10000 
    }
    myrequest(options, callback)
}

⑥构建针对主页面(seedurl)的函数,用以进入具体的各个新闻页面

request(seedurl, function(err, res, body)     //访问并且读取种子页面
{
    //用iconv转换编码
    var html = myiconv.decode(body, myencoding);
    //console.log(html);
    //准备用cheerio解析html
    var $ = mycheerio.load(html, { decodeEntities: true });
    var seedurl_news;

    try {
        seedurl_news = eval(seedurl_format);
    } catch (e) { console.log('url中html识别error:' + e) };

    seedurl_news.each(function(i, e) { //遍历种子页面里所有的a链接,获取所有新闻url
        var myurl = "";
        try {
            //获取新闻url,可在此处设计循环计数以限制爬取上限数量
            var href = "";
            href = $(e).attr("href");
            if (typeof(href) == "undefined") {  // 部分新闻地址为undefined
                return true;
            }
            if (href.toLowerCase().indexOf('http://') >= 0 || href.toLowerCase().indexOf('https://') >= 0) myurl = href; //针对http://或者https://开头
            else if (href.startsWith('//')) myurl = 'http:' + href; //针对//开头
            else myurl = seedurl.substr(0, seedurl.lastIndexOf('/') + 1) + href; //针对其他

        } catch (e) { console.log('seed中新闻链接error:' + e) }

        if (!url_reg.test(myurl)) return; //检验符合该网站新闻url的正则表达式
        getnews(myurl); //进入新闻页面
    });
});

⑦编写获取新闻页面中所需信息的函数

function getnews(myurl) {
    request(myurl, function(err, res, body) {//读取新闻页面
        var html_news = myiconv.decode(body, myencoding); //用iconv编码
        var $ = mycheerio.load(html_news, { decodeEntities: true });        //用cheerio解析html_news
        myhtml = html_news;

        console.log("转码读取成功:" + myurl);
        //format字符串,开始写入
        var fetch = {};

        fetch.publish_date = (new Date()).toFormat("YYYY-MM-DD");
        fetch.content = "";
        fetch.title = "";
        fetch.source_name = source_name;
        fetch.url = myurl;
        fetch.source_encoding = myencoding; //编码
        fetch.crawltime = new Date();

        if (keywords_format == "") fetch.keywords = source_name;//没有关键词就用sourcename
        else fetch.keywords = eval(keywords_format);

        if (title_format == "") fetch.title = ""
        else fetch.title = eval(title_format); //标题

        if (date_format != "") fetch.publish_date = eval(date_format); //publish日期   
        console.log('date: ' + fetch.publish_date);//发布日期
        console.log(myurl);//爬取对象

        if (author_format == "") fetch.author = source_name;  //作者
        else fetch.author = eval(author_format);

        if (content_format == "") fetch.content = "";
        else fetch.content = eval(content_format); //内容
        fetch.content = fetch.content.replace(/[\r\n]/g,"");
        //去除回车换行
        
        if (des_format == "") fetch.des = fetch.title;
        else fetch.des = eval(des_format); //摘要  
    });
}

⑧在getnews函数中补充储存爬取信息的方式,此处分别采用生成文件和mysql存储
生成json文件:

var filename = source_name + "_" + (new Date()).toFormat("YYYY-MM-DD") +
    "_" + myurl.substr(myurl.lastIndexOf('/') + 1) + ".json";
//存储json
fs.writeFileSync(filename, JSON.stringify(fetch));//将fetch转化为字符串录入

mysql存储:

var fetchadd = 'INSERT INTO fetches(source_name,url,source_encoding,title,' +
    'author,keywords,publish_date,crawltime,description,content) VALUES(?,?,?,?,?,?,?,?,?,?)';
var fetchadd_params = 
[
    fetch.source_name,fetch.url,fetch.source_encoding,
    fetch.title, fetch.author, fetch.keywords, fetch.publish_date,
    fetch.crawltime.toFormat("YYYY-MM-DD HH24:MI:SS"), fetch.des,fetch.content
];

//执行sql,库中fetch里的url属性为unique,防止重复
mysql.query(fetchadd, fetchadd_params, function(qerr, vals, fields) 
{
    if (qerr) 
    {
        console.log(qerr);
    }
}); //写入mysql

附上对应使用的mysql包原文件(根据本地环境设置登录参数)

var mysql = require("mysql");
var pool = mysql.createPool({
    host: '127.0.0.1',
    user: 'root',
    password: 'hdx',
    database: 'crawl'
});
var query = function(sql, sqlparam, callback) 
{
    pool.getConnection(function(err, conn) {
        if (err) {
            callback(err, null, null);
        } else {
            conn.query(sql, sqlparam, function(qerr, vals, fields) {
                conn.release(); //释放连接 
                callback(qerr, vals, fields); //事件驱动回调 
            });
        }
    });
};
var query_noparam = function(sql, callback) 
{
    pool.getConnection(function(err, conn) {
        if (err) {
            callback(err, null, null);
        } else {
            conn.query(sql, function(qerr, vals, fields) {
                conn.release(); //释放连接 
                callback(qerr, vals, fields); //事件驱动回调 
            });
        }
    });
};
exports.query = query;
exports.query_noparam = query_noparam;

使用mysql建立一个简单的表格,其中database名字为crawl,含有一个名为fetches的表,表中各个表头类型如下所列出(部分规定了内容类型与长度)。

CREATE TABLE `fetches` (
  `id_fetches` int(11)  NOT NULL AUTO_INCREMENT,
  `source_name` varchar(300) DEFAULT NULL,
  `url` varchar(300) DEFAULT NULL,
  `source_encoding` varchar(50) DEFAULT NULL,
  `title` varchar(300) DEFAULT NULL,
  `author` varchar(300) DEFAULT NULL,
  `keywords` varchar(300) DEFAULT NULL,
  `publish_date` longtext,
  `crawltime` datetime DEFAULT NULL,
  `description` longtext,
  `content` longtext,
  `createtime` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id_fetches`),
  UNIQUE KEY `id_fetches_UNIQUE` (`id_fetches`),
  UNIQUE KEY `url_UNIQUE` (`url`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

(注意与爬虫程序中的信息类型对应,longtext等属性设置正确,约束正确)

⑨试运行
存为文件成功:
在这里插入图片描述
存于mysql(用select相关命令查询对应项)(后续的网页查询原理在此处):
在这里插入图片描述
代码:

var source_name = "新浪";//来源
var myencoding = "utf-8";//解码
var seedurl = 'https://news.sina.com.cn/';//主页面
var seedurl_format = "$('a')";//寻找子页面
var keywords_format = " $('meta[name=\"keywords\"]').eq(0).attr(\"content\")";//关键词
var title_format = "$('.main-title').text()";//标题
var date_format = "$('.date').text()";//日期
var author_format = "$('.show_author').text()";//编辑
var content_format = "$('.article').text()";//文章
var des_format = " $('meta[name=\"description\"]').eq(0).attr(\"content\")";//摘要
var url_reg = /\/(\d{4})\-(\d{2})\-(\d{2})\/doc\-(\w{8})(\d{7})\.shtml/;//用于匹配主页面中的新闻子页面的正则表达式

var fs = require('fs');//文件
var myrequest = require('request');//访问
var mycheerio = require('cheerio');//解析html
var myiconv = require('iconv-lite');//编码用
var mysql = require('./mysql.js');//mysql存储用
require('date-utils');//日期工具类,用于格式化日期

//伪装为windows的safari5.1进行访问
var headers = 
{
    'User-Agent': 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50'
}

//利用request模块回调函数
function request(url, callback) {
    var options = {
        url: url,
        encoding: null,
        headers: headers,
        timeout: 10000 
    }
    myrequest(options, callback)
}

request(seedurl, function(err, res, body)     //访问并且读取种子页面
{
    //用iconv转换编码
    var html = myiconv.decode(body, myencoding);
    //console.log(html);
    //准备用cheerio解析html
    var $ = mycheerio.load(html, { decodeEntities: true });
    var seedurl_news;

    try {
        seedurl_news = eval(seedurl_format);
    } catch (e) { console.log('url中html识别error:' + e) };

    seedurl_news.each(function(i, e) { //遍历种子页面里所有的a链接
        var myurl = "";
        try {
            //获取新闻url
            var href = "";
            href = $(e).attr("href");
            if (typeof(href) == "undefined") {  // 部分新闻地址为undefined
                return true;
            }
            if (href.toLowerCase().indexOf('http://') >= 0 || href.toLowerCase().indexOf('https://') >= 0) myurl = href; //针对http://或者https://开头
            else if (href.startsWith('//')) myurl = 'http:' + href; //针对//开头
            else myurl = seedurl.substr(0, seedurl.lastIndexOf('/') + 1) + href; //针对其他

        } catch (e) { console.log('seed中新闻链接error:' + e) }

        if (!url_reg.test(myurl)) return; //检验符合该网站新闻url的正则表达式
        getnews(myurl); //进入新闻页面
    });
});

function getnews(myurl) {
    request(myurl, function(err, res, body) {//读取新闻页面
        var html_news = myiconv.decode(body, myencoding); //用iconv编码
        var $ = mycheerio.load(html_news, { decodeEntities: true });//用cheerio解析html_news
        myhtml = html_news;

        console.log("转码读取成功:" + myurl);
        //format字符串,开始写入
        var fetch = {};

        fetch.publish_date = (new Date()).toFormat("YYYY-MM-DD");
        fetch.content = "";
        fetch.title = "";
        fetch.source_name = source_name;
        fetch.url = myurl;
        fetch.source_encoding = myencoding; //编码
        fetch.crawltime = new Date();

        if (keywords_format == "") fetch.keywords = source_name;//没有关键词就用sourcename
        else fetch.keywords = eval(keywords_format);

        if (title_format == "") fetch.title = ""//无标题
        else fetch.title = eval(title_format); //标题

        if (date_format != "") fetch.publish_date = eval(date_format); //publish日期   
        console.log('date: ' + fetch.publish_date);//发布日期
        console.log(myurl);//爬取对象

        if (author_format == "") fetch.author = source_name;  //作者
        else fetch.author = eval(author_format);

        if (content_format == "") fetch.content = "";
        else fetch.content = eval(content_format); //内容
        fetch.content = fetch.content.replace(/[\r\n]/g,"");//去除回车换行

        if (des_format == "") fetch.des = fetch.title;
        else fetch.des = eval(des_format); //摘要    

        
        var filename = source_name + "_" + (new Date()).toFormat("YYYY-MM-DD") +
            "_" + myurl.substr(myurl.lastIndexOf('/') + 1) + ".json";
        //存储json
        fs.writeFileSync(filename, JSON.stringify(fetch));//将fetch转化为字符串录入
        
        /*
        var fetchadd = 'INSERT INTO fetches(source_name,url,source_encoding,title,' +
            'author,keywords,publish_date,crawltime,description,content) VALUES(?,?,?,?,?,?,?,?,?,?)';
        var fetchadd_params = 
        [
            fetch.source_name,fetch.url,fetch.source_encoding,
            fetch.title, fetch.author, fetch.keywords, fetch.publish_date,
            fetch.crawltime.toFormat("YYYY-MM-DD HH24:MI:SS"), fetch.des,fetch.content
        ];

        //执行sql,库中fetch里的url属性为unique,防止重复
        mysql.query(fetchadd, fetchadd_params, function(qerr, vals, fields) 
        {
            if (qerr) 
            {
                console.log(qerr);
            }
        }); //写入mysql
        */
    });
}

⑩建立网页对mysql进行搜索:
为了网页清晰美观,此处选用express框架。
在这里插入图片描述
在cmd中用express -e search_site建立项目文件夹,(-e为使用ejs),并将前之前使用的mysql.js文件拷入备用
在这里插入图片描述
之后在项目文件夹中安装需要的包(mysql等)
npm install --save;npm install;

再之后对routes/index.js进行编辑

var express = require('express');
var router = express.Router();
var mysql = require('../mysql.js');

/* GET 主页 */
router.get('/', function(req, res, next) {
    res.render('index', { title: 'Express' });
});

router.get('/process_get', function(request, response) {
    //sql
    var fetchSql = "select url,source_name,title,author,publish_date " +
        "from fetches where author like '%" + request.query.author + "%'";
        var tarray=request.query.title.split(" ");
        for(var i=0;i<tarray.length;i++){
          fetchSql+="and title like '%"+ tarray[i] + "%'";
        }
        fetchSql+="order by publish_date"
    mysql.query(fetchSql, function(err, result, fields) {
        response.writeHead(200, {
            "Content-Type": "application/json"
        });
        response.write(JSON.stringify(result));
        response.end(); ``
    });
});
module.exports = router;

其中,fetchsql为对mysql操作的核心,此处作出解释:
第一,本次搜索参数有author和title两个,其中author为人名,无须复合查询,因而直接使用request.query.author输入即可;

    var fetchSql = "select url,source_name,title,author,publish_date " +
        "from fetches where author like '%" + request.query.author + "%'";

第二,由于title较长,为了便于复合要素的查询(例如对“A B”的查询,空格作为分割符号),采用.split(“ ”)按空格分割获得数组(如“A,B”),再利用“and title like”语句循环导入,即可成功完成符合搜索(用like与通配符完成模糊查询)。

        var tarray=request.query.title.split(" ");
        for(var i=0;i<tarray.length;i++){
          fetchSql+="and title like '%"+ tarray[i] + "%'";
        }

第三,为了方便分析新闻时间热度情况,先按时间序排放搜索结果便于查看

        fetchSql+="order by publish_date"

最后,使用fetchSql完成搜索即可

    mysql.query(fetchSql, function(err, result, fields) {
        response.writeHead(200, {
            "Content-Type": "application/json"
        });
        response.write(JSON.stringify(result));
        response.end(); ``
    });

紧接着,完成html文件前后端的构建:

<!DOCTYPE html>
<html>
<header>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
</header>
<head>
    <style>
        .cardLayout{
            border:rgb(147, 64, 163) solid 10px;
            margin: 5px 0px;
        }
        tr{
            border: solid 3px;
        }
        td{
            border:solid 3px;
        }
    </style>
</head>
<body>
    <form>
        <br> 标题:<input type="text" id="input1" name="title_text">
        <br> 作者:<input type="text" id="input2" name="title_text">
        <input class="form-submit" type="button" id="btn1"value="查询">
        <input type="reset">
    </form>
    <div class="cardLayout">
        <table width="100%" id="record2"></table>
    </div>
    <script>
        $(document).ready(function() {
            $("#btn1").click(function() {
                $.get('/process_get?title=' + $("#input1").val()+'&author='+$("#input2").val(), function(data) {
                    $("#record2").empty();
                    $("#record2").append('<tr class="cardLayout"><td>url</td><td>source_name</td>' +
                        '<td>title</td><td>author</td><td>publish_date</td></tr>');
                    for (let list of data) {
                        let table = '<tr class="cardLayout"><td>';
                        Object.values(list).forEach(element => {
                            table += (element + '</td><td>');
                        });
                        $("#record2").append(table + '</td></tr>');
                    }
                });
            });

        });
    </script>
</body>
</html>

css格式按照喜好设置即可(此处主要满足显示清楚)

    <style>
        .cardLayout{
            border:rgb(147, 64, 163) solid 10px;
            margin: 5px 0px;
        }
        tr{
            border: solid 3px;
        }
        td{
            border:solid 3px;
        }
    </style>

搜索展示:

    <script>
        $(document).ready(function() {
            $("#btn1").click(function() {
                $.get('/process_get?title=' + $("#input1").val()+'&author='+$("#input2").val(), function(data) {
                    $("#record2").empty();
                    $("#record2").append('<tr class="cardLayout"><td>url</td><td>source_name</td>' +
                        '<td>title</td><td>author</td><td>publish_date</td></tr>');
                    for (let list of data) {
                        let table = '<tr class="cardLayout"><td>';
                        Object.values(list).forEach(element => {
                            table += (element + '</td><td>');
                        });
                        $("#record2").append(table + '</td></tr>');
                    }
                });
            });

        });
    </script>

其中获得form中信息传入get进行搜索(注意与input的id各自对应)

$("#btn1").click(function() {
    $.get('/process_get?title=' + $("#input1").val()+'&author='+$("#input2").val(), function(data)

紧接着按格式输出表格即可(表格标签style通过css调整)

            $("#record2").empty();
            $("#record2").append('<tr class="cardLayout"><td>url</td><td>source_name</td>' +
                '<td>title</td><td>author</td><td>publish_date</td></tr>');
            for (let list of data) {
                let table = '<tr class="cardLayout"><td>';
                Object.values(list).forEach(element => {
                    table += (element + '</td><td>');
                });
                $("#record2").append(table + '</td></tr>');
            }
        });
    });
});

构建完成后将html文件放入项目文件夹
在这里插入图片描述
之后在cmd启动express
在这里插入图片描述
浏览器访问html
在这里插入图片描述
测试各种功能是否正常:
单独搜索标题
在这里插入图片描述

复合搜索标题
在这里插入图片描述

标题+作者
在这里插入图片描述
发布时间从早到晚顺序排布
在这里插入图片描述
最后,为了美化展示,引入bootstrap中css表单进行结果分页展示,对html文件进行微调:
先在原先基础上引入bootstrap包,原css格式不变

<head>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
    <link href="http://www.itxst.com/package/bootstrap-table-1.14.1/bootstrap-4.3.1/css/bootstrap.css" rel="stylesheet" />
    <link href="http://www.itxst.com/package/bootstrap-table-1.14.1/bootstrap-table-1.14.1/bootstrap-table.css" rel="stylesheet" />
    <script src="http://www.itxst.com/package/bootstrap-table-1.14.1/bootstrap-table-1.14.1/bootstrap-table.js"></script>
    <style>
        .cardLayout{
            border:rgb(147, 64, 163) solid 10px;
            margin: 5px 0px;
        }
        tr{
            border: solid 3px;
        }
        td{
            border:solid 3px;
        }
    </style>
</head>

紧接着修改get函数中展示表单的部分(使用bootstrap方法)

    <script>
        $(document).ready(function() {
            $("#btn1").click(function() {
                /*$.get('/process_get?title=' + $("#input1").val()+'&author='+$("#input2").val(), function(data) {
                    $("#record2").empty();
                    $("#record2").append('<tr class="cardLayout"><td>url</td><td>source_name</td>' +
                        '<td>title</td><td>author</td><td>publish_date</td></tr>');
                    for (let list of data) {
                        let table = '<tr class="cardLayout"><td>';
                        Object.values(list).forEach(element => {
                            table += (element + '</td><td>');
                        });
                        $("#record2").append(table + '</td></tr>');
                    }
                });*/
            $.get('/process_get?title=' + $("#input1").val()+'&author='+$("#input2").val(), function(data) {
                    $("#record2").bootstrapTable({
                    search:true,		//加上搜索控件						
                    method: 'get',		//请求方式
                    pagination: true,	//是否显示分页
                    striped: true,      //是否显示行间隔色
                    uniqueId: "userId", //每一行的唯一标识,一般为主键列
                    pageSize: 5,        //每页的记录行数
                    sidePagination : 'client',              
                    columns:[{
                        field:'url',	//对应数据库字段名
                        title:'链接',
                    },{
                        field:'source_name',
                        title:'来源'
                    },{
                        field:'title',
                        title:'标题'
                    },{
                        field:'author',
                        title:'作者'
                    },{
                        field:'keywords',
                        title:'关键词'
                    },{
                        field:'publish_date',
                        title:'发布时间',
                    }],
                    data: data,
                    });
                });
            });
        });
    </script>

(bootstrap能简单表答进一步搜索,详细分页,时间热度分析等功能)

search:true,		//加上搜索控件,注意此处可进一步完善时间热度分析						
method: 'get',		//请求方式
pagination: true,	//是否显示分页
striped: true,      //是否显示行间隔色
uniqueId: "userId", //每一行的唯一标识,一般为主键列
pageSize: 5,        //每页的记录行数

尝试效果:
在这里插入图片描述
测试在搜索结果中进行search
在这里插入图片描述
分页成功,并且可以显示满足条件的搜索结果一共有多少条,也可以通过此处在进一步搜索中得到特定时间某个话题的新闻量(此处67rows即表示满足搜索条件的新闻一共有67条,结合日期信息可完成进一步时间热度分析)(成功加强了时间热度分析):
在这里插入图片描述
在这里插入图片描述
前后两种搜索页面均保存备用
在这里插入图片描述

代码通用性检测,对网易新闻进行爬取
查看网页结构,与前者风格类似
在这里插入图片描述
在这里插入图片描述

修改爬虫中关于页面结构中子页面、class、id等内容的检索规则(同根据新闻页结构)

var source_name = "网易";//来源
var myencoding = "utf-8";//解码
var seedurl = 'https://news.163.com/';//主页面
var seedurl_format = "$('a')";//寻找子页面
var keywords_format = "$('meta[name=\"keywords\"]').eq(0).attr(\"content\")";//关键词
var title_format = "$('title').text()";//标题
var date_format = "$('meta[property=\"article:published_time\"]').eq(0).attr(\"content\")";//日期
var author_format = "$('.post_author').text()";//编辑
var content_format = "$('.article').text()";//文章
var des_format = " $('meta[name=\"description\"]').eq(0).attr(\"content\")";//摘要
var url_reg = /\/news\/article\//;//用于匹配主页面中的新闻子页面的正则表达式

存入与之前相同的一个数据库进行搜索
在这里插入图片描述
(成功检索到新浪网易二者的新闻)
代码通用性检测,对搜狐新闻进行爬取
同样查看网页结构
在这里插入图片描述
在这里插入图片描述

修改爬虫中关于页面结构中子页面、class、id等内容的检索规则(同根据新闻页结构)

var source_name = "搜狐";//来源
var myencoding = "utf-8";//解码
var seedurl = 'http://news.sohu.com/';//主页面
var seedurl_format = "$('a')";//寻找子页面
var keywords_format = "$('meta[name=\"keywords\"]').eq(0).attr(\"content\")";//关键词
var title_format = "$('title').text()";//标题
var date_format = "$('meta[property=\"og:release_date\"]').eq(0).attr(\"content\")";//日期
var author_format = "$('meta[name=\"mediaid\"]').eq(0).attr(\"content\")";//编辑
var content_format = "$('article').text()";//文章
var des_format = " $('meta[name=\"description\"]').eq(0).attr(\"content\")";//摘要
var url_reg = /\/a\/(\d{9})\_/;//用于匹配主页面中的新闻子页面的正则表达式

存入与之前相同的一个数据库进行搜索
在这里插入图片描述
均成功实现。

总结:

本次开发耗时约半个学期,最终在老师的引导和前人提供的各类教程帮助下成功完成了项目。其中最大的收获莫过于积累了从零学习/开发web项目的经验,提高了查阅、应用相关资料的技能。虽然过程中充满了不成熟,但好歹迈出了第一步,今后要继续加油~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值