让我们开始吧~~~~~~
爬虫
期中作业
一、项目介绍
本次的小目标是爬取新浪网和中新网的新闻!!
两个爬虫的实现如下:
二、实现过程
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数据库中。效果如下:
-
在数据库中创建表格:
-
下图是在数据库中的显示:
下面,让我们再尝试另一个网站: -
下一个——中新网
实现过程与上方类似,下面的代码是我所采用的稍微简单一点的方法:
'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.最终可为我们呈现出统计数据。
三、总结回顾
这一次的爬虫选取了两个网站,中新网和新浪网,它们有各自的特点。其中中新网代码稍微既简单一些。学会了如何找到网站的各级标签,写爬虫代码,将信息放入数据库中,创建网页获取想要的信息。。。
最后,谢谢老师、助教的指导哇!!