node.js爬虫教程 node.js安装

首先,既然学爬虫,那么其实最重要的一点就是要安装node.js。

这里我用的是Windows系统,重新用虚拟机开了一个全新的windows10系统。

然后我们百度搜一下nvm,然而其实并没有找到直接的下载地址,唯一的一个GitHub是Linux的。
nvm百度搜索结果

所以我们直接打开GitHub,在GitHub上找一下。

nvm GitHub

不错,找到了windows版本的nvm。

找到他的releases,之后下载最新版的即可。

https://github.com/coreybutler/nvm-windows/releases

nvm GitHub
nvm GitHub

下载之后解压,然后右键管理员打开,一路安装即可。

之后安装完成nvm,打开cmd窗口。
nvm GitHub

输入nvm查看安装是否成功。
可以看到,安装成功了,那么我们直接nvm install lts安装最新的稳定版,目前是16.15.0。
nvm GitHub

安装完成之后,打开一个管理员权限的cmd窗口,然后输入nvm 16.15.0然后输入node -v就能看到成功安装node.js了。
nvm GitHub
nvm GitHub

mac安装nvm的话可以直接去GitHub上下载

1
2
shell notranslate position-relative overflow-auto
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh bash
1
2
shell notranslate position-relative overflow-auto
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh bash

之后将nvm添加到环境中

1
2
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm"  printf %s "${XDG_CONFIG_HOME}/nvm")"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm

1
source ~/.bash_profile

即可使用

node.js爬虫教程 vscode安装

安装完成node.js后,我们需要一个编辑器来进行代码的编写。

目前我觉得比较好用的一个是vscode,一个是webstorm。

这两个我比较推荐使用vscode,因为webstorm有一个很致命的问题,就是他的终端不能解析一些编码格式的内容,比如说表情,就会导致非常的难受。

并且vscode免费,而webstorm是付费的,高下立判。

百度搜索vscode,然后向下拉,找到一个全英文的链接。
node vscode

然后找到download for windowsnode vscode
之后找到适合自己的版本进行下载,然后一路确认安装即可

node vscode
之后打开拓展,安装一下中文插件,重启,就能获得中文界面了。

node vscode

node.js爬虫教程

目前有想法做一套简单的node.js的爬虫教程。
其实这是因为目前node.js的爬虫教程有点少,但是node.js写爬虫其实效果还是非常不错的。所以本着技术共享,共同提升的想法,准备简单的出一套node.js的爬虫教程。

首先其实简单说一下,如果是前端想要学爬虫,我建议学node.js来做爬虫,这是因为node.js是使用的v8引擎,直接用JavaScript代码写就可以了,上手快。
如果是有一定经验的话,也可以学习一下node.js爬虫。

如果是新手入门的话,我其实建议还是使用python来开发爬虫。

目前的想法是简单介绍一下node.js然后直接上实战。

分别使用几个目前我觉得比较好的库进行网站爬取。

网站就不挑难得了,主要是介绍一下这几个库。

  1. Puppeteer
  2. Axios
  3. Request
  4. Node-fetch

目前是准备介绍一下这4个库。

然后爬取的网站,是分了下面的这几个站。

1
2
3
4
5
6
7
[http://www.espn.com/nba/salaries] nba薪资
[https://www.datehoer.com/] 博客
[https://yt.lianjia.com/ershoufang/] 链家二手房
[https://www.baidu.com/s?wd=美国50年来首次披露UFO影像] 百度搜索
[http://www.kuwo.cn/rankList] 酷我音乐
[https://ss.netnr.com/wallpaper] 壁纸
[https://www.zhihu.com/]知乎登录

目前的想法是每个库都写一个站来做说明。
当然也就是简单的爬个几页,其实就是像前面说的一样,主要是为了介绍,然后提出来这个东西,方便大家共享自己的经验。

已完成录制:
node.js安装 待上传

vscode安装 待上传

待完成:
简单的爬虫
使用puppeteer爬取博客
通过axios爬取美国nba球员薪资
使用request爬取链家二手房
使用node-fetch爬取百度搜索结果,酷我音乐,壁纸
使用puppeteer登录知乎

ubuntu安装node

1
2
3
4
5
6
7
apt update
apt upgrade
apt install npm
npm install -g npm
npm install -g n
n xx.xx.xx
hash -r

首先是更新服务器的apt,然后安装npm,全局更新npm版本到最新或者指定版本npm install -g [email protected],之后全局安装n,再用n安装node,我一般都是指定版本 n xx.xx.x,然后hash -r就可以正常使用了

puppeteer卡死怎么办?

发现服务器上跑的进程进场会卡死,必须要手动重启一下才行,一开始以为是服务器配置不行,但是后来一想,我之前运行的代码一直在跑着也没出什么事情,为啥这次就不行了呢?

于是仔细地检查了一下,发现了一个问题。

可以持续运行的代码是只执行了一次puppeteer.lanuch(),而不可以持续运行的代码是执行一次后关闭重启再执行,这样的话,启动可能会造成资源的浪费,内存溢出等等,导致Linux服务器无法启动chrome,而这时没有增加启动判断得话,会导致进程一直卡在这个位置上不动。
所以其实应该首先浏览器,然后不关闭浏览器,关闭page页面,这样就会持续使用同一个浏览器了。

假设我现在有一个函数,是一个循环执行的函数。

1
2
3
4
async function getData(msg){
const browser = await puppeteer.launch()
const page = await browser.newPage()
}

这样每次执行这个getData函数,我们都需要启动一次chrome,导致资源占用率升高,如果所有的进程卡在同一时间启动得话,会发生启动失败现象,所以我们应该首先启动一个chrome然后不断地在里面打开page。

1
2
3
4
const browser  = await puppeteer.launch()
async function getData(msg,browser){
const page = await browser.newPage()
}

也就是这样,这样就能防止启动超时了。

用node跑excel时遇到了内存溢出的问题

报错信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
[19372:00000188FE38D750]   482437 ms: Scavenge 13679.5 (14045.6) -> 13666.6 (14045.6) MB, 14.4 / 0.0 ms  (average mu = 0.989, current mu = 0.992) allocation failure
[19372:00000188FE38D750] 482469 ms: Scavenge 13680.9 (14045.6) -> 13668.1 (14045.9) MB, 14.0 / 0.0 ms (average mu = 0.989, current mu = 0.992) allocation failure
[19372:00000188FE38D750] 484236 ms: Scavenge (reduce) 13687.5 (14061.0) -> 13683.4 (14061.0) MB, 14.4 / 0.0 ms (average mu = 0.989, current mu = 0.992) allocation failure


<--- JS stacktrace --->

FATAL ERROR: MarkCompactCollector: young object promotion failed Allocation failed - JavaScript heap out of memory
1: 00007FF65F861DDF napi_wrap+109135
2: 00007FF65F806D06 v8::internal::OrderedHashTable<v8::internal::OrderedHashSet,1>::NumberOfElementsOffset+33350
3: 00007FF65F807AD6 node::OnFatalError+294
4: 00007FF6600D64CE v8::Isolate::ReportExternalAllocationLimitReached+94
5: 00007FF6600BB31D v8::SharedArrayBuffer::Externalize+781
6: 00007FF65FF6574C v8::internal::Heap::EphemeronKeyWriteBarrierFromCode+1516
7: 00007FF65FF502EB v8::internal::NativeContextInferrer::Infer+59339
8: 00007FF65FF3571F v8::internal::MarkingWorklists::SwitchToContextSlow+57503
9: 00007FF65FF4947B v8::internal::NativeContextInferrer::Infer+31067
10: 00007FF65FF4050D v8::internal::MarkCompactCollector::EnsureSweepingCompleted+6269
11: 00007FF65FF486CE v8::internal::NativeContextInferrer::Infer+27566
12: 00007FF65FF4C64B v8::internal::NativeContextInferrer::Infer+43819
13: 00007FF65FF55E82 v8::internal::ItemParallelJob::Task::RunInternal+18
14: 00007FF65FF55E03 v8::internal::ItemParallelJob::Run+643
15: 00007FF65FF29583 v8::internal::MarkingWorklists::SwitchToContextSlow+7939
16: 00007FF65FF409CC v8::internal::MarkCompactCollector::EnsureSweepingCompleted+7484
17: 00007FF65FF3F204 v8::internal::MarkCompactCollector::EnsureSweepingCompleted+1396
18: 00007FF65FF3CD18 v8::internal::MarkingWorklists::SwitchToContextSlow+87704
19: 00007FF65FF6B4F1 v8::internal::Heap::LeftTrimFixedArray+929
20: 00007FF65FF6D5D5 v8::internal::Heap::PageFlagsAreConsistent+789
21: 00007FF65FF627F1 v8::internal::Heap::CollectGarbage+2033
22: 00007FF65FF609F5 v8::internal::Heap::AllocateExternalBackingStore+1365
23: 00007FF65FF7AD76 v8::internal::Factory::AllocateRaw+166
24: 00007FF65FF8F49F v8::internal::FactoryBase<v8::internal::Factory>::NewRawTwoByteString+79
25: 00007FF65FE9BD70 v8::base::TimeDelta::operator!=+31136
26: 00007FF65FE9DF57 v8::base::TimeDelta::operator!=+39815
27: 00007FF65FE9BFCA v8::base::TimeDelta::operator!=+31738
28: 00007FF66004873B v8::internal::Builtins::builtin_handle+80267
29: 00007FF660048CD3 v8::internal::Builtins::builtin_handle+81699
30: 00007FF66015F0FD v8::internal::SetupIsolateDelegate::SetupHeap+464173
31: 00007FF6600F7A02 v8::internal::SetupIsolateDelegate::SetupHeap+40498
32: 00007FF6600F7A02 v8::internal::SetupIsolateDelegate::SetupHeap+40498
33: 00007FF6600F7A02 v8::internal::SetupIsolateDelegate::SetupHeap+40498
34: 00007FF6600F7A02 v8::internal::SetupIsolateDelegate::SetupHeap+40498
35: 00007FF6600F7A02 v8::internal::SetupIsolateDelegate::SetupHeap+40498
36: 00007FF6600F7A02 v8::internal::SetupIsolateDelegate::SetupHeap+40498
37: 00007FF6600F7A02 v8::internal::SetupIsolateDelegate::SetupHeap+40498
38: 00007FF6600F7A02 v8::internal::SetupIsolateDelegate::SetupHeap+40498
39: 00007FF6600F7A02 v8::internal::SetupIsolateDelegate::SetupHeap+40498
40: 00007FF6600F7A02 v8::internal::SetupIsolateDelegate::SetupHeap+40498
41: 00007FF6600F7A02 v8::internal::SetupIsolateDelegate::SetupHeap+40498
42: 00007FF6600F7A02 v8::internal::SetupIsolateDelegate::SetupHeap+40498
43: 00007FF6600F56BE v8::internal::SetupIsolateDelegate::SetupHeap+31470
44: 00007FF6600F52AC v8::internal::SetupIsolateDelegate::SetupHeap+30428
45: 00007FF65FFC5959 v8::internal::Execution::CallWasm+1657
46: 00007FF65FFC51BF v8::internal::Execution::Call+191
47: 00007FF6600B0797 v8::Function::Call+615
48: 00007FF65F83146E napi_unref_threadsafe_function+3278
49: 00007FF65F835517 node::Start+1159
50: 00007FF65F835911 node::Start+2177
51: 00007FF65F883D71 node::LoadEnvironment+49
52: 00007FF65F7C03E3 v8::internal::OrderedHashTable<v8::internal::OrderedHashSet,1>::NumberOfBucketsOffset+9299
53: 00007FF65F8351C7 node::Start+311
54: 00007FF65F6967CC RC4_options+339660
55: 00007FF66063B1EC v8::internal::compiler::RepresentationChanger::Uint32OverflowOperatorFor+152748
56: 00007FFD89657034 BaseThreadInitThunk+20
57: 00007FFD89F02651 RtlUserThreadStart+33

将跑的数据加进excel中,发现出现了MarkCompactCollector: young object promotion failed Allocation failed - JavaScript heap out of memory这个问题,于是百度查了好久,最后找到了一个不算方法的方法。

https://support.snyk.io/hc/en-us/articles/360002046418-JavaScript-heap-out-of-memory
在powershell中输入下面这个指令,将内存值调大一点,可以解决一点点问题,但是看我的报错会发现并没有解决,只要你调的内存不够,还是会继续报错。

1
$env:NODE_OPTIONS="--max-old-space-size=8192"

node-red的二三事

前两天了解到了node-red,一个低代码平台。
简单测试了一些功能感觉挺不错的,于是尝试将部分代码移植到node-red上。

安装

我是先百度查了一下,感觉可以用docker来安装这个node-red,所以我就用的docker。
其实还是因为这一篇文章,所以选择的docker,具体安装推荐百度查一下。

docker pull nodered/node-red

安装后启动就行了。

然后也可以直接在node上安装,其实还是推荐这个方法,因为docker启动puppeteer出现了个问题,没有解决。

在本地上安装直接npm -g --unsafe-perm node-red即可,之所以要全局安装是因为不这样安装会启动不了。

使用

安装后直接在cmd里使用node-red,然后打开127.0.0.1:1880即可。
node-red界面

然后具体的库可以用它已经集成好的,右上角的三条杠里面有一个节点设置,然后找到安装,进行安装即可。

这里其实就简单说一下puppeteer,首先它其实出现问题就是因为没有找到chrome浏览器,我们找到node-red的配置,然后修改一下puppeteer-core里面的lanuch.js内的浏览器位置即可。

然后再就是想要使用它没有继承的node模块,那么我们就需要在他的setting里面进行设置,具体是在400多行,有一个functionGlobalContext我们将想要用的模块在这里面写上即可,记得要npm install一下才行。

然后使用左面的function即可。

1
2
3
const moment= global.get('moment');
msg.time = moment().format();
return msg

之后用debug读一下msg.time就能读出当前时间了。
然后再比如kafka之类的,都可以整到node-red上,并且可以把一些常用的函数封装一下,变成控件进行拖拽就行。

node mysql模块返回insertid为0解决方法

在用nodejs向MySQL插入数据的时候,获取返回值发现insertid一直是0,然后再获取的时候会获得比最新小1的值,比如说最新插入的值为1122,获取的id就是1121。

后来发现是因为获取id的时候,没有等待query执行完成就获取id了,而我们应该等待query执行完成后再获取id,这样才能获取到当前id。

但是当时给query加上await了,为什么不会执行呢?

因为query不支持异步操作,所以要重写query函数。

创建一个Promise然后将query放在里面进行执行,就可以了。

1
2
3
4
5
6
7
8
9
10
11
async function query(query,params){
return new Promise((resolve,reject)=>{
db.query(query,params,(err,results)=>{
if(err){
reject(err.message)
} else {
resolve(results.insertId);
}
})
});
}