爬虫经历分享——完整版

爬虫经历分享
老师的要求如下在这里插入图片描述

1.找网页
新闻链接:https://sports.sina.com.cn
新浪体育
新浪体育
新浪体育
永远的神!!!!!
为什么选某浪网页——当然是多次尝试的结果,使着爬了很多个网页,但好多爬下来不是有问题就是中文乱码,气死,只有这个某浪网页,非常nice!!!!

2.读取种子页面
应该也可以解释为读取它的源代码吧,我按照老师说的点击右键,选择查看网页源代码,但是Mac操作不是这样!
你要——以下来自百度百科
1.首先打开safari浏览器,点击上方的菜单栏,选择“偏好设置”选项。
2.然后在弹出来的窗口中,选择 “高级”页签,勾选 “在菜单栏里显示开发菜单”。
3.此时回到要查看源码的页面,点击上方的开发选项菜单,点击显示页面源文件,显示页面资源,显示错误控制台三项即可。
4.此时回到网页中,即可看到下方显示的当前网页源码了。

打开后源代码差不多长这样然后我也不咋看得懂(到后期就差不多可以看懂了),然后进行下一步——the next one!

3.分析出种子页面里所有的新闻链接
(说实话,刚开始的时候,这句话我就不太懂老师要我们干什么了)
分析出种子页面的新闻链接,也就是爬取出所有的a链接
一开始我也看不太懂老师的代码,但在网上看了一些爬虫的视频和代码,又跑了跑老师给的代码也就差不多有了初步的了解。
然后就尝试开始自己写代码,跟老师不同的是,我是引入了http库的request函数来写,这表示我的作业有着自己的思想哈哈哈,但其实本质上也差不多…
先引入包

const https = require ('https')
const cheerio = require ('cheerio')

再向网页发送请求

//引入http模块
var myurl = 'https://sports.sina.com.cn'
//创建请求对象
var req = https.request(myurl,res => {
    let chunks =[]//因为chunk很多,所以用chunks接受一下
    //data事件就是有数据传过来了,有数据响应了,然后用chunk接收一下
    res.on('data',chunk => chunks.push(chunk))
    //end的时候说明所有数据传输完毕,这个时候可以来一个回调
    res.on('end',()=>{
        //拼接成一个完整的数据流,再转换为html代码
        let htmlstr = Buffer.concat(chunks).toString('utf-8')
        //console.log(htmlstr)
        var all=[]
        let  $ = cheerio.load(htmlstr)//用cheerio解析整个网页,$对象就等于我们的解块对象
        $('a').each((index,item) =>{
            //each函数进行遍历
            //console.log( $(item).attr('href'))
            all.push( $(item).attr('href'))
        })
       console.log(all)
    })
})
//请求发送出去
req.end()

运行结果如下:
在这里插入图片描述

感觉自己是完成了第一步,这样运行后的结果就是打印出了新浪体育网所有a链接,但是但是后面遇到的问题真的是各种各样!!!!!!!

根据现在我们打印出的结果可以看出,有一些网页是不规范的,所以我们需要写一段代码,使其输出格式规范
代码如下:

 if (typeof(mine) == "undefined") return true;
 if (mine.toLowerCase().indexOf('http://') >= 0 || mine.toLowerCase().indexOf('https://') >= 0) mine = mine; //http://开头的或者https://开头
 else if (mine.startsWith('//')) mine = 'http:' + mine ; 开头的
 else mine = myurl.substr(0, myurl.lastIndexOf('/') ) + mine; //其他

4.开始正式爬取内容(完整代码见1.js)
然后接下来根据自己要爬取的内容来写变量,老师有给例子说明
也是先引入所需模块

//引入http模块
const https = require ('https')
const http = require ('http')
const cheerio = require ('cheerio')
const fs = require ('fs')
require('date-utils');

var myurl = 'https://sports.sina.com.cn'//创建请求对象

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 = "$('meta[property=\"article:author\"]').eq(0).attr(\"content\")";
var desc_format = " $('meta[name=\"description\"]').eq(0).attr(\"content\")";
var url_reg =/\/.+\/\d{4}-\d{2}-\d{2}\/.+[.]shtml/;
var source_name ='新浪新闻网'
var myEncoding = "utf-8";

防止网站屏蔽我们的爬虫

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'
}

一开始我each每一个‘a’链接,然后就直接开始进行有关数据库的操作,但我发现这样,每次爬取的信息都是一样的!!都是新浪体育总页面,归结原因为:一直拿到的是首页内容是因为你只访问了首页的url,没有访问其他链接。所以现在需要引入一个newget函数来继续访问其他链接再进行文件操作。

但是问题又来了直接对访问到的链接进行newget函数,直接报错
心态崩掉,呜呜呜~

后来经过高人指点哈哈哈哈发现:因为我们所爬取到的‘a’链接有些是’http‘开头,有些是‘https开头,所以就需要分类写来,听起来很复杂,但是写好一个newget函数后,另一个复制后改一改就好啦

分类如下:在这里插入图片描述
newget函数如下:

function newget(mine)
{
    var req = http.request(mine,res => 
        {
        var chunks =[]//因为chunk很多,所以用chunks接受一下
        //data事件就是有数据传过来了,有数据响应了,然后用chunk接收一下
        res.on('data',chunk => chunks.push(chunk))
        //end的时候说明所有数据传输完毕,这个时候可以来一个回调
        res.on('end',()=>{
            //拼接成一个完整的数据流,再转换为html代码
            var htmlstr = Buffer.concat(chunks).toString('utf-8')
            //console.log(htmlstr)
            var  $ = cheerio.load(htmlstr)//用cheerio解析整个网页,$对象就等于我们的解块对象
           
            var fetch = {};
            fetch.title = "";
            fetch.content="";
            fetch.keywords = "";
            fetch.date = "";
            fetch.author = "";
            fetch.Myurl=myurl;
            fetch.url=mine;
            fetch.source_name = source_name;
            fetch.source_encoding = myEncoding;
            fetch.crawltime=new Date();
        
            console.log('转码成功:'+fetch.url)  

            if (keywords_format == "") fetch.keywords =""; // 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); //刊登日期   
            
            if (author_format == "") fetch.author = source_name; //eval(author_format);  //作者
            else fetch.author = eval(author_format);
    
            if (desc_format == "") fetch.content = "";
            else fetch.content = eval(desc_format);
    
            var filename = source_name + "_" + (new Date()).valueOf()+"_" + ".json";
            fs.writeFileSync(filename, JSON.stringify(fetch));
        })
    })
    req.end()//请求发出去  
}

newget2函数就只需要把newget函数开始的http改为https就好啦

然后开始运行!!!!
成功!!(其实在这个爬虫过程经历居多失败,各种报错,这里就不一一展示了)
运行结果如下:
在这里插入图片描述
在这里插入图片描述
给爷激动死了!!!!

5.创建并使用数据库
在终端输入/usr/local/MySQL/bin/mysql -u root -p进入mysql
然后输入密码
再输入
create database crawl;
use crawl;(一定注意句末+分号,不然就会错很多次)

6.存入数据库(完整代码见2.js)
先根据自己需求创建表(fetches代码)创建成功后,再稍微修改了下数据库的代码
但是运行代码之后
果不其然
报错了😭😭😭😭😭
在这里插入图片描述
有问题,解决!!!
然后
报错原因说明我的插入语句有问题
我写了8个‘?’
但是我要插入的是7个字段
于是改!!!!
新鲜代码出炉

//var filename = source_name + "_" + (new Date()).valueOf()+"_" + ".json";
//fs.writeFileSync(filename, JSON.stringify(fetch));
var fetchAddSql = 'INSERT INTO fetches(url,source_name,source_encoding,title,' +'keywords,author,crawltime,content) VALUES(?,?,?,?,?,?,?,?)';
var fetchAddSql_Params = [fetch.url, fetch.source_name, fetch.source_encoding,fetch.title, fetch.keywords, fetch.author,fetch.crawltime, fetch.content];
mysql.query(fetchAddSql, fetchAddSql_Params, function(qerr, vals, fields) {
            if (qerr) {
                console.log(qerr);
            }
});

成功
查看下fetches里面的author, title;
select author, title,url from fetches;
在这里插入图片描述太激动了!!!!!

看看新闻网
和上述过程相同,爬取其他网友内容也差不多如此(完整代码见7.j s)
下面来爬取——看看新闻网——‘http://www.kankanews.com/’
因为开头为http开头
所有对于2.js的代码修改如下:
1.对网页的请求改为http库的request函数
2.修改变量

var keywords_format = " $('meta[name=\"Keywords\"]').eq(0).attr(\"content\")";
var title_format = "$('title').text()";
var date_format = "$('.time').text()";
var author_format = "$('.resource').text()";
var desc_format = " $('meta[name=\"Description\"]').eq(0).attr(\"content\")";
var source_name ='看看新闻网'
var url_reg = /a\/(\d{4})-(\d{2})-(\d{2})\/(\d{10}).shtml/;
var myEncoding = "utf-8";

运行结果:
在这里插入图片描述
也就成功了

搜狐
同理也是修改变量
完整见6.js

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 url_reg = /\/a\/(\d{9})\_/;//用于匹配主页面中的新闻子页面的正则表达式

结果
在这里插入图片描述

7.用mysql查看自己爬取到的数据
然后接下来操作主要是针对新浪体育
试了一下查询NBA
结果乐观
在这里插入图片描述

8.用网页发送请求到后段查询
先创建一个前端(文件4.html)
注意:要用英文!否则会乱码:(其实也可以在开头加
<meta charset="utf-8" />,将代码都转换成——utf-8)
在这里插入图片描述
就会像这样乱码

然后再创建一个后端(文件4)

运行后查询结果如下:
在这里插入图片描述
9.用express构建网站访问mysql

同样先创建前端(注意用英文)(见5.html)
在这里插入图片描述
再创建后端文件5.js
`
结果如下:
在这里插入图片描述
10.用express脚手架来创建网络框架
好家伙按老师那样来,一直报错,说:“command not find express"
然后求助大佬,反正就是express路径不对
于是解决后的方法就是:
先手动创建一个文件叫“e_1”
然后新建位于文件夹的终端窗口
在终端输入 express -e
在这里插入图片描述

就可以了

在这里插入图片描述
再输入npm install mysql --save将mysql包安装到项目中,并将依赖项保存进package.json
再输入npm install将package.json中列举的依赖项全部安装,完成网站搭建
在这里插入图片描述
之后,在routes目录下修改index.js
然后,在e_1/public/下创建一个search.html
但是
报错报错还是报错!我根本在页面就查询不了
解决不了
找助教——发现问题——解决问题
首先是index.js里面,写的sql语句有个小问题是authorfrom,这两个连在一起了导致无法正常查询数据库
修改!主要问题还是在index.js里的process_get
方法:在search.html里面对执行回车操作在form里加了个action,让它跳转到index.js的/process_get来处理
代码新鲜出炉
index修改

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

/* GET home page. */
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 " +
        "from fetches where title like '%" + request.query.title + "%'";
    console.log(request.query.title);
    mysql.query(fetchSql, function(err, result, fields) {
        response.writeHead(200, {
            "Content-Type": "application/json"
        });
        if(err){
            console.log(err);
            return;
        }
        console.log(result);
        response.write(JSON.stringify(result));
        response.end();
    });
});
module.exports = router;

search修改

<!DOCTYPE html>
<html>
<header>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</header>

<body>
    <form action="/process_get">
        <br> 标题:<input type="text" name="title">
        <input class="form-submit" type="button" value="查询">
    </form>
    <div class="cardLayout" style="margin: 10px 0px">
        <table width="100%" id="record2"></table>
        <tr class="cardLayout"><td>url</td><td>source_name</td><td>title</td><td>author</td><td>publish_date</td></tr>
    </div>
    <script>
        $(document).ready(function() {
            $("input:button").click(function() {
                $.get('/process_get?title=' + $("input:text").val(), function(data) {
                    $("#record2").empty();
                    $("#record2").append('<tr class="cardLayout"><td>url</td><td>source_name</td>' +
                        '<td>title</td><td>author</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>

然后在终端输入:node ./bin/www
这个跟老师输入得不太一样
得看自己目录下的是什么
然后用chrome浏览器打开http://127.0.0.1:3000/search.html
一定一定要记得加端口名
否则就会像我一样一直打不开
结果如下:在这里插入图片描述
输入NBA:
在这里插入图片描述

这就完了吗?
不没有!
好家伙,我今天又跑了下之前的代码,然后我发现5.j s跑不了了,太伤心了,一直报错说Error: Cannot find module ‘express’,一直无法解决,然后经过指点后发现:
在这里插入图片描述
我的5.js所在的目录下没有node_modules这个文件夹,也就是没有存放其他的模块,所以一直报错,解决方法:在其他地方找到node_modules这个文件夹后,copy到5.js所在文件,再运行就好了!

11.进一步使我们网页更美观
1.再次对index.js和search.html进行修改
修改如下:
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 " +
        "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] + "%'";
        }
    mysql.query(fetchSql, function(err, result, fields) {
        response.writeHead(200, {
            "Content-Type": "application/json"
        });
        response.write(JSON.stringify(result));
        response.end(); ``
    });
});
module.exports = router;

修改一,增加了搜索参数author
修改二,由于title大多数较长,可改成多关键词查询

search.html修改

<!DOCTYPE html>
<html>
<header>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
</header>
<head>
    <style>
        .cardLayout{
            border:rgb(224, 23, 117) solid 10px;
            margin: 5px 0px;
        }
        tr{
            border: solid 3px;
        }
        td{
            border:solid 3px;
        }
    </style>
</head>
<body background="background.jpeg"
     style="background-repeat:no-repeat;
     background-size:100% 100%;
     background-attachment: fixed;">
    <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>

修改主要是增加了一段style,使页面更好看(最近好喜欢玫红色哈哈哈哈)
然后对body加了一段代码

<body background="background.jpeg"
     style="background-repeat:no-repeat;
     background-size:100% 100%;
     background-attachment: fixed;">

也就是这样:
在这里插入图片描述

多关键词搜索
在这里插入图片描述

然后重点来了!!!!!
进行分页操作!!!!——因为一页实在是太多了(完整代码见search.html)
这一步都是跟着别人学的(参考:https://blog.csdn.net/qq_38071755/article/details/81944359
1.第一步:对html文件进行微调:先在原先基础上引入bootstrap包
主要就是要引入bootstrap包!!!!!

<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(224, 23, 117) solid 10px;
            margin: 5px 0px;
        }
        tr{
            border: solid 2px;
        }
        td{
            border:solid 2px;
        }
    </style>
</head>

2.第二步:紧接着修改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:'作者'
                    }],
                    data: data,
                    });
                });
            });
        });
    </script>

成果展示:
搜索🔍某一个关键词后,可以分页展示,并且显示相关话题的总条数
在这里插入图片描述

学习分页成功

啊啊啊啊啊救命,老师突然发了要求,我发现我没有对热度进行分析,于是我准备加一个词云,但是我就不会用python写,这远远超过了我的能力范围,就只好运用一些现有的工具,在这里我就用了Word Art这个工具来搞
在这里插入图片描述
词云搞好之后,就要想办法在前端显示
于是我在search中又加了一段代码

        <br/>
        <a href="/e_4/public/Word Cloud.png"><input type = "button" value="Word Cloud"></a>
        <br />

于是前端就有了Word Cloud 的按钮🔘
在这里插入图片描述
点击后就可以看见我的词云图片了
在这里插入图片描述
啊啊啊啊啊,终于结束了,感觉自己被掏空
完结——撒花🎉🎉🎉

12.总结
真的太不容易了,一开始对js,html的各种语法都不懂,上网各种乱看,摸不着头脑,后来发现还是自己动手实操最有用,跟着老师的代码一步一步跑,有什么问题通过问老师,问助教,问大佬解决,期间也遇到了很多困难,各种报错,在一开始选取爬取网站就经历了很多挫折,找到全是“utf-8”的真不容易,在最后一步分页操作我觉得也很难,期间试了很多种写法一直不可以,最后是在网上看见了一篇教程,一步步跟着写,最后就可以了。以上就是第一次的爬虫经历,希望之后可以越来越好!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值