- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Puppeteer使用示例详解由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
phantomjs曾经是无头浏览器里的王者,测试、爬虫等都在使用,随着googlechrome headless的出现,phantomjs的作者已经明确表示不在更新,而googlechrome headless将会是未来爬虫的趋势,而测试将依然会使用webdriver那套方案,googlechrome headless可以利用webdriver调用,也可以使用其集成的api——puppeteer(操纵木偶的人),他的功能和他的名字一样强大,可以随意操控chrome或chromeium,缺点就是只有node的api,来看看他的图标:
puppeteer是基于devtools协议来控制headless chrome的node库,依赖6.4以上版本的node,本人是在接触这个软件时才开始学习node,依然感觉到它的异步async/await超级强大,在puppeteer中也大量使用异步来完成任务.
puppeteer的安装可以使用node的包管理工具npm来安装:
1
|
npm i puppeteer
|
这里安装时会自动安装chromeium,如果不需要则可以通过配置npm跳过下载,做为一名爬虫工程师我不会去讨论测试相关的使用,接下来看看如何使用,和webdriver类似,首先需要实例化brower,代码如下:
1
2
3
4
5
6
7
8
|
const puppeteer
=
require(
'puppeteer'
);
(async ()
=
> {
const browser
=
await puppeteer.launch();
const page
=
await browser.newpage();
await page.goto(
'http://www.baidu.com'
);
await browser.close();
})();
|
这段代码执行结束时,你可能什么也没有感觉到,因为它在后台启动了一个chromeium进程,打开了百度首页,接着就关闭了,当然我们可以在前台打开chromeium,这里就需要配置一下,所配置参数只需传入launch()即可,常用参数如下:
headless: 是否打开浏览器,默认为true 。
ignorehttpserrors: 是否忽略https错误,默认为true 。
executablepath: 配置要调用浏览器的可执行路径,默认是同puppeteer一起安装的chromeium 。
slowmo:指定的毫秒延缓puppeteer的操作 。
args:设置浏览器的相关参数,比如是否启动沙箱模式“--no-sandbox”,是否更换代理“--proxy-server”,具体参数请点此查看 。
使用示例如下:
1
|
const browser
=
await puppeteer.launch({headless:false, args: [
"--no-sandbox"
,]})
/
/
打开浏览器
|
打开新的窗口:
1
|
const page
=
await browser.newpage();
|
设置窗口大小 。
1
2
3
4
|
await page.setviewport({
width:
1920
,
height:
1080
})
|
过滤不需要的请求:
1
2
3
4
5
6
7
|
await page.setrequestinterception(true);
page.on(
'request'
, interceptedrequest
=
> {
if
(interceptedrequest.url().endswith(
'.png'
) || interceptedrequest.url().endswith(
'.jpg'
))
interceptedrequest.abort();
else
interceptedrequest.
continue
();
});
|
为浏览器设置useragent:
1
|
await page.setuseragent(
"mozilla/5.0 (windows nt 10.0; win64; x64) applewebkit/537.36 (khtml, like gecko) chrome/58.0.3029.110 safari/537.36 edge/16.16299"
)
|
设置cookie, 。
1
2
3
4
5
6
|
const data
=
{
name:
"smidb2"
,
domain:
".csdn.net"
,
value:
"201806051502283cf43902aa8991a248f9c605204f92530032f23ef22c16270"
}
await page.setcookie(data)
|
示例中只是演示,真实的cookie是一个列表形式的,需要循环添加才可以 。
1
2
3
|
for
(let data of cookies){
await page.setcookie(data)
}
|
请求url:
1
2
|
const url
=
"http://www.baidu.com"
await page.goto(url, { waituntil:
"networkidle2"
});
|
设置页面等待时间:
1
|
await page.waitfor(
1000
);
/
/
单位是毫秒
|
等待页面某个元素加载完成 。
1
|
await page.waitforselector(
"input[class='usrname']"
)
|
点击某个元素 。
1
|
await page.click(
"input[class='submit']"
)
|
利用page.evaluate()函数拖动鼠标至页面底部,原理就是在页面注入js代码.
1
2
3
4
5
6
7
8
9
10
|
let scrollenable
=
false;
let scrollstep
=
500
;
/
/
每次滚动的步长
while
(scrollenable) {
scrollenable
=
await page.evaluate((scrollstep)
=
> {
let scrolltop
=
document.scrollingelement.scrolltop;
document.scrollingelement.scrolltop
=
scrolltop
+
scrollstep;
return
document.body.clientheight > scrolltop
+
1080
? true : false
}, scrollstep);
await page.waitfor(
600
)
}
|
获取html信息 。
1
2
3
4
5
|
const frame
=
await page.mainframe()
const bodyhandle
=
await frame.$(
'html'
);
const html
=
await frame.evaluate(body
=
> body.innerhtml, bodyhandle);
await bodyhandle.dispose();
/
/
销毁
console.log(html)
|
这是爬虫能用到的大致操作,以下是爬取豆瓣热门电影的基本信息和评分的代码,写这个程序时对node也是一知半解,如有不对,欢迎留言 。
basepupp.js 。
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
|
const puppeteer
=
require(
"puppeteer"
)
class
basepuppeteer{
puppconfig(){
const config
=
{
headless: false
}
return
config
}
async openbrower(setting){
const browser
=
puppeteer.launch(setting)
return
browser
}
async openpage(browser){
const page
=
await browser.newpage()
return
page
}
async closebrower(browser){
await browser.close()
}
async closepage(page){
await page.close()
}
}
const pupp
=
new basepuppeteer()
module.exports
=
pupp
|
douban.js 。
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
const pupp
=
require(
"./basepupp.js"
)
const cheerio
=
require(
"cheerio"
)
const mongo
=
require(
"mongodb"
)
const
assert
=
require(
"assert"
)
const mongoclient
=
mongo.mongoclient
const urls
=
"mongodb://10.4.251.129:27017/douban"
mongoclient.connect(urls, function (err, db) {
if
(err) throw err;
console.log(
'数据库已创建'
);
var dbase
=
db.db(
"runoob"
);
dbase.createcollection(
'detail'
, function (err, res) {
if
(err) throw err;
console.log(
"创建集合!"
);
db.close();
});
});
async function getlist(){
const brower
=
await pupp.openbrower()
const page
=
await pupp.openpage( brower)
const url
=
"https://movie.douban.com/explore#!type=movie&tag=%e7%83%ad%e9%97%a8&sort=recommend&page_limit=20&page_start=0"
await page.goto(url);
while
(true){
/
/
循环点击, 直到获取不到该元素
try
{
await page.waitfor(
1000
);
await page.waitforselector(
'a[class=more]'
);
/
/
等待元素加载完成,超时时间
30000ms
await page.click(
"a[class=more]"
)
/
/
break
}catch(err){
console.log(err)
console.log(
"stop click !!!"
)
break
}
}
await page.waitfor(
1000
);
/
/
等待页面一秒
const links
=
await page.evaluate(()
=
> {
/
/
获取电影详情url
let movies
=
[...document.queryselectorall(
'.list a[class=item]'
)];
return
movies.
map
((movie)
=
>{
return
{
href: movie.href.trim(),
}
});
});
console.log(links.length)
for
(var i
=
0
; i < links.length; i
+
+
) {
const a
=
links[i];
await page.waitfor(
2000
);
await getdetail(brower, a.href)
/
/
break
}
await pupp.closepage(page)
await pupp.closebrower(brower)
}
async function getdetail(brower, url){
const page
=
await pupp.openpage(brower)
await page.goto(url);
await page.waitfor(
1000
);
try
{
await page.click(
".more-actor"
, {delay:
20
})
}catch(err){
console.log(err)
}
const frame
=
await page.mainframe()
const bodyhandle
=
await frame.$(
'html'
);
const html
=
await frame.evaluate(body
=
> body.innerhtml, bodyhandle);
await bodyhandle.dispose();
/
/
销毁
const $
=
cheerio.load(html)
const title
=
$(
"h1 span"
).text().trim()
const rating_num
=
$(
".rating_num"
).text().trim()
const data
=
{}
data[
"title"
]
=
title
data[
"rating_num"
]
=
rating_num
let info
=
$(
"#info"
).text()
const keyword
=
[
"director"
,
"screenplay"
,
"lead"
,
"type"
,
"website"
,
"location"
,
"language"
,
"playdate"
,
"playtime"
,
"byname"
,
"imdb"
]
if
(info.indexof(
"www."
) >
0
){
info
=
info.replace(
/
https:\
/
\
/
|http:\
/
\
/
/
g, "
").replace(/\t/g,"
").replace(/\r/g, "
").split("
:")
for
(var i
=
1
; i < info.length; i
+
+
){
data[keyword[i
-
1
]]
=
info[i].split(
/
\n
/
g)[
0
].replace(
/
\
/
/
g,
","
).trim()
}
}
else
{
info
=
info.replace(
/
\t
/
g,
" "
).replace(
/
\r
/
g,
" "
).split(
":"
)
keyword.splice(
4
,
1
)
for
(var i
=
1
; i < info.length
-
1
; i
+
+
){
data[keyword[i
-
1
]]
=
info[i].split(
/
\n
/
g)[
0
].replace(
/
\
/
/
g,
","
).trim()
}
data[
"website"
]
=
""
}
/
/
console.log(data)
mongoclient.connect(urls,function(err,db){
/
/
获取连接
assert
.equal(null,err);
/
/
使用断言模块代替以前的
if
判断
var dbo
=
db.db(
"douban"
);
dbo.collection(
"detail"
).insert(data, function(err,result){
/
/
连接到数据库上面,并使用参数传入集合
assert
.equal(null,err);
console.log(result);
db.close();
});
});
await pupp.closepage(page)
}
getlist()
|
以上的代码完成了对豆瓣热门电影的全部抓取,有以下几个步骤:
1, 循环点击加载更多,直到没有此元素可操作而抛出异常 。
2,加载完全部热门电影列表时解析出每个电影详情页的url并逐一请求 。
3, 解析详情页的所需数据, 。
4,对所抓取数据进行入库,这里使用mongodb 。
入库后的数据如下所示:
对以上的浏览器实例化做了优化,写成了单例模式 。
config.js 。
1
2
3
4
5
6
7
|
module.exports
=
{
browseroptions:{
headless: false,
/
/
args: [
'--no-sandbox'
,
'--proxy-server=http://proxy:abc100@cp.test.com:8995'
],
args: [
'--no-sandbox'
],
}
};
|
brower.js 。
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
|
const puppeteer
=
require(
"puppeteer"
);
const config
=
require(
'./config'
);
/
/
const deasync
=
require(
'deasync'
);
const browser_key
=
symbol.
for
(
'browser'
);
const browser_status_key
=
symbol.
for
(
'browser_status'
);
launch(config.browseroptions)
wait4lunch();
/
*
*
*
启动并获取浏览器实例
*
@param {
*
} options
*
param options
is
puppeteer.launch function's options
*
/
function launch(options
=
{}) {
if
(!
global
[browser_status_key]) {
global
[browser_status_key]
=
'lunching'
;
puppeteer.launch(options)
.then((browser)
=
> {
global
[browser_key]
=
browser;
global
[browser_status_key]
=
'lunched'
;
})
.catch((err)
=
> {
global
[browser_status_key]
=
'error'
;
throw err;
});
}
}
function wait4lunch(){
while
(!
global
[browser_key] &&
global
[browser_status_key]
=
=
'lunching'
) {
/
/
wait
for
lunch
deasync.runlooponce();
}
}
module.exports
=
global
[browser_key];
|
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我.
原文链接:https://blog.csdn.net/tilyp/article/details/80674559 。
最后此篇关于Puppeteer使用示例详解的文章就讲到这里了,如果你想了解更多关于Puppeteer使用示例详解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我最近刚跨过木偶继承。围绕它的几个问题: 使用p继承是一种好习惯吗?一些经验丰富的木偶同事告诉我,木偶的继承不是很好,我不太相信。 来自OO世界,我真的很想了解木偶继承的原理,以及覆盖的原理。 最佳答
需要一个 puppet 特工联系一些不同 puppet 师。 原因:不同的组创建了不同且独立的 list 集。 可能的组及其任务 应用程序供应商:应用程序的配置 安全性:强化 运营:路由表、监控工具
您可以在 puppet 中制作子模块吗,例如... puppet_root - modules - module_1 - submodule - manifes
在执行类 mypackage 中的代码之前,我需要执行类 mysql,tomcat。在我的 site.pp 我有 node 'node1' { include mysql,mypackage,tomc
我试图从失败的请求和js错误中收集数据。 我正在使用以下网站:https://nitzani1.wixsite.com/marketing-automation/3rd-page 该网站有一个对htt
我在 Suse 11 Linux 机器上使用 puppet 2.7.19 和 facter 1.6.0。 $::osfamily因子变量未设置,尽管它确实有 $::operatingsystem事实集
我正在使用 Puppet 开源版本。 我发现 Puppet 3.7.5 中有几个组件: puppet 大师 puppet 代理 MCollective 希拉 puppet 数据库 但我不知道他们是如何
主要目标是自动添加所有 puppet 模块,以便可以使用一个命令启动所有 dev-env 和 prod-env。如何通过 puppet manifest 安装 puppet 模块? 最佳答案 我们一直
我的 Puppet list 中有一系列 exec: 第一个下载带有二进制文件的 ZIP 文件(除非已经安装了二进制文件)并将其保存到 /tmp。 第二个将其解压缩。 当我第一次应用 list 时,它
我使用 aws opsworks 创建了 puppet master。我可以将 ami linux 节点自动添加到 puppet master。 当我尝试通过此链接 https://puppet.co
关于 this 的另一个问题问题。 有没有办法puppet module install从我已经下载到磁盘的本地存储库安装的工具? 最佳答案 您可以使用Puppet Library托管您自己的私有(p
我可以通过 Puppet Enterprise Master 到 Agent 运行几乎所有其他命令,但更新命令不会运行。据我所知,PE确实以root身份运行。 有人可以建议如何让这个命令在 Linux
我只想在 puppeteer 中刚刚打开的页面中应用标题,而不是在所有内部页面标题中应用标题 page.setExtraHTTPHeaders({ 'X-Just-Must-Be-Req
有没有什么方法可以用 Puppet 的语言声明数组中的包应该按照它们在数组中给出的顺序安装? 我想自动安装 CUDA,这需要 nvidia-driver-latest-dkms、cuda 和 cuda
鉴于这个简化的 Puppet 示例,很明显,由于 ~> 链接运算符,对 my_file 的任何更改都会触发 my_service 刷新: package { 'my_package': } -> fi
我是第一次使用 puppeteer,而不是工程师/程序员! 我已经能够生成我尝试使用 puppeteer 的大部分表单,但是我被单选按钮卡住了。网络表单中的开发人员工具显示该字段的以下内容: 使用:
如果您为代理在后台运行时执行 puppet agent -t,我们可以在其中看到更改的日志文件在哪里,而不是在 puppet 仪表板上。 我查看了 puppet.conf 并在主要部分看到了 logd
我正在尝试使用 exec 资源类型来执行批处理文件。但我想将变量 $dsn_64bit 的值从 init.pp 传递到 install.pp。请让我知道如何实现: 这是我的 init.pp class
我正在尝试使用 list 将用户分配到多个组,但遇到了障碍。 尝试 1: class usergroup { group { "user_one": ensure => present
我想先说我是 puppet 的新手。我一直在通过 vagrant 使用它并且我开始对写作表现感到自在,但我可能缺乏可以回答我的问题的经验或直觉。 我试图掌握 puppet 的范围以及画线的位置。我对这
我是一名优秀的程序员,十分优秀!