使用puppeteer爬取文章

729 阅读3分钟

背景

最近公司在做cms系统(内容管理),东西搞好了内容填充却是一大问题,本着节省成本的思想便觉得一部分文章通过爬虫爬取然后进行填充(爬取的内容都是经过授权的,做爬虫只是想节省人力而已)。
其实正常的文章可以直接就后端请求文章进行处理返回,奈何有些文章(例如公众号推文)要打开之后才动态生成文章内容,图片还要懒加载。得知谷歌推出了无界面的chrome, 附送了Puppeteer用于驱动没头的Chome。号称能进行几乎所有能在有界面浏览器的操作,好的,那就简单了,我用在node里直接就用Puppeteer打开页面获取内容进行操作不就完事了吗~~~

附上puppeteer地址:pptr.dev/


安装

windows环境下安装

npm i puppeteer
window下安装这个是最省事的了,依赖都帮你装好,一条龙服务。不过因为要安装浏览器嘛,浏览器120m左右,所以推荐用cpm安装,亲测快很多

LINUX环境下安装

linux环境下执行上面的安装命令并都不会把所有依赖都装好,需要你手动装,详情看这里:github.com/puppeteer/p…

CentOS需要安装这些:

pango.x86_64
libXcomposite.x86_64
libXcursor.x86_64
libXdamage.x86_64
libXext.x86_64
libXi.x86_64
libXtst.x86_64
cups-libs.x86_64
libXScrnSaver.x86_64
libXrandr.x86_64
GConf2.x86_64
alsa-lib.x86_64
atk.x86_64
gtk3.x86_64
ipa-gothic-fonts
xorg-x11-fonts-100dpi
xorg-x11-fonts-75dpi
xorg-x11-utils
xorg-x11-fonts-cyrillic
xorg-x11-fonts-Type1
xorg-x11-fonts-misc
Ubuntu 需要安装这些:
gconf-service
libasound2
libatk1.0-0
libatk-bridge2.0-0
libc6
libcairo2
libcups2
libdbus-1-3
libexpat1
libfontconfig1
libgcc1
libgconf-2-4
libgdk-pixbuf2.0-0
libglib2.0-0
libgtk-3-0
libnspr4
libpango-1.0-0
libpangocairo-1.0-0
libstdc++6
libx11-6
libx11-xcb1
libxcb1
libxcomposite1
libxcursor1
libxdamage1
libxext6
libxfixes3
libxi6
libxrandr2
libxrender1
libxss1
libxtst6
ca-certificates
fonts-liberation
libappindicator1
libnss3
lsb-release
xdg-utils
wget

我部署的服务器是CentOS的,所以在执行完 npm i puppeteer 后,安装依赖:

yum install pango.x86_64 libXcomposite.x86_64 libXcursor.x86_64 libXdamage.x86_64 libXext.x86_64 libXi.x86_64 libXtst.x86_64 cups-libs.x86_64 libXScrnSaver.x86_64 libXrandr.x86_64 GConf2.x86_64 alsa-lib.x86_64 atk.x86_64 gtk3.x86_64 -y

启动:

引入

const puppeteer = require("puppeteer");

启动浏览器:

const browser = await puppeteer.launch({    headless: true,    args: ['--no-sandbox', '--disable-setuid-sandbox']  });

headless为表示是否无头(即无界面),true表示无界面,false表示有界面,有界面的话启动的时候就像正常浏览器一样。

args为参数选择,亲测在window下不配置该项是没问题的,运行正常,而在centOS上缺会报错,解决办法为sandbox去除沙箱运行,所有还是得配置下该选项:

args: ['--no-sandbox', '--disable-setuid-sandbox']

有了以上得操作,浏览器是能正常调起打开的了。接下来的大家就可以随意发挥了,相关功能API大家需到文档查询,例如怎么模拟点击,输入,怎么查询节点等,应有尽有。


文章爬取

我得需求是爬取前端传过来的文章链接内容,获取文章的标题,摘要,作者,来源,meta等,然后匹配文章主体的图片,上传到自家的cdn,再把地址替换回来,最后整理这些信息返回给前端使用。

例如有一文章链接是www.abc.com,我要实现上述操作:

启动浏览器后,打开新页面:

  const page = await browser.newPage;

设置一些浏览器选项:

const UA =   "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/63.0.3239.84 Chrome/63.0.3239.84 Safari/537.36";  
await Promise.all([ 
page.setUserAgent(UA),    // 设置客户端信息
page.setJavaScriptEnabled(true),    //允许运行js(有些页面需要运行js才能正常打开)
page.setViewport({ width: 800, height: 600 })  ]); 设置视图大小(无界面的话这项可有可无)


打开文章页:

 await page.goto('www.abc.com'); //url根据实际地址定

现在page变量代表这个文章页面

获取文章某部分内容:

例如获取头部内容:

 let head = await page.$eval("head", el => el.innerHTML);

head表示头部标签,el表示获取到的dom节点,利用js可以正常对它操作。
现在是获取它的内部内容,用innerHTML

获取主体内容:

let mainBody = await page.$eval("#js_content", el => el.innerHTML);

同理,找到主体内容的id或class或标签,轻松获取内容

内容处理:

内容拿到了,这下可以随意操作了

如匹配某个name为descriptioncontent

const meta = head.match(/(?<=<meta.*?name="description".*?content=").*?(?=".*?>)/g)[0]

匹配特定格式图片,获取链接爬取图片上传cdn等,具体操作视需求而定。
最后返回处理后的数据格式,完美~~~