爬虫菜鸟试水

写爬虫好难...头发掉了好几把...好在最后终于算是懂了个大概...吧。

在这里以NBA中国官方网站为例。

1.首先是对目标网站的分析过程:

打开NBA网站,单击右键查看网页源代码。会跳出这样一个页面:

看上去很恶心,但往下拖,认真看,找想爬的文章。比如我想爬这一些看起来就方方整整的标题和文章:

那具体怎么操作呢?

这些文章的标题都在一系列标签之间,对我们爬虫爬取文章有影响的标签从内到外分别是<a></a>,<li></li>,<ul></ul>三种。那我们就从这里找出了待会要写的代码的循环层数是三层。

爬虫不可缺少的除了标题,还有内容和时间,还可以带上来源使文章更具说服力。因此,我想还从网页源代码里找到这些东西,那就抓一篇文章来分析它的时间、来源和内容在源代码里是怎么表示的。

就让我点开《单月85记三分创史 库里:我是当世最强射手》这篇文章,可以一眼看到时间和来源就在标题下面。先把它复制下来。

查看这一页面的源代码,在键盘上按Ctrl+F,将刚刚复制的时间和来源分别输入,以时间为例:

有两个结果,另一个显然是作为文本输出的就不用管它。找到这个有标签的,那么此后时间都将从”span.article-time"找了。先记下这个class。来源和内容的查找也是同理。这就是大致的目标网站分析。

2、爬虫整体结构,使用的工具包:

不太会讲,先丢爬虫代码吧,也就是我写的爬取NBA网站的爬虫整体结构:

'use strict';
var cheerio = require('cheerio');
var fs = require('fs');
var request = require('request');
var iconv = require('iconv-lite');

var Title = [];
var Source = [];
var Time = [];
var Content = [];
var Url = [];

request({url: "https://china.nba.com/", encoding: null, headers: null }, function(err, res, body){
    if(err || res.statusCode !=200){
        console.error(err);
        console.error(res.statusCode);
        return;
    }
    let $ = cheerio.load(iconv.decode(body, 'gbk'));

    let cnt = 0;
    let ulArr = $("ul.text-news").eq(cnt);
    while(ulArr.text()){
        let cnt1 = 0;
        let liArr = ulArr.children("li").eq(cnt1);
        while(liArr.text()){
            let cnt2 = 0;
            let aArr = liArr.children("a").eq(cnt2);
            while(aArr.text()){
                let urlstr = aArr.attr("href");
                let title = aArr.text();
                if(urlstr && title){
                    console.log(`${title}`);
                    request({ url: urlstr, encoding: null, headers: null }, function (err,res,body){
                        if(err || res.statusCode != 200){
                            console.error(err);
                            console.error(res.statusCode);
                            return;
                        }
                        let $ = cheerio.load(iconv.decode(body, 'gbk'));
                        Title.push($("title").text());
                        Time.push($("span.article-time").text());
                        Source.push($("span.color-a-1").text());
                        Content.push($("div#Cnt-Main-Article-QQ").text());
                        Url.push(res.request.uri.href);
                        console.log(`${$("title").text()}`)
                    });
                }
                cnt2++;
                aArr = liArr.children("a").eq(cnt2);
            }
            cnt1++;
            liArr = ulArr.children("li").eq(cnt1);
        }
     cnt++;
        ulArr = $("ul.text-news").eq(cnt);
    }
});

setTimeout(function(){
    for(let i in Url){
        fs.writeFileSync("NBA/" + i + ".txt", `URL: ${Url[i]}\nTitle: ${Title[i]}\nSource: ${Source[i]}\nContent: ${Content[i]}\nTime: ${Time[i]}`);
    }
},5000);

以下是使用的工具包,要爬之前要把这四个都npm install一遍:

这是定义的数组,为了储存爬到的数据:

这是判断能不能爬或爬的网站对不对的请求操作,对就进去,不对返回:

这是个报错版块:

接下来就是本爬虫最核心的部分,其实也是三大循环,回到前面看,会发现其实这就是之前讲到的三个标签<ul><li><a>:

    let cnt = 0;
    let ulArr = $("ul.text-news").eq(cnt);
    while(ulArr.text()){
        let cnt1 = 0;
        let liArr = ulArr.children("li").eq(cnt1);
        while(liArr.text()){
            let cnt2 = 0;
            let aArr = liArr.children("a").eq(cnt2);
            while(aArr.text()){
                let urlstr = aArr.attr("href");
                let title = aArr.text();
                if(urlstr && title){
                    console.log(`${title}`);
                    request({ url: urlstr, encoding: null, headers: null }, function (err,res,body){
                        if(err || res.statusCode != 200){
                            console.error(err);
                            console.error(res.statusCode);
                            return;
                        }
                        let $ = cheerio.load(iconv.decode(body, 'gbk'));
                        Title.push($("title").text());
                        Time.push($("span.article-time").text());
                        Source.push($("span.color-a-1").text());
                        Content.push($("div#Cnt-Main-Article-QQ").text());
                        Url.push(res.request.uri.href);
                        console.log(`${$("title").text()}`)
                    });
                }
                cnt2++;
                aArr = liArr.children("a").eq(cnt2);
            }
            cnt1++;
            liArr = ulArr.children("li").eq(cnt1);
        }
     cnt++;
        ulArr = $("ul.text-news").eq(cnt);
    }
});

循环的大概意思是找到第cnt个<ul class="text-news">存在ulArr里,class用.替换。
如果ulArr的文本里是有东西的,我们就将进下一层循环。
找到第cnt1个ulArr的子标签<li>存为liArr。
如果liArr的文本里有东西,我们又进下一层。
找到第cnt2个liArr的子标签<a>存为aArr后就不能再进循环了,进二级页面,将需要一个网址。

href就是我要的网址,下面的语句会自行把网址导入爬虫:

最后一段是爬虫爬取结果的输出,我将爬取内容存到了叫NBA的文件中:

其实对于三层循环的爬虫来说,整个框架中白色部分的内容基本是不变的,要改的内容几乎就是显示绿色的东西,通过修改它们可以爬一些普通的你想要爬的不同网址不同文章。

大概就是这些了,我可能讲不太清楚,剩下的自求多福吧...

2.数据库设计:

由于对mysql ptsd了,将爬取内容存入数据库我用的是另一个软件,长这样:

进去后要新建表,预备把你要爬的东西存进去。一顿操作后,我弄了一个叫news的表要存数据,右键点击“设计表”,把我们要的几项如URL,Title,Time,Content,Source都打进去,还要修改表的各项属性,此处太多就不一一截图了。

表弄好之后,接下来就要把VScode里的爬取内容导入表中。我们要修改一下之前的代码,因为之前的代码是把爬取内容存进文件夹的,现在要让它们入库。以下是修改过的代码:

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

var Title = [];
var Source = [];
var Time = [];
var Content = [];
var Url = [];

request({url: "https://china.nba.com/", encoding: null, headers: null }, function(err, res, body){
    if(err || res.statusCode !=200){
        console.error(err);
        console.error(res.statusCode);
        return;
    }
    let $ = cheerio.load(iconv.decode(body, 'gbk'));

    let cnt = 0;
    let ulArr = $("ul.text-news").eq(cnt);
    while(ulArr.text()){
        let cnt1 = 0;
        let liArr = ulArr.children("li").eq(cnt1);
        while(liArr.text()){
            let cnt2 = 0;
            let aArr = liArr.children("a").eq(cnt2);
            while(aArr.text()){
                let urlstr = aArr.attr("href");
                let title = aArr.text();
                if(urlstr && title){
                    console.log(`爬取${title}`);
                    request({ url: urlstr, encoding: null, headers: null }, function (err,res,body){
                        if(err || res.statusCode != 200){
                            console.error(err);
                            console.error(res.statusCode);
                            return;
                        }
                        let $ = cheerio.load(iconv.decode(body, 'gbk'));

                        database.query('INSERT INTO news(URL, Title, Time, Content, Source) VALUES(?, ?, ?, ?, ?);', [
                            res.request.uri.href,
                            $("title").text(),
                            $("span.article-time").text(),
                            $("div#Cnt-Main-Article-QQ").text(),
                            $("span.color-a-1").text()
                        ], function (err, vals, fields) {
                            if (err) {
                                console.error(`数据库错误:${err}`);
                            }
                            console.log(`完成爬取${$("title").text()}`);
                        });
                    });
                }
                cnt2++;
                aArr = liArr.children("a").eq(cnt2);
            }
            cnt1++;
            liArr = ulArr.children("li").eq(cnt1);
        }
        cnt++;
        ulArr = $("ul.text-news").eq(cnt);
    }
});

其实也就是中间的输出部分做了些调整,其他大致上一样。运行成功后,爬取数据就被写入数据库了。以下是写入数据库的效果:

3.搜索网站前后端:

为了搜索爬取内容的关键字,还要建一个搜索网站,先展示一下我设计的搜索网站:

要设计这样一个网站需要写前后端。前段设计搜索网站的显示方式,也就是通过写前端告诉电脑你想要的搜索网站要长什么样。我通过HTML写,以下是我的代码(index.html):

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=1900">
    <title>查询NBA网页具体信息</title>
</head>

<body background="NBA1.jpg"
      style="background-repeat:no-repeat;
      background-size:100% 100%;
      filter:alpha(opacity=10);
      background-attachment:fixed;">
    <form action="/" method="GET">
        <p style="background-color:rgba(146, 127, 127, 0.5);">请输入关键词 <input name="kw" type="text" style="width: 640px" /><input type="submit" value="Search" /></p>
    </form>
    <table border="1" id="news">
        <caption style="font-size: 24px;font-weight:700">News</caption>
        <tr>
            <th>Title</th>
            <th>Time</th>
            <th>Content</th>
            <th>Source</th>
        </tr>
    </table>

</body>
</html>

单写前端还不够,还要写后端将要呈现的内容连接到前端去。后端还是通过js写(serve1.js):

'use strict';
var express = require('express');
var cheerio = require('cheerio');
var fs = require('fs');
var database = require('./mysql.js');
var port = process.env.PORT || 1337;

var server = express();
server.use(express.static("public"));

server.get('/', function (req, res) {
    res.writeHead(200, { 'Content-Type': 'text/html' });

    let AdditionSQL = "";

    var html = fs.readFileSync("index.html");
    let $ = cheerio.load(html);

    if (req.query.kw) {
        AdditionSQL = ` WHERE (Title LIKE '%${req.query.kw}%') OR  (Content LIKE '%${req.query.kw}%')`;
    }

    database.query_noparam('SELECT * FROM news' + AdditionSQL + ';', function(qerr, vals, fields) {
        if (qerr) {
            console.error(qerr);
            return;
        }
        for (let i in vals) {
            $('table#news').append(`<tr>
    <td><a href=${vals[i].URL}>${vals[i].Title}</ a></td>
    <td>${vals[i].Time}</td>
    <td>${vals[i].Content}</td>
    <td>${vals[i].Source}</td>  
</tr>`);
        }

            res.end($.html());
        });
    
});

server.listen(port);

运行serve1.js文件,在浏览器搜索框输入127.0.0.1:1337,就会跳出刚刚我们设计的搜索网站,实现爬虫爬取内容的搜索。

总的爬虫大概就是这样。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值