c爬虫抓取网页数据(关于爬虫的知识后,你了解多少?(一) )

优采云 发布时间: 2022-02-05 00:04

  c爬虫抓取网页数据(关于爬虫的知识后,你了解多少?(一)

)

  如今,大前端理念已经深入人心,需要涉及的知识很多。所以,对于现在的前端来说,也是不可抗拒的。在修炼吸星大法时,尽可能多地吸收知识,最终达到物尽其用的效果。

  最近也在学习爬虫,因为之前项目中需要用到的地铁信息数据不是爬虫爬下来的数据,而是直接复制过来的。

  虽然这些数据暂时不会有太大变化,但感觉还是有点低。所以在了解了爬虫之后,打算和大家讨论交流,然后直接进入正题。

  首先说一下爬虫和Robots协议是什么

  然后介绍爬虫的基本流程

  最后根据实际栗子爬个豆瓣最近上映的电影来试试小刀

  2、爬虫和机器人协议

  首先看定义:爬虫是自动获取网页内容的程序。它是搜索引擎的重要组成部分,因此搜索引擎优化主要针对爬虫进行优化。

  下面我们来看看Robots协议的介绍。robots.txt 是文本文件,robots.txt 是协议,而不是命令。

  robots.txt 是爬虫要查看的第一个文件。robots.txt 告诉爬虫可以在服务器上查看哪些文件。爬虫机器人会根据文件内容确定访问范围。

  下图是豆瓣电影页面列出的robots协议的访问范围。

  

  爬虫和机器人协议密切相关。如果您看到不允许抓取的页面,请不要抓取它们。万一涉及到用户隐私的某些方面,稍后会被发现并带到合法渠道。

  因此,业内每个人都认可这个 Robots 协议。不想爬网页就别爬了,上网就可以安宁了。

  有点跑题了,我们看下面一张图,简单梳理一下上面提到的内容。

  

  其实有人会问,爬行动物到底在爬什么?

  这是一个非常有见地的问题。说白了就是爬虫拿到的那段html代码,所以这对我们来说并不陌生,只要我们把它转换成DOM树就行了。

  所以,现在看上图的右半部分,是一张对比图。

  左边的那个没有受限的机器人协议。从逻辑上讲,admin/private和tmp这三个文件夹是不能被抓到的,但是因为没有Robots协议,人就可以肆无忌惮的爬了。

  从右侧看,Robots 协议是有限的。相反,像谷歌这样的搜索引擎,也是通过 Robots.txt 文件来查看哪些是抓不到的,然后去 admin 或者 private 的时候直接跳过。去抢吧。

  好了,介绍到此为止。凡是不包括真刀真*敏*感*词*的,都只是纸上谈兵。

  3、爬虫基本流程

  其实对于爬虫的使用来说,过程无非就是这四个步骤。

  专用数据

  数据存储

  启动服务

  渲染数据

  专用数据

  现在到了激动人心的部分,不要停下来,跟着我,敲出一页爬豆瓣电影,供自己欣赏。

  我们先来看看整体的目录结构。

  

  既然是抓数据,就得用业界知名的神器——request

  请求工件

  那么如何使用request,我们一起听风看代码

  // 使用起来超简单let request = require('request');

request('http://www.baidu.com', function (error, response, body) { console.log('error:', error); // 当有错误发生时打印错误日志 console.log('statusCode:', response && response.statusCode); // 打印响应状态码 console.log('body:', body); // 打印百度页面的html代码});

  看了上面的代码,是不是还觉得不明显。小伙伴们,html代码已经出现在你们面前了,不要犹豫,只要把它变成熟悉的DOM,就可以为所欲为。

  于是,cheerio 出道,大家都称它为 Node 版的 jq。你可以完全按照jq的习惯来操作DOM。

  下面不再走弯路,一起来写爬虫吧!

  阅读内容

  首页应该先分析豆瓣电影的页面,也就是热映的电影,我们先来看看DOM结构。

  

  好了,读完噻吩后,我们需要的内容也标注出来了,然后进入read.js文件,一步步开始舔。

  // read.js文件

// request-promise是让request支持了promise的语法,可以说是request的小弟const rp = require('request-promise');// 将抓取页面的html代码转为DOM,可以称之为是node版的jqconst cheerio = require('cheerio');// 这个是为了在调试时查看日志const debug = require('debug')('movie:read');

// 读取页面的方法,重点来了const read = async (url) => { debug('开始读取最近上映的电影');

const opts = { url, // 目标页面 transform: body => { // body为目标页面抓取到的html代码 // 通过cheerio.load方法可以把html代码转换成可以操作的DOM结构 return cheerio.load(body); } };

return rp(opts).then($ => { let result = []; // 结果数组 // 遍历这些热映电影的li $('#screening li.ui-slide-item').each((index, item) => { let ele = $(item); let name = ele.data('title'); let score = ele.data('rate') || '暂无评分'; let href = ele.find('.poster a').attr('href'); let image = ele.find('img').attr('src'); // 影片id可以从影片href中获取到 let id = href && href.match(/(\d+)/)[1]; // 为了防止豆瓣防盗链导致裂图,换成webp格式加载图片 image = image && image.replace(/jpg$/, 'webp');

if (!name || !image || !href) { return; }

result.push({ name, score, href, image, id }); debug(`正在读取电影:${name}`); }); // 返回结果数组 return result; });};// 导出方法module.exports = read;

  写完代码,让我们回忆一下你做了什么。

  4、数据存储

  这里我们使用mysql建一个数据库来存储数据,不懂的没关系,我先一步一步来。我们首先安装 XAMPP 和 Navicat 可视化数据库管理工具,安装完成后,按照下面的说明进行操作。

  XAMPP启动mysql

  

  Navicat 连接数据库并创建表

  几句话可能不像有图有真相那么真实。我们先来看看图片。

  

  

  

  

  

  

  嗯,看图的时代到此结束。我真的很惭愧消耗了大量的流量。现在让我们回到编码阶段。

  连接到数据库

  首先,我们需要在 src 目录下创建一个 sql 文件。它需要和我们刚刚创建的数据库同名,所以我们称之为my_movie.sql(当然目录结构已经创建好了)

  然后,回到 db.js 文件,编写连接数据库的代码

  // db.js

const mysql = require('mysql');const bluebird = require('bluebird');

// 创建连接const connection = mysql.createConnection({ host: 'localhost', // host port: 3306, // 端口号默认3306 database: 'my_movie', // 对应的数据库 user: 'root', password: ''});

connection.connect(); // 连接数据库

// bluebird是为了方便支持promise语法化// 然后直接把数据库的query查询语句导出方便之后调用module.exports = bluebird.promisify(connection.query).bind(connection);

  上面的代码已经创建了连接Mysql数据库的操作。接下来,不要放慢速度,将内容直接写入数据库。

  写入数据库

  这时候我们来看看write.js这个文件。是的,顾名思义,就是用来写数据库的,直接上代码

  // write.js文件

// 从db.js那里导入query方法const query = require('./db');const debug = require('debug')('movie:write');// 写入数据库的方法const write = async (movies) => { debug('开始写入电影');

// movies即为read.js读取出来的结果数组 for (let movie of movies) { // 通过query方法去查询一下是不是已经在数据库里存过了 let oldMovie = await query('SELECT * FROM movies WHERE id=? LIMIT 1', [movie.id]);

// sql查询语句返回的是一个数组,如果不为空数组的话就表示有数据存过 // 直接就进行更新操作了 if (Array.isArray(oldMovie) && oldMovie.length) { // 更新movies表里的数据 let old = oldMovie[0]; await query('UPDATE movies SET name=?,href=?,image=?,score=? WHERE id=?', [movie.name, movie.href, movie.image, movie.score, old.id]); } else { // 插入内容到movies表 await query('INSERT INTO movies(id,name,href,image,score) VALUES(?,?,?,?,?)', [movie.id, movie.name, movie.href, movie.image, movie.score]); }

debug(`正在写入电影:${movie.name}`); }};

module.exports = write;

  上面写的可能有点混乱,毕竟纯前端很少写SQL语句。不过不要害羞,我先把上面的代码整理好之后再简单介绍一下SQL语句部分。

  write.js 到底写了什么?

  好了,上面也实现了写入数据库的方法。接下来,趁热打铁,稍微聊聊SQL语句。

  SQL语句学习

  ? 表示占位符。顺便说一下,我将简要介绍将在 SQL 语句中使用的语法,以及无处不在的增删改查。

  插入数据

  语法: INSERT INTO 表名(列名) VALUES(列名值)栗子: INSERT INTO tags(name,id,url) VALUES('爬虫',10,'https://news.so.com/hotnews')解释: 向标签表(tags)里插入一条,姓名,id和访问地址分别为VALUES内对应的值

  更新数据

  语法: UPDATE 表名 SET 列名=更新值 WHERE 更新条件栗子: UPDATE articles SET title='你好,世界',content='世界没你想的那么糟!' WHERE id=1解释: 更新id为1的文章,标题和内容都进行了修改

  删除数据

  语法: DELETE FROM 表名 WHERE 删除条件栗子: DELETE FROM tags WHERE id=11解释: 从标签表(tags)里删除id为11的数据

  查询

  语法: SELECT 列名 FROM 表名 WHERE 查询条件 ORDER BY 排序列名栗子: SELECT name,title,content FROM tags WHERE id=8解释: 查询id为8的标签表里对应信息

  至此,我已经把所有的读写方法都写完了,所以大家一定是有点累了。是时候测试结果了,否则都是废话

  5、执行读写操作

  现在来到 index.js 并开始检查它。

  // index.js文件

const read = require('./read');const write = require('./write');const url = 'https://movie.douban.com'; // 目标页面

(async () => { // 异步抓取目标页面 const movies = await read(url); // 写入数据到数据库 await write(movies); // 完毕后退出程序 process.exit();})();

  完了,执行一下看看效果如何,直接上图

  

  代码已执行。接下来回到Navicat,看看数据是否已经写入。我们用图片来说话。

  

  至此,我们已经完成了数据采集和存储操作,但似乎还缺少什么?

  也就是我们需要写一个页面来展示它,因为爬取和写数据只允许在node环境下进行。所以我们还要创建一个web服务来显示页面,坚持下去很快就OK了,加油。

  6、启动服务

  既然我们要创建一个 web 服务,让我们开始编写 server.js 的内容

  服务器服务

  // server.js文件

const express = require('express');const path = require('path');const query = require('../src/db');const app = express();

// 设置模板引擎app.set('view engine', 'html');app.set('views', path.join(__dirname, 'views'));app.engine('html', require('ejs').__express);

// 首页路由app.get('/', async (req, res) => { // 通过SQL查询语句拿到库里的movies表数据 const movies = await query('SELECT * FROM movies'); // 渲染首页模板并把movies数据传过去 res.render('index', { movies });});// *敏*感*词*localhost:9000端口app.listen(9000);

  写完服务端服务,我们再来看看 index.html 模板。这是最后一件事。写完,就大功告成了。

  7、渲染数据

  // index.html

热映的电影 正在热映的电影 %=movie.image% <p class="score">评分: </a>

</p>

  通过模板引擎遍历movies数组,然后渲染

  现在,看看最终效果

  

  和你一起来到这里是缘分。我很高兴经历了这么长时间的文章 学习。每个人都应该对爬行动物的知识有一个很好的了解。

  对了,这里是代码地址:爬虫研究/电影

  为了您的方便,敲敲敲。

  感谢阅读,886。

  

  

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线