当前位置:   article > 正文

利用Nodejs实现爬虫_nodejs 爬虫

nodejs 爬虫


前言

本学期期中作业是 新闻爬虫及爬取结果的查询网站,作为只有c语言基础的小菜鸟,刚看到要求时还是一脸懵,通过半个学期的学习,借助老师的代码,撸起袖子加油干,跌跌撞撞地也实现了爬虫。先来看看啥是爬虫,爬虫就是个自动获取网络内容的程序,又称为网页蜘蛛,网络机器人......(来自百度百科...)ok 话不多说 现在开始实现新闻爬虫以及爬取结果的查询网站。


一.工具安装

1.Nodejs

百度搜索nodejs进入官网

 点击下载,找到自己需要的版本

按照提示一路next 安装完成 在cmd中输入node -v可以查看安装版本

2.编码工具VsCode

这里因为以前写C/C++时下载过VScode所以稍微下个插件直接用了,也可以下载WebStorm,Sublime等等

WebStorm下载地址: WebStorm: The Smartest JavaScript IDE, by JetBrains

Sublime下载地址: Sublime Text - Text Editing, Done Right

VScode是一个轻量且强大的跨平台开源代码编辑器(IDE) 打开VScode应用商店下载nodejs插件

3.安装MySQL

下载地址:MySQL :: Download MySQL Community Server

数据库 根据自己需要的版本 下载 后面会详细描述

要下载的工具下载的差不多了,下面正式开始爬虫


二、引入模块

这里先看一下npm这个东西

npm就是Nodejs下的包管理器

  • 允许用户从NPM服务器下载别人编写的第三方包到本地使用。
  • 允许用户从NPM服务器下载并安装别人编写的命令行程序到本地使用。
  • 允许用户将自己编写的包或命令行程序上传到NPM服务器供别人使用

但是,npm的服务器位于国外可能会影响安装 所以淘宝团队做了国内镜像cnpm,与官方同步频率目前为 10分钟 一次以保证尽量与官方服务同步。

安装方法:

  • 安装:命令提示符执行
    npm install cnpm -g --registry=https://registry.npm.taobao.org
  • cnpm -v 来测试是否成功安装

通过改变地址来使用淘宝镜像

  • npm的默认地址是 https://registry.npmjs.org/
  • 可以使用npm config get registry查看npm的仓库地址
  • 可以使用npm config set registry https://registry.npm.taobao.org来改变默认下载地址,达到可以不安装cnpm就能采用淘宝镜像的目的,然后使用上面的get命令查看是否成功。

搞定之后 就可以用cnpm来下载需要的包

之后可以根据需要引入不同的包,在npm网站可以对包的用法进行查询

比如

获取网页内容(http\request\superagent等)

筛选网页信息(cheerio)

输出或存储信息(console\fs\mongodb\mysql等)

下面简单介绍几个

1.request来获取网页内容

  1. var request = require('request');
  2. // 通过 GET 请求来读取 http://cnodejs.org/ 的内容
  3. request('https://nba.hupu.com/', function (error, response, body) {
  4. if (!error && response.statusCode == 200) {
  5. // 输出网页内容
  6. console.log(body);
  7. }
  8. });

 运行之后得到

利用chrome 右键 查看网页源代码 发现和上面是一样的

2.mysql来连接到数据库

用来实现将数据存储到数据库中

  1. var mysql = require("mysql");
  2. var pool = mysql.createPool({
  3. host: '127.0.0.1',
  4. user: 'root',
  5. password: 'root',//密码
  6. database: 'crawl'
  7. });

 后面会详细介绍

3.cheerio抓取页面模块

cheerio是nodejs为服务器特别定制的,快速、灵活、实施的jQuery核心实现。适合各种Web爬虫程序。

借用老师发的代码来爬一篇北京大学官网的文章

  1. var myRequest = require('request')
  2. var myCheerio = require('cheerio')
  3. var myURL = 'https://www.pku.edu.cn/about.html'
  4. function request(url, callback) {
  5. var options = {
  6. url: url, encoding: null, headers: null
  7. }
  8. myRequest(options, callback)
  9. }
  10. request(myURL, function (err, res, body) {
  11. var html = body;
  12. var $ = myCheerio.load(html, { decodeEntities: false });
  13. console.log($.html());
  14. })

运行之后得到

 搞定


三.开始爬虫

下面根据老师发的代码示例,进行分析,然后实现爬虫,将新闻存储到自己的电脑中。

首先分析要爬取的网站 打开网页后点击检查,可以查看该网页相关部分的html代码

  1. var fs = require('fs');
  2. var myRequest = require('request');
  3. var myCheerio = require('cheerio');
  4. var myIconv = require('iconv-lite');
  5. require('date-utils');
  6. var mysql = require('./mysql.js');

首先安装所需要的包

当发现提示throw err; ^ Error: Cannot find module 'xxxx'时

说明并没有安装xxxx这个包

在命令行输入cnpm install xxxx 回车就可以下载所需要的包 

  1. var source_name = "中国新闻网";
  2. var myEncoding = "utf-8";
  3. var seedURL = 'http://www.chinanews.com/';

要爬取的网站 以及查看的此网站编码是utf-8 以及正则表达式。。

正则表达式是第一次接触到的概念,其实就是一种被用来检索、替换那些符合某个模式(规则)的文本

这里附上学习链接 正则表达式 – 语法 | 菜鸟教程

  1. var seedURL_format = "$('a')";
  2. var keywords_format = " $('meta[name=\"keywords\"]').eq(0).attr(\"content\")";
  3. var title_format = "$('title').text()";
  4. var date_format = "$('#pubtime_baidu').text()";
  5. var author_format = "$('#editor_baidu').text()";
  6. var content_format = "$('.left_zw').text()";
  7. var desc_format = " $('meta[name=\"description\"]').eq(0).attr(\"content\")";
  8. var source_format = "$('#source_baidu').text()";
  9. var url_reg = /\/(\d{4})\/(\d{2})-(\d{2})\/(\d{7}).shtml/;
  10. var regExp = /((\d{4}|\d{2})(\-|\/|\.)\d{1,2}\3\d{1,2})|(\d{4}年\d{1,2}月\d{1,2}日)/

这里是爬取的信息 关键词 作者 日期等 

  1. var headers = {
  2. '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'
  3. }

 防止网站屏蔽我们的爬虫 很多网站都反爬虫 这里需要伪装

  1. function request(url, callback) {
  2. var options = {
  3. url: url,
  4. encoding: null,
  5. headers: headers,
  6. timeout: 10000
  7. }
  8. myRequest(options, callback)
  9. }

构造模拟浏览器的request 爬下来的内容以浏览网址形式储存

  1. request(seedURL, function(err, res, body) { //读取种子页面
  2. // try {
  3. //用iconv转换编码
  4. var html = myIconv.decode(body, myEncoding);
  5. //console.log(html);
  6. //准备用cheerio解析html
  7. var $ = myCheerio.load(html, { decodeEntities: true });
  8. // } catch (e) { console.log('读种子页面并转码出错:' + e) };
  9. var seedurl_news;
  10. try {
  11. seedurl_news = eval(seedURL_format);
  12. //console.log(seedurl_news);
  13. } catch (e) { console.log('url列表所处的html块识别出错:' + e) };
  14. seedurl_news.each(function(i, e) { //遍历种子页面里所有的a链接var myURL = "";
  15. try {
  16. //得到具体新闻url
  17. var href = "";
  18. href = $(e).attr("href");
  19. if (typeof(href) == "undefined") { // 有些网页地址undefined
  20. return true;
  21. }
  22. if (href.toLowerCase().indexOf('http://') >= 0 || href.toLowerCase().indexOf('https://') >= 0) myURL = href; //http://开头的或者https://开头
  23. else if (href.startsWith('//')) myURL = 'http:' + href; 开头的
  24. else myURL = seedURL.substr(0, seedURL.lastIndexOf('/') + 1) + href; //其他
  25. } catch (e) { console.log('识别种子页面中的新闻链接出错:' + e) }
  26. if (!url_reg.test(myURL)) return; //检验是否符合新闻url的正则表达式
  27. //console.log(myURL);
  28. newsGet(myURL); //读取新闻页面
  29. });
  30. });

如果要爬取新闻内容的话 就必须读取种子页面 思路是解析种子页面的所有 a href 链接并遍历——规整化链接,符合新闻url的正则表达式的就爬取

  1. function newsGet(myURL) { //读取新闻页面
  2. request(myURL, function(err, res, body) { //读取新闻页面
  3. //try {
  4. var html_news = myIconv.decode(body, myEncoding); //用iconv转换编码
  5. //console.log(html_news);
  6. var $ = myCheerio.load(html_news, { decodeEntities: true });
  7. myhtml = html_news;
  8. //} catch (e) { console.log('读新闻页面并转码出错:' + e);};
  9. console.log("转码读取成功:" + myURL);
  10. var fetch = {};
  11. fetch.title = "";
  12. fetch.content = "";
  13. fetch.publish_date = (new Date()).toFormat("YYYY-MM-DD");
  14. //fetch.html = myhtml;
  15. fetch.url = myURL;
  16. fetch.source_name = source_name;
  17. fetch.source_encoding = myEncoding; //编码
  18. fetch.crawltime = new Date();

构建json对象准备写入文件并且建立一个空fetch以存储数据 这样可以将爬到的数据存储到构建的json文件中

  1. if (keywords_format == "") fetch.keywords = source_name; // eval(keywords_format); //没有关键词就用sourcename
  2. else fetch.keywords = eval(keywords_format);
  3. if (title_format == "") fetch.title = ""
  4. else fetch.title = eval(title_format); //标题
  5. if (date_format != "") fetch.publish_date = eval(date_format); //刊登日期
  6. console.log('date: ' + fetch.publish_date);
  7. console.log(myURL);
  8. fetch.publish_date = regExp.exec(fetch.publish_date)[0];
  9. fetch.publish_date = fetch.publish_date.replace('年', '-')
  10. fetch.publish_date = fetch.publish_date.replace('月', '-')
  11. fetch.publish_date = fetch.publish_date.replace('日', '')
  12. fetch.publish_date = new Date(fetch.publish_date).toFormat("YYYY-MM-DD");
  13. if (author_format == "") fetch.author = source_name; //eval(author_format); //作者
  14. else fetch.author = eval(author_format);
  15. if (content_format == "") fetch.content = "";
  16. else fetch.content = eval(content_format).replace("\r\n" + fetch.author, ""); //内容,是否要去掉作者信息自行决定
  17. if (source_format == "") fetch.source = fetch.source_name;
  18. else fetch.source = eval(source_format).replace("\r\n", ""); //来源
  19. if (desc_format == "") fetch.desc = fetch.title;
  20. else fetch.desc = eval(desc_format).replace("\r\n", ""); //摘要

需要爬取的内容标题 日期 作者 内容 来源 以及摘要

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

最后 将爬取的内容储存到fetch中并建立文件

到这里基本完成一个可以爬取新闻网页内容,并且存储的爬虫,下面来运行看结果

文件夹中出现很多的json文件 用记事本打开看一下内容 

得到了想到得到的内容 还不错 


三.使用数据库

第一次使用mysql,这也是我走最多弯路的地方,在官网安装完成后

完成一系列配置工作 可以参照MySQL 安装 | 菜鸟教程

可以在我的电脑——管理——服务中找到MySQL

在此过程中我也遇到很多问题:

比如 进行配置时一定要以管理员身份运行。

第一次登陆后会要求强制修改密码,好好记住自己的密码...... 

还有这种低级的...mysql写成mysqld...... 

记住实在不行就重启 net stop mysql 和net start mysql

ok 当你克服了种种困难终于进入了你的数据库 

因为要将数据存入数据库中,所以对刚才的代码进行修改

首先将存入json文件部分注释掉

  1. var mysql = require('./mysql.js');

加入所需要的模块

  1. var mysql = require("mysql");
  2. var pool = mysql.createPool({
  3. host: '127.0.0.1',
  4. user: 'root',
  5. password: 'root',//密码
  6. database: 'crawl'
  7. });
  8. var query = function(sql, sqlparam, callback) {
  9. pool.getConnection(function(err, conn) {
  10. if (err) {
  11. callback(err, null, null);
  12. } else {
  13. conn.query(sql, sqlparam, function(qerr, vals, fields) {
  14. conn.release(); //释放连接
  15. callback(qerr, vals, fields); //事件驱动回调
  16. });
  17. }
  18. });
  19. };
  20. var query_noparam = function(sql, callback) {
  21. pool.getConnection(function(err, conn) {
  22. if (err) {
  23. callback(err, null, null);
  24. } else {
  25. conn.query(sql, function(qerr, vals, fields) {
  26. conn.release(); //释放连接
  27. callback(qerr, vals, fields); //事件驱动回调
  28. });
  29. }
  30. });
  31. };
  32. exports.query = query;
  33. exports.query_noparam = query_noparam;

 mysql.js文件 其中数据库的用户名是root 密码为root 使用database名为crawl 当然这些东西可以自己设置

比如进入数据库后在命令提示符中使用create database xxx创建名为xxx的database 使用use xxx使用名为xxx的database等等操作......

当然这里我还是根据老师的来操作了

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

执行sql,数据库中fetch表里的url属性是unique的,不会把重复的url内容写入数据库

  1. mysql.query(fetchAddSql, fetchAddSql_Params, function(qerr, vals, fields) {
  2. if (qerr) {
  3. console.log(qerr);
  4. }

实现将内容写入到数据库中 

代码修改完成后进去数据库,借用老师的fetches代码,创建表格

创建完成后 运行程序

 进入数据库中 输入select url , title from fetches;(注意结尾要有分号)可以看到

爬取的内存存储到了数据库的表格中(这里可以下载navicat等数据库管理软件,嫌麻烦我并没有下....想要更加直观对数据库进行可视化可以尝试)

到这里就实现了将新闻网页内容进行爬取,并且存入数据库中。


四.查询网站

 1.前端

创建一个html文件,以实现输入要查询title而输出包含查询内容的新闻

  1. <!DOCTYPE html>
  2. <html>
  3. <body>
  4. <form action="http://127.0.0.1:8080/process_get" method="GET">
  5. <br> 标题:<input type="text" name="title">
  6. <input type="submit" value="Submit">
  7. </form>
  8. <script>
  9. </script>
  10. </body>
  11. </html>

2.后端

js代码如下:

  1. var express = require('express');
  2. var mysql = require('./mysql.js')
  3. var app = express();
  4. //app.use(express.static('public'));
  5. app.get('/7.03.html', function(req, res) {
  6. res.sendFile(__dirname + "/" + "7.03.html");
  7. })
  8. app.get('/7.04.html', function(req, res) {
  9. res.sendFile(__dirname + "/" + "7.04.html");
  10. })
  11. app.get('/process_get', function(req, res) {
  12. res.writeHead(200, { 'Content-Type': 'text/html;charset=utf-8' }); //设置res编码为utf-8
  13. //sql字符串和参数
  14. var fetchSql = "select url,source_name,title,author,publish_date from fetches where title like '%" +
  15. req.query.title + "%'";
  16. mysql.query(fetchSql, function(err, result, fields) {
  17. console.log(result);
  18. res.end(JSON.stringify(result));
  19. });
  20. })
  21. var server = app.listen(8080, function() {
  22. console.log("访问地址为 http://127.0.0.1:8080/7.03.html")
  23. })

code runner运行之后:

 在浏览器中打开网址后

在标题中输入要查询的内容,例如“赵立坚”

就可以看到含有“赵立坚”的新闻内容 


 五.拓展

在完成了老师的代码例子之后,开始自己寻找可以爬取的新闻网站进行爬虫操作,以及存入数据库

但是要注意对网站源代码进行分析 进行代码修改

爬取结束之后 打开数据库看一下

从另一个网站爬取了很多新闻 一共有了150条 数据库中多了很多内容 ok搞定 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/黑客灵魂/article/detail/848657
推荐阅读
相关标签
  

闽ICP备14008679号