第一次爬虫(使用node.js与Mysql)

让我们开始吧~~~~~~

爬虫

期中作业

一、项目介绍

在这里插入图片描述本次的小目标是爬取新浪网和中新网的新闻!!
两个爬虫的实现如下:

二、实现过程

1、引入模块
为了实现一个爬虫,我们需要在代码头部用require函数引入request、cheerio、iconv-lite和fs四个模块,可以这样做:

var fs = require('fs');//该模块提供本地文件的读写能力
var myRequest = require('request');
var myCheerio = require('cheerio');
var myIconv = require('iconv-lite');
//为了实现爬虫功能,通常要在代码头部用require函数引入request、cheerio、iconv-lite和fs四个模块

2、连接数据库并写出域名

require('date-utils');//一个日期工具类
var mysql = require('./mysql.js');

var source_name = "新浪网";//网页原名
var domain = 'https://news.sina.com.cn/';//域名
var myEncoding = "utf-8";
var seedURL = 'https://news.sina.com.cn/';

注意拼写一定要正确!本人拼新浪sina拼错了两次。。

3、用正则表达式筛选
通过查看网页源代码,可以了解到每一条新闻的特征,借以正则表达式来筛选。如每条新闻的连接中都有2021-4-20这样的字样,是明显特征。

var seedURL_format = "$('a')";//把所有链接取出来
var keywords_format = " $('meta[name=\"keywords\"]').eq(0).attr(\"content\")";
var title_format = "$('title').text()";
var date_format = "$('span.date').text()";
var author_format = "$('a.source').text()";
var content_format = "$('div.article').text()";
var desc_format = " $('h1.main-title').text()";
var source_format = "$('a.source').text()";
var url_reg = /\/c\/(\d{4})-(\d{2})-(\d{2})\//; //“/c/2021-4-18/s”

//定义新闻元素的读取方式
var regExp = /((\d{4}|\d{2})(\-| \/| \.)\d{1,2}\3\d{1,2})|(\d{4}年\d{1,2}月\d{1,2}日)/

4、防止我们的爬虫被屏蔽嘤嘤
通过上网查询,明白了怎么做到这一点,以及这一步的重要性。

//防止网站屏蔽我们的爬虫
var headers = {
    
    
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36'
}//防止被屏蔽

5.回调函数登场噔噔蹬蹬
myRequest需要传入两个参数,第一个url是将要发送请求的网址,第二个函数便是回调函数啦(callback)。
另外,回调函数直接体现了node.js异步编程的特性,能加快代码运行的速度。
同时,构造一个模仿浏览器的request。

//request模块异步fetch url
function request(url, callback) {
    
    
    var options = {
    
    
        url: url,
        encoding: null,
        //proxy: 'http://x.x.x.x:8080',
        headers: headers,
        timeout: 10000 //
    }
    myRequest(options, callback)
};

6、读取种子页面

seedget();
function seedget() {
    
    
    request(seedURL, function(err, res, body) {
    
    
        var html = myIconv.decode(body, myEncoding);
        
        var $ = myCheerio.load(html, {
    
     decodeEntities: true });
        var seedurl_news;
        try {
    
    
            seedurl_news = eval(seedURL_format);
        } catch (e) {
    
     console.log('url列表所处的html块识别出错:' + e) };
        seedurl_news.each(function(i, e) {
    
     
            var myURL = "";
            try {
    
    
                var href = "";
                href = $(e).attr("href");
                if (href == undefined) return;
                if ((href.toLowerCase().indexOf('http://') >= 0) || (href.toLowerCase().indexOf('https://') >= 0)) myURL = href; //http://开头的
                else if (href.startsWith('//')) myURL = 'http:' + href; 
                else myURL = seedURL.substr(0, domain.lastIndexOf('/') + 1) + href; //其他

            } catch (e) {
    
     console.log('识别种子页面中的新闻链接出错:' + e) }

            if (!url_reg.test(myURL)) return; //检验是否符合新闻url的正则表达式
            var fetch_url_Sql = 'select url from fetches where url=?';
            var fetch_url_Sql_Params = [myURL];
            mysql.query(fetch_url_Sql, fetch_url_Sql_Params, function(qerr, vals, fields) {
    
    
                newsGet(myURL);
            });
        });
    });
};

其中,cheerio模块可以用来解析html, 在try语句中,我们则找到了想要的URL.

7.读取新闻页面
将这些新闻通过fetch变量放到数据库中——

function newsGet(myURL) {
    
     //读取新闻页面
    request(myURL, function(err, res, body) {
    
     //读取新闻页面
        //try {
    
    
        var html_news = myIconv.decode(body, myEncoding); //用iconv转换编码
        //console.log(html_news);
        //准备用cheerio解析html_news
        var $ = myCheerio.load(html_news, {
    
     decodeEntities: true });
        myhtml = html_news;
        //} catch (e) {    console.log('读新闻页面并转码出错:' + e);};

        console.log("转码读取成功:" + myURL);
        //动态执行format字符串,构建json对象准备写入文件或数据库
        var fetch = {
    
    };
        fetch.title = "";
        fetch.content = "";
        fetch.publish_date = (new Date()).toFormat("YYYY-MM-DD");
        //fetch.html = myhtml;
        fetch.url = myURL;
        fetch.source_name = source_name;
        fetch.source_encoding = myEncoding; //编码
        fetch.crawltime = new Date();

        if (keywords_format == "") fetch.keywords = source_name; // eval(keywords_format);  //没有关键词就用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); //刊登日期   
        console.log('date: ' + fetch.publish_date);
        fetch.publish_date = regExp.exec(fetch.publish_date)[0];
        fetch.publish_date = fetch.publish_date.replace('年', '-')
        fetch.publish_date = fetch.publish_date.replace('月', '-')
        fetch.publish_date = fetch.publish_date.replace('日', '')
        fetch.publish_date = new Date(fetch.publish_date).toFormat("YYYY-MM-DD");

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

        if (content_format == "") fetch.content = "";
        else fetch.content = eval(content_format).replace("\r\n" + fetch.author, ""); //内容,是否要去掉作者信息自行决定

        if (source_format == "") fetch.source = fetch.source_name;
        else fetch.source = eval(source_format).replace("\r\n", ""); //来源

        if (desc_format == "") fetch.desc = fetch.title;
        else fetch.desc = eval(desc_format).replace("\r\n", ""); //摘要    

        // var filename = source_name + "_" + (new Date()).toFormat("YYYY-MM-DD") +
        //     "_" + myURL.substr(myURL.lastIndexOf('/') + 1) + ".json";
        // 存储json
        // fs.writeFileSync(filename, JSON.stringify(fetch));

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

        //执行sql,数据库中fetch表里的url属性是unique的,不会把重复的url内容写入数据库
        mysql.query(fetchAddSql, fetchAddSql_Params, function(qerr, vals, fields) {
    
    
            if (qerr) {
    
    
                console.log(qerr);
            }
        }); //mysql写入
    });
}

至此,我们成功将读取的新闻写入Mysql数据库中。效果如下:

  • List item
    在这里插入图片描述
    在数据库中创建表格:
    在这里插入图片描述

  • 下图是在数据库中的显示:List item
    下面,让我们再尝试另一个网站:

  • List item
    下一个——中新网
    实现过程与上方类似,下面的代码是我所采用的稍微简单一点的方法:

'use strict';
var myCheerio = require('cheerio');
var myRequest = require('request');
var iconv = require('iconv-lite');
var database = require('./mysql.js');

var seedURL = "https://www.chinanews.com/china/";

var header = {
    
    
	'Connection': 'Keep-Alive',
	'Accept': 'text/html, application/xhtml+xml, */*',
	'Accept-Language': 'en-US,en;q=0.8,zh-Hans-CN;q=0.5,zh-Hans;q=0.3',
	'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko'
};

function request(url, callback) {
    
    
	var options = {
    
    
		url: url,
		encoding: null,
		headers: header,
		timeout: 10000
	}
	myRequest(options, callback)
}
;
request(seedURL, function (err, res, body) {
    
    
	if (err || res.statusCode != 200) {
    
    
		console.error(err);
		console.error(res.statusCode);
		return;
	}
	let $ = myCheerio.load(body);

	let cnt = 0;//找div class="life_left_ul"
	let div = $("div.life_left_ul ").eq(cnt);
	while (div.text()) {
    
    
		let cnt1 = 0;//找div的标签li
		let li = div.children("ul").children("li").eq(cnt1);
		while (li.text()) {
    
    
			let cnt2 = 0;//找a
			let a = li.children("a").eq(cnt2);
			while (a.text()) {
    
    
				let urlstr = "https:" + a.attr("href");
				let title = a.text();
				console.log(`爬取新闻${
      
      title}`);
				if (urlstr && title) {
    
    
					request(urlstr, function (err, res, body) {
    
    
						if (err || res.statusCode != 200) {
    
    
							console.error(err);
							console.error(res.statusCode);
							return;
						}
						body = iconv.decode(body, 'utf-8');
						let $ = myCheerio.load(body);

						database.query('INSERT INTO news1(URL, Title, Time, Content, Source, Author) VALUES(?, ?, ?, ?, ?, ?);', [
							res.request.uri.href,
							$("title").text(),
							$("span#pubtime_baidu").text(),
							$("div.left_zw").text(),
							$("span#source_baidu").text(),
							$("span#author_baidu").text()
						], function (err, vals, fields) {
    
    
							if (err) {
    
    
								console.error(`数据库错误:${
    
    err}`);
							}
								console.log(`完成爬取${
    
    $("title").text()}`);
						});
					});
				}
				cnt2++;
				a = li.children("a").eq(cnt2);
				urlstr = a.attr("href");
				title = a.text();
			}
			cnt1++;
			li = div.children("ul").children("li").eq(cnt1);
		}
		cnt++;
		div = $("div.life_left_ul ").eq(cnt);
	}
});

在将两个新闻网站的内容都存入数据库后,可以搭建属于自己的网站。

三、前端和后端

1.后端框架

为了实现一个网页,必须写好后端代码。首先先运行js后缀的文件,编辑好html后缀(命名为search)的文件,再搜索http://127.0.0.1:3000/search.html,便可以实现对特定新闻的搜索。
在这里插入图片描述
这里使用express框架。但在安装的时候,express总是安不上,经过询问才知道,是安装express_generator。

2.前端查询

完成html代码后,我随意地输入一个关键词,看下图:
在这里插入图片描述
此时页面显得非常凌乱,感受很不直观,就要用到前面搭好的框架,使结果条理清晰,看下面~~
在这里插入图片描述
插入背景图片之后。。。。。。
在这里插入图片描述
我采用了拼接的方法,以免遮挡文字。
这样,我们从两个新闻网站中爬取到了关键词为“英国”的有关新闻。

3.事件热度分析

<div class="search bar2">
	<input type="text" name="keywordtime" id="HeatAnalysisKeyword" placeholder="输入关键词进行时间热度分析">
	<input type="button" value="开始" onclick="HeatAnalysis()">
	<p id="demo">时间热度分析: </p>
</div>

在这里,我把时间热度分析函数,命名为heatAnalysis.最终可为我们呈现出统计数据。

三、总结回顾

这一次的爬虫选取了两个网站,中新网和新浪网,它们有各自的特点。其中中新网代码稍微既简单一些。学会了如何找到网站的各级标签,写爬虫代码,将信息放入数据库中,创建网页获取想要的信息。。。
最后,谢谢老师、助教的指导哇!!
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_51499597/article/details/115840754