从零开始的Node.js新闻爬虫实验项目(四)东方财富网、网易新闻、Pixiv的爬取思路
这是计划的第3步
有了前篇雪球网新闻的爬取代码,可以同样的爬取其他各类网站
1)东方财富网
1、一级页面
在这里,选择信息较为集中,内容丰富的“右边部分”开始分析。
观察到每一条消息均在各自的 li 项下的 a 中,于是主体部分非常好写
var item = $('.nlist', 'div').find('li').children('a')item.map(function (idx, element) {var news = {};news.title = $(element).text();news.link = $(element).attr('href');console.log(news);})
输出非常漂亮
2、二级页面
可以看到,我们感兴趣的内容均在class=“newsContent”下,可以分类爬取信息,爬取二级地址内容的代码如下:
rp(options).then(function ($) {var item = $('.newsContent', 'div');news.time = item.find('.time', 'div').first().text();news.editor = item.find('.author', 'div').first().text();news.source = item.find('.source', 'div').text();var source = news.source;news.source = source.replace(/\s*/g, '');news.comment = item.find('.num', 'span').text();news.contain = item.find('.b-review', 'div').text();var maintext = '';$('.newsContent', 'div').find('.Body', 'div').children('p').each(function (idx, element) {maintext = maintext.concat($(element).text());})news['texts'] = maintext;console.log(news);
})
绝大部分网页可以正确爬取,部分网页链接至其他网站,故html结构有所不同,不做考虑。
2)网易新闻
1、一级页面
注意,该网站采用的是GBK编码,需要使用iconv-lite转码,与此同时,options中将encoding设置为null,如下
var options = {uri: 'https://news.163.com',encoding: null,transform: function (body) {body = iconv.decode(body, 'gbk');return cheerio.load(body);}
}
var item = $('.mod_top_news2', 'div').find('li');item.map(function (idx, element) {var news = {};news.title = $(element).find('a').text();news.link = $(element).find('a').attr('href');console.log(news);})
使用类似的办法,同样爬取出标题和二级页面url
2、二级页面
简明扼要;非常好处理
rp(options).then(function ($) {var item = $('.post_content_main', 'div');news.time = item.find('.post_time_source', 'div').text().slice(0, 36).replace(/\s*/g, '');news.editor = item.find('.ep-editor', 'span').text();news.source = item.find('.post_time_source', 'div').children('a').first().text();news.comment = item.find('.post_cnum_tie', 'a').text();var maintext = '';$('.post_text', 'div').children('p').each(function (idx, element) {maintext = maintext.concat($(element).text()).replace(/\s*/g, '');})news['texts'] = maintext;console.log(news);
吐槽一下用了两次去除字符串中的空字符的方法 .replace(/\s*/g, ‘’)
3)Pixiv
1、一级页面
Pixiv是一个图片网站,这里不再对主页进行爬取,而是直接对某个关键词的搜索页进行爬取
https://www.pixiv.net/tags/比那名居天子/artworks?s_mode=s_tag
我们随机挑一个关键词进行搜索,可以看见url的组成方式非常简单,可以直接利用字符串操作
在这里插入图片描述
同样是每张图片都在各自 class=sc-prOVx jMjpVy 中
然而事与愿违,这是因为Pixiv是需要代理的。同时,pixiv需要登录才能使用会员搜索等功能。
a. 使request使用代理
首先安装ss5代理需要的模块
npm install socks5-https-client
然后你需要一个可以使用的 socks 代理,并且先测试一下代理是否能生效,首先选取登录界面的一段文字尝试爬取
var cheerio = require('cheerio')
var rp = require('request-promise')
var Agent = require('socks5-https-client/lib/Agent');
var headers = {"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",'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'
}
var options = {strictSSL: true,agentClass: Agent,agentOptions: {socksHost: '*.*.*.*', //代理的IP或者域名!socksPort: *, //代理的端口!socksUsername: '*', //代理的用户名!socksPassword: '*' //该用户的密码!},uri:'https://www.pixiv.net/',headers: headers,transform: function (body) {return cheerio.load(body);}
}rp(options).then(function ($) {console.log('Tip: ' + $('.signup-form__catchphrase', 'div').text());})
代理成功生效!
b. 对某个搜索结果的爬取
uri: encodeURI('https://www.pixiv.net/tags/'+tag),
首先,我们写的tag都是汉字形式,需要利用 encodeURI 函数转化为UTF-8格式
console.log($('body').html());
然而,在获取整个 body 的时候,发现里面的内容是空的。如果用浏览器直接打开这个页面,会发现内容是分步骤加载的,也就是动态加载的,直接request页面,是缺少了很多信息的。
打开控制台的 Network ,选择 XMR ,可以发现网站向四个不同的url发送了请求。在一个个尝试之后,发现其中一个页面: https://www.pixiv.net/ajax/search/top/比那名居天子 是如下json内容:
通过敏锐的嗅觉不难发现,选中的 “id”:“80511208”正是搜索结果中的图片的ID,实际打开之后也确实如此,于是我们改为爬取 “https://www.pixiv.net/ajax/search/top/ + tag” 的内容。
这里另外找到了一个json更加简洁的页面 “https://www.pixiv.net/ajax/search/manga/” + tag + “?word=” + tag + “&order=date_d&mode=all&p=1&s_mode=s_tag_full&type=manga”
丢到 https://www.bejson.com/ 上去格式化一下,可以看见每个id都在“data”内每个对象中的“id”属性内。
rp(options).then(function ($) {var str = $('body').html(); //将body中的json内容转换为字符串str = str.replace(/"/g,'"'); //json中的所有引号都显示为了",在此处替换回来var json = JSON.parse(str); //将字符串转换为json对象var data = json.body.manga.data; //每个对象内存着一个id的data数组for(var element in data){console.log(data[element].id); //遍历data数组内的所有对象的id}
})
id就顺利的都爬取了下来
c. 爬取每个id下的图片
容易发现,每个ID下的图片均为 “https://www.pixiv.net/artworks/” + id
同样地,该网站也是动态加载的,并且在XHR中难以找到图片对应的url,不过,我们可以观察到每一张图片的命名规律:
https://i.pximg.net/img-original/img/2020/02/08/19/09/08/79355941_p0.png
主要信息为日期、时间和id,重新检查上图中的json文件,可以看到这些信息都有很好地保存。
for(var element in data){var id = data[element].id;var url = data[element].url;if (url!=undefined) {url = url.replace(/c\/250x250_80_a2\/img-master/g,'img-original');url = url.replace(/_square1200.jpg/g,'.png');console.log(url);} }
图片的地址已经正确的爬取下来了,然而网站直接打开是403,这是因为服务器还验证了用户是从哪个页面转来的,即下图中的referer。
headers: {'referer': 'http://www.pixiv.net/member_illust.php?mode=big&illust_id=' + id,"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.75 Safari/537.36'
},
在headers中加上了referer之后,便不报403了
var writeStream = fs.createWriteStream('image.png');
var readStream = request(ne_options);
readStream.pipe(writeStream);
writeStream.on("finish", function() {console.log("下载成功!!");writeStream.end();
});
//临时加上一段通过request下载图片的代码
图片下载成功了,从文件夹打开之后,也发现图片可以正常显示。
d. 使各种格式的图片都能正确下载,优化下载体验
网站上的大部分图片都有JPG和PNG两种格式的URL,但是部分图片只含其中一种。这里的笨办法是两种后缀URL都进行访问,通过判断返回的状态码是否是404,来判断URL是否有效
function download(Jpg_options, Png_options, id) {request(Jpg_options, function (error, response, body) {var now_options = Jpg_options;if(response.statusCode!=404) {var name = id + '_0.jpg';var writeStream = fs.createWriteStream("./images/"+name);var readStream = request(now_options);readStream.pipe(writeStream);writeStream.on("finish", function() {downloading++;console.log("第 " + downloading + '/' + downloadAmount + " 张下载成功!");writeStream.end();});}else{request(Png_options, function (error, response, body) {var now_options = Png_options;if(response.statusCode!=404) {var name = id + '_0.png';var writeStream = fs.createWriteStream("./images/"+name);var readStream = request(now_options);readStream.pipe(writeStream);writeStream.on("finish", function() {downloading++;console.log("第 " + downloading + '/' + downloadAmount + " 张下载成功!");writeStream.end();});}});}});
}
通过简单地if判断来进行下载,Png_options 和 Jpg_options 分别含有这两种后缀的url
function finishDownload() {//console.log(listArr);var finallist=JSON.stringify(listArr, '', '\t');fs.writeFileSync("./images/list.json", finallist);console.log('全部下载完毕!共抓取到 ' + total + " 张,计划下载 " + downloadAmount + " 张,其中 " + downloaded + " 张已存在,下载成功 " + success + " 张,下载失败 " + fail + " 张。");if(fail>0) {console.log('下载失败:' + fails);}process.exit();
}
将结束下载重构为函数,并且添加一个文件,用来存储所有下载过的图片的id,以免重复下载图片。同时加入几个变量,用于记录抓取总数、下载计划数、已下载数、下载成功数和下载失败数。最后输出如下:
下载失败的原因可能是链接已失效。完整代码在:
https://github.com/AquariusAQ/Web-Crawler-in-Node.js
从零开始的Node.js新闻爬虫实验项目(四)东方财富网、网易新闻、Pixiv的爬取思路相关推荐
- Node.js期中爬虫实验项目
Node.js期中爬虫实验项目 期中作业要求 基础概念引入 前期准备工作 安装node.js 安装数据库 安装Navicat Premium 15 正则表达式学习网站 课堂示例演示 示例一(显示在终端 ...
- Python 网络爬虫实战:去哪儿网旅游攻略图文爬取保存为 Markdown电子书
接上回,<Python 网络爬虫实战:爬取<去哪儿>网数千篇旅游攻略数据>. 我们爬取到了数千篇的旅游攻略文章的数据. 但是事情还没有结束,对于大部分的人来讲,最希望得到的东西 ...
- 用python爬虫爬取东方财富网信息网页信息_爬取东方财富网数据的网页分析
自学Python已有3个月之多,浏览无数大神的佳作,收获颇丰.当初自学python就是为了学习爬虫,爬取网站上好看妹子的图片--[流口水][流口水] 言归正传,近期学习量化交易知识,发现东方财富网(e ...
- 从零开始搭建Node.js, Express, Ejs, Mongodb服务器
http://www.toolmao.com/nodejs-express-ejs-mongodb-server 本文改自非鱼的<[翻译]前端开发人员入门指南,从零开始搭建Node.js, Ex ...
- 如何把 Node.js 嵌入自己的项目中
Node.js 不仅可以单独运行,还可以以库的方式被使用,本文介绍下如何把 Node.js 嵌入到自己项目中. 首先第一步下载 Node.js 源码,然后根据 Node.js 的文档进行编译安装.这样 ...
- helmet是一个保护Node.JS应用的安全项目
helmet是一个保护Node.JS应用的安全项目 14-11-15 banq #NodeJS #express #安全 Helmet是一系列帮助增强Node.JS之 ...
- 爬虫小项目(四)利用多进程和ajax技术爬取堆糖
这次主要讲一下怎么分析ajax请求来获得我们想要的数据,在通过多进程进行抓取,当然这次的目的主要是这两个,所以最后的结果是以打印在控制台为主. 那么让我们开始这一次的爬虫之旅 我们先进入堆糖网,这次我 ...
- 知乎爬虫(scrapy默认配置下单机1小时可爬取60多万条数据)
知乎爬虫(scrapy默认配置下单机1小时可爬取60多万条数据) 版本:1.0 作者: AlexTan CSDN: http://blog.csdn.net/alextan_ e-mail: alex ...
- 爬虫第1课,手把手教你,批量爬取高清壁纸
一.环境准备 '''1.安装虚拟环境 python -m venv venv2.选择解释器 File/Settings/Project:getPicture(项目名)3.进入虚拟环境 cd .\ven ...
最新文章
- Tensorflow初学者之搭建神经网络基本流程
- solr管理界面详解
- 利用原生js 如何实现div移动?
- 限时秒杀┃月销10000+件,风靡全国的steam科学实验套装
- OpenMP之双重for循环并行计算改进
- iOS设计模式之单例模式
- win7计算机双击空白,win7系统控制面板“打开或关闭Windows 功能”空白没有任何选项的解决方法...
- Oracle 基础知识
- linux命令之tee,linux tee命令
- 1个开发如何撑起一个过亿用户的小程序
- 【数字信号去噪】基于matlab奇异值分解(SVD)数字信号降噪【含Matlab源码 1020期】
- python曲线和直线的交点_求直线与分段线性曲线的交点
- Unity插件-HighlightingSystem(边缘光)
- 安卓模拟器安装教程_安卓模拟器测试总结!究哪个最流畅?内附模拟换IP教程...
- FishC笔记—21 讲 函数:lambda表达式
- Matlab中散点图绘制详细教程scatter函数(附matlab代码)
- SpringCloud整合Feign和Nacos报错:No Feign Client for loadBalancing defined. Did you forget to include?
- python excel 单元格换行_python excel单元格如何换行
- win2012 r2/win2016修改域密码复杂度策略
- 用python输出圣诞树_教你怎样用Python画了一棵圣诞树,赶紧来学习
热门文章
- 【每日一读】Self-Paced Network Embedding
- 高考后的我们要去追逐星辰大海
- 解决IDEA中maven创建web项目时新建无jsp选择项
- Mysql子查询优化技术
- 【tensorrt】——Network has dynamic or shape inputs, but no optimization profile has been defined.
- MongoDB高性能、高可用之副本集、读写分离、分片、操作实践
- 云信DUILIB 常用控件 小实例
- 10.11-数据库mysql
- SQL查询列出每个班的班号和总人数
- “消费者至上:媒体新时代 ”主题响彻IBC2019