js提取指定网站内容(如何去组织所有文章的功能了吗?|之旅)

优采云 发布时间: 2021-11-20 12:17

  js提取指定网站内容(如何去组织所有文章的功能了吗?|之旅)

  1. 前言

  这个文章藏在心里很久了,久久不敢开始写。主要是不知道怎么组织这样的技术文章文章。

  其实我个人觉得技术文章是最难写的,细节往往很难把握。一些技术细节没有解释到位,对于害怕阅读的人来说很难。相反,一些简单的东西怕解释的太多,增加了不必要的章节。

  教人钓鱼不如教人钓鱼

  所以,在这个文章中,我会尽量少发代码,多谈谈思考过程。

  2. 编码的原因

  最近在重建我的个人网站,想把我在简写的所有文章数据导入到那个网站。

  这时候可能有朋友不高兴了:“如果你想得到你写的所有文章,为什么还要写代码?简书是不是已经提供了下载所有文章的功能?当前用户?”

  

  兄弟们说得对。首先我要声明,简书确实是一个很棒的写作平台。可以满足大部分用户的需求,但是对于我这个癌症晚期的“懒惰”程序员来说,还是有点不适应。太多了。我有以下考虑

  坚持

  不要重复自己

  带着这个原理,让我们开始这次的爬虫之旅。

  3. 功能介绍

  简述爬虫的作用

  向服务器发送请求,获取所有作者的文章。从文章中提取你需要的数据(文章内容、标题、发布日期...),整理好数据,存放到对应的数据库中。

  本文将重点介绍页面请求、分析和数据组织。至于如何在数据库中存储数据,我就不多说了。有兴趣的可以直接看源码。

  4. 技术栈

  最后选择使用node.js来写这个爬虫。毕竟重新学习python或ruby等服务器端语言要花很多时间。当然这还不够。

  工欲善其事,必先利其器

  为了写更少的代码,我还需要一个更成熟的爬虫框架。这里使用了节点爬虫。个人觉得这是一个很酷的爬虫框架,前端人员在使用的时候会觉得比较亲切——我们可以用我们最亲切的jQuery语法来解析响应返回的页面。

  5. 数据模型

  在我们要爬取东西之前,首先要确认我们要爬取什么。为了简化文章,我将需要爬取的内容设置为以下三个字段(源码可以多于这三个字段)。

  我只需要找到一种方法,从响应返回的页面中提取上述三种类型的数据。至于把数据存放在什么数据库中,如何存放,就看个人喜好了。

  6. 制定爬取策略(1) 基本信息爬取

  首先进入通讯作者短书首页,类似这个页面。我们会看到一堆文章列表,看看能不能提取出我们需要的信息?

  

  嗯,问题挺多的,除了文章这个标题,其他的内容好像很难抓取。不管怎样,都得去文章详情页查看

  

  看来详情页还是可以满足我的需求的。因此,我决定使用以下策略来提取基本信息

  (2)面对滚动加载,如何获取所有文章?

  当我进入特定作者的简书首页时,我发现简书实际上并没有加载作者的所有文章,他只是加载了文章列表的一部分。如果需要获取更多的 文章 列表,则需要向下滚动并从服务器请求更多页面。

  

  一开始我是站在前端的角度考虑这个问题,真的很痛苦。我最初的想法是使用一些库,例如 phantomjs 来模拟浏览器的行为。我打算模拟浏览器的滚动行为,并在数据加载后继续滚动,直到不再从服务器请求数据。我真的这样做了,后来才发现这是一场噩梦,这意味着我不得不做以下事情:

  先不说有没有库支持上面的功能,上面的策略对于挑剔的人来说都是不靠谱的,估计只有我一个人傻傻的跑着试了。经过多次尝试,发现模拟滚动行为相当困难,使用phantomjs时开发环境经常卡死。我的直觉告诉我,可能有更好的方法来做到这一点。当你对一个问题感到困惑时,你可能会尝试超越原来的思维方式,换个角度思考问题。问题往往要简单得多。

  后来从后端的角度考虑了这个

  问:这种加载更多行为的本质是什么?

  答:向服务器发送请求以获取更多页面数据。

  那么我只需要知道浏览器向服务器发送的请求的URL以及页面滚动时的相应参数,就可以使用爬虫来迭代发送这个请求,进而达到获取<的完整列表的目的@文章 ?

  OK,马上去Network,就可以看到我们发送的网络请求了。清除网络下的历史记录后,我滚动页面,发现以下内容。

  

  服务器响应后,返回渲染的列表数据。果然,如我所料。然后我会看完整的网址

  

  原来它是使用分页参数page向服务器请求分页数据的。我通过代码封装了这个过程

  var i = 1;

var queue = []

while( i < 10) {

var uriObject = {

uri: 'http://www.jianshu.com/u/a8522ac98584?order_by=shared_at&&page=' + i,

queue.push(uriObject);

i ++;

}

  这只是代码片段的一部分,将 10 个 URL 存储到队列数组中。最后只能得到10页的数据,但是有问题。如果真实数据少于10页,如何处理?

  我试图请求第 100 页上的数据,看看会发生什么。发现简书服务器返回302状态码,然后浏览器跳转到个人动态页面。

  

  这个状态码很有用,我可以判断我们请求的页码参数page的值是否超过了这个状态码指定的页数。

  我可以预设更多的请求。如果请求返回此状态码,则不会对请求的数据进行任何处理(因为已超出页数)。否则,分析返回的数据以提取我们需要的关键数据。

  当然,这种方式相当粗鲁,会发送很多不必要的请求。有时间我会优化这部分代码。

  7. 页面分析

  发送请求后,我们可以在服务器响应后得到我们需要的页面。接下来要做的就是解析页面结果,提取我们需要的内容。如上所述,node-crawler 的爬虫框架内置了 jQuery,这让我们的页面解析工作变得更加轻松。

  (1)获取文章详情页的url

  我们来看看文章列表中每个条目的html结构(简书的程序员也有评论)。

  

  我们只需要提取ul.note-list中的每个li a.title,然后提取它们的href属性对应的值,也就是我们需要获取的url。这种操作对于jQuery来说简直是小菜一碟。以下是我的代码片段。我把所有的网址都提出来之后,就会存放在articlesLink数组中,以备后用。

  let articlesLink = [];

$('ul.note-list').find('li').each((i, item) => {

var $article = $(item);

let link = $article.find('.title').attr('href');

articlesLink.push(link);

})

  (2)从详情页提取数据

  查看详情页的结构

  

  从页面结构中,我们可以很容易的提取出发布日期这两个字段的标题和内容

  let title = $article.find('.title').text();

let date = $article.find('.publish-time').text().replace('*', '');

  一些更新的文章在发布日期结束时会有一个*,所以我需要处理它们以避免干扰。但是,文章主体的提取存在一些问题。

  

  我希望得到的最后一件事是降价格式的字符串。此时,我可以通过 to-markdown 包将 html 转换为 markdown。但是现在的问题是这个包好像无法解析div标签。我在想把文章的body里面的div标签全部删掉,然后通过to-markdown把处理后的字符串转换成对应的markdown格式字符串,然后就可以得到我们期望的数据了。

  既然jQuery是神器,实现起来也不会很麻烦。但是我也想删除收录类名image-caption的label——这是简书的默认设置,有时候有点碍眼,可以考虑删除。

  下面是我的代码片段:

  var toMarkdown = require('to-markdown');

// 删除图片的标题

let $content = $article.find('.show-content');

$content.find('.image-caption').remove();

$content.find('div').each(function(i, item) {

var children = $(this).html();

$(this).replaceWith(children);

})

// 获取markdown格式的文章

let articleBody = toMarkdown($content.html());

  最后,只需将它们放入对象中:

  let article;

article = {

title: title,

date: new Date(date),

articleBody: articleBody

}

  至于如何将上述数据存入数据库,方法有很多种。考虑到文章的长度,这里就不赘述了。个人尊重MongoDB。它是目前使用最多的非关系型数据库,非常灵活。对于构建渐进式应用程序,我认为这是一个更好的选择。在频繁修改表结构的情况下,至少不需要维护大量的迁移文件。

  最终的存储结果如下,正好是68篇文章

  

  结尾

  不知不觉这个文章已经占用了好几个小时了,就算这个文章我把不必要的代码细节去掉了,重点说说自己的思考过程和遇到的问题。,不过还是写了很多字。视觉概括能力有待提高~~~~

  注:本文只是一些经验和思考过程的总结,github源码仅供参考,并非即插即用包。可以根据自己的情况写一个符合自己需求的爬虫。我相信你可以比我做得更好。

  快乐编码和写作!!

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线