安装

python3 -m pip install pyppeteer

最好是py3.5+

手动安装

你懂的,天朝网络环境很复杂,如果要用pyppeteer自己绑定的chromium,半天都下载不下来,所以我们要手动安装,然后在程序里面指定executablePath

下载地址

模块介绍

启动pyppeteer.launch

launch 浏览器,可以传入一个字典来配置几个options,比如:

browser = await pyppeteer.launch({
'headless': False, # 关闭无头模式
'devtools': True, # 打开 chromium 的 devtools
// 'executablePath': '你下载的Chromium.app/Contents/MacOS/Chromiu', //# 浏览器的存放地址
'args': [
'--disable-extensions',
'--hide-scrollbars',
'--disable-bundled-ppapi-flash',
'--mute-audio',
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-gpu',
],
'dumpio': True,
})
browser = await launch({'headless': False,'dumpio':True, 'autoClose':False,'args': ['--no-sandbox', '--window-size=1366,850']})
await page.setViewport({'width':1366,'height':768})

注入脚本page.evaluate

await page.evaluate("""
() =>{
Object.defineProperties(navigator,{
webdriver:{
get: () => false
}
})
}
""")

我们会看到这一步非常关键,因为puppeteer出于政策考虑(这个词用的不是很好,就是那个意思)会设置window.navigator.webdrivertrue,告诉网站我是一个 webdriver 驱动的浏览器。有些网站比较聪明(反爬措施做得比较好),就会通过这个来判断对方是不是爬虫程序。

截获response和request

await page.setRequestInterception(True)
page.on('request', intercept_request)
page.on('response', intercept_response)

intercept_requestintercept_response相当于是注册的两个回调函数,在浏览器发出请求和获取到请求之前指向这两个函数。

比如可以这样禁止获取图片、多媒体资源和发起 websocket 请求:

async def intercept_request(req):
"""请求过滤"""
if req.resourceType in ['image', 'media', 'eventsource', 'websocket']:
await req.abort()
else:
await req.continue_()

然后每次获取到请求之后将内容打印出来(这里只打印了fetchxhr类型response 的内容):

async def intercept_response(res):
resourceType = res.request.resourceType
if resourceType in ['xhr', 'fetch']:
resp = await res.text()
print(resp)

一共有哪些resourceType,pyppeteer文档里面有:

页面自动下拉的代码

健壮的代码

请求钩子

async def request_check(req):
'''请求过滤'''
if req.resourceType in ['image', 'media', 'eventsource', 'websocket']:
await req.abort()
else:
await req.continue_() await page.setRequestInterception(True)
page.on('request', request_check)

判断加载是否完成

async def goto(page, url):
while True:
try:
await page.goto(url, {
'timeout': 0,
'waitUntil': 'networkidle0'
})
break
except (pyppeteer.errors.NetworkError,
pyppeteer.errors.PageError) as ex:
# 无网络 'net::ERR_INTERNET_DISCONNECTED','net::ERR_TUNNEL_CONNECTION_FAILED'
if 'net::' in str(ex):
await asyncio.sleep(10)
else:
rais

注入JS文件

from pathlib import Path

CURDIR = Path(__file__).parent
JS_AJAX_HOOK_LIB = str(CURDIR / 'static' / 'ajaxhook.min.js') await page.addScriptTag(path=JS_AJAX_HOOK_LIB)

这样注入的js文件不能有中文,因为 pyppeteer 里面打开文件用的是默认编码,可以 hook 住

open 函数来解决。

# 因为 pyppeteer 库里面 addScriptTag 用的是系统默认编码,导致js文件里面不能有中文
pyppeteer.frame_manager.open = lambda file: open(file, encoding='utf8')

完整的跑一个小项目

import asyncio
from pyppeteer import launch
import time async def main():exepath = 'C:/Users/tester02/AppData/Local/Google/Chrome/Application/chrome.exe'
browser = await launch({'executablePath': exepath, 'headless': False, 'slowMo': 30})
page = await browser.newPage()
await page.setViewport({'width': 1366, 'height': 768})
await page.goto('http://192.168.2.66') // # 请求网址
await page.type("#Login_Name_Input", "test02") # 第一个参数是选择器,选中某个元素,第二个参数是要输入的内容
await page.type("#Login_Password_Input", "12345678", )
await page.waitFor(1000) # 停顿
await page.click("#Login_Login_Btn")
await page.waitFor(3000)
await browser.close()# 关闭浏览器 asyncio.get_event_loop().run_until_complete(main()) # 执行main函数

登陆谷歌

import asyncio
import time
from pyppeteer import launch async def gmailLogin(username, password, url):
#'headless': False如果想要浏览器隐藏更改False为True
# 127.0.0.1:1080为代理ip和端口,这个根据自己的本地代理进行更改,如果是vps里或者全局模式可以删除掉'--proxy-server=127.0.0.1:1080'
browser = await launch({'headless': False, 'args': ['--no-sandbox', '--proxy-server=127.0.0.1:1080']})
page = await browser.newPage()
await page.setUserAgent(
'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36') await page.goto(url) # 输入Gmail
await page.type('#identifierId', username)
# 点击下一步
await page.click('#identifierNext > content')
page.mouse # 模拟真实点击
time.sleep(10)
# 输入password
await page.type('#password input', password)
# 点击下一步
await page.click('#passwordNext > content > span')
page.mouse # 模拟真实点击
time.sleep(10)
# 点击安全检测页面的DONE
# await page.click('div > content > span')#如果本机之前登录过,并且page.setUserAgent设置为之前登录成功的浏览器user-agent了,
# 就不会出现安全检测页面,这里如果有需要的自己根据需求进行更改,但是还是推荐先用常用浏览器登录成功后再用python程序进行登录。 # 登录成功截图
await page.screenshot({'path': './gmail-login.png', 'quality': 100, 'fullPage': True})
#打开谷歌全家桶跳转,以Youtube为例
await page.goto('https://www.youtube.com')
time.sleep(10) if __name__ == '__main__':
username = '你的gmail包含@gmail.com'
password = r'你的gmail密码'
url = 'https://gmail.com'
loop = asyncio.get_event_loop()
loop.run_until_complete(gmailLogin(username, password, url))
# 代码由三分醉编写,网址www.sanfenzui.com,参考如下文章:
# https://blog.csdn.net/Chen_chong__/article/details/82950968

登陆淘宝

async def taobao_login(username, password, url):
"""
淘宝登录主程序
:param username: 用户名
:param password: 密码
:param url: 登录网址
:return: 登录cookies
"""
###
await page.click('#J_QRCodeLogin > div.login-links > a.forget-pwd.J_Quick2Static')
page.mouse
time.sleep(1)
# 输入用户名,密码
await page.type('#TPL_username_1', username, {'delay': input_time_random() - 50}) # delay是限制输入的时间
await page.type('#TPL_password_1', password, {'delay': input_time_random()})
time.sleep(2)
# 检测页面是否有滑块。原理是检测页面元素。
slider = await page.Jeval('#nocaptcha', 'node => node.style') # 是否有滑块 if slider:
print('当前页面出现滑块')
# await page.screenshot({'path': './headless-login-slide.png'}) # 截图测试
flag, page = await mouse_slide(page=page) # js拉动滑块过去。
if flag:
await page.keyboard.press('Enter') # 确保内容输入完毕,少数页面会自动完成按钮点击
print("print enter", flag)
await page.evaluate('''document.getElementById("J_SubmitStatic").click()''') # 如果无法通过回车键完成点击,就调用js模拟点击登录按钮。
time.sleep(2)
cookies_list = await page.cookies()
print(cookies_list)
return await get_cookie(page) # 导出cookie 完成登陆后就可以拿着cookie玩各种各样的事情了。
else:
print("")
await page.keyboard.press('Enter')
print("print enter")
await page.evaluate('''document.getElementById("J_SubmitStatic").click()''')
await page.waitFor(20)
await page.waitForNavigation() try:
global error # 检测是否是账号密码错误
print("error_1:", error)
error = await page.Jeval('.error', 'node => node.textContent')
print("error_2:", error)
except Exception as e:
error = None
finally:
if error:
print('确保账户安全重新入输入')
# 程序退出。
loop.close()
else:
print(page.url)
return await get_cookie(page)

今日头条文章

import asyncio
from pyppeteer import launch async def main():
# headless参数设为False,则变成有头模式
browser = await launch(
# headless=False
) page = await browser.newPage() # 设置页面视图大小
await page.setViewport(viewport={'width':1280, 'height':800}) # 是否启用JS,enabled设为False,则无渲染效果
await page.setJavaScriptEnabled(enabled=True) await page.goto('https://www.toutiao.com/') # 打印页面cookies
print(await page.cookies()) # 打印页面文本
print(await page.content()) # 打印当前页标题
print(await page.title()) # 抓取新闻标题
title_elements = await page.xpath('//div[@class="title-box"]/a')
for item in title_elements:
# 获取文本
title_str = await (await item.getProperty('textContent')).jsonValue()
print(await item.getProperty('textContent'))
# 获取链接
title_link = await (await item.getProperty('href')).jsonValue()
print(title_str)
print(title_link) # 关闭浏览器
await browser.close() asyncio.get_event_loop().run_until_complete(main())

Pyppeteer和Puppeteer的不同点

  1. Pyppeteer支持字典和关键字传参,Puppeteer只支持字典传参
# Puppeteer只支持字典传参
browser = await launch({'headless': True})
# Pyppeteer支持字典和关键字传参
browser = await launch({'headless': True})
browser = await launch(headless=True)
  1. 元素选择器方法名 $变为querySelector
# Puppeteer使用$符
Page.$()/Page.$$()/Page.$x()
# Pyppeteer使用Python风格的函数名
Page.querySelector()/Page.querySelectorAll()/Page.xpath()
# 简写方式为:
Page.J(), Page.JJ(), and Page.Jx()
  1. Page.evaluate() 和 Page.querySelectorEval()的参数

Puppeteer的evaluate()方法使用JavaScript原生函数或JavaScript表达式字符串。Pyppeteer的evaluate()方法只使用JavaScript字符串,该字符串可以是函数也可以是表达式,Pyppeteer会进行自动判断。但有时会判断错误,如果字符串被判断成了函数,并且报错,可以添加选项force_expr=True,强制Pyppeteer作为表达式处理。

获取页面内容:

content = await page.evaluate('document.body.textContent', force_expr=True)

获取元素的内部文字:

element = await page.querySelector('h1')
title = await page.evaluate('(element) => element.textContent', element)

爬虫例子

# -*- coding: utf-8 -*-

import asyncio
from pyppeteer import launch
from pyquery import PyQuery as pq # 最好指定一下自己浏览器的位置,如果不指定会自动下载,太慢了...
executable_path = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" # 示例一: 渲染页面
async def crawl_page():
# 打开浏览器
browser = await launch(executablePath=executable_path) # 打开tab
page = await browser.newPage() # 输入网址回车
await page.goto('http://quotes.toscrape.com/js/') # 获取内容并解析
doc = pq(await page.content())
print('Quotes:', doc('.quote').length) # 关闭浏览器
await browser.close() # 示例二:截图,保存pdf,执行js
async def save_pdf():
browser = await launch(executablePath=executable_path)
page = await browser.newPage()
await page.goto('http://quotes.toscrape.com/js/') # 网页截图保存
await page.screenshot(path='example.png') # 网页导出 PDF 保存
await page.pdf(path='example.pdf') # 执行 JavaScript
dimensions = await page.evaluate('''() => {
return {
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight,
deviceScaleFactor: window.devicePixelRatio,
}
}''') print(dimensions) await browser.close() if __name__ == '__main__':
asyncio.get_event_loop().run_until_complete(crawl_page())
# asyncio.get_event_loop().run_until_complete(save_pdf(

如何建立一个cookie池

必须多个账号,那么如何注册多个淘宝账号呢。。

  1. 可以通过第三方提供手机号验证码服务商,通过pyppeteer注册账号,保存账号信息
  2. 登录账号并保存在redis
  3. 开线程检查账号是否已过期,若过期重新登录即可

爬虫的新模块pyppeteer的使用的更多相关文章

  1. python爬虫主要就是五个模块:爬虫启动入口模块,URL管理器存放已经爬虫的URL和待爬虫URL列表,html下载器,html解析器,html输出器 同时可以掌握到urllib2的使用、bs4(BeautifulSoup)页面解析器、re正则表达式、urlparse、python基础知识回顾(set集合操作)等相关内容。

    本次python爬虫百步百科,里面详细分析了爬虫的步骤,对每一步代码都有详细的注释说明,可通过本案例掌握python爬虫的特点: 1.爬虫调度入口(crawler_main.py) # coding: ...

  2. asynicio模块以及爬虫应用asynicio模块(高性能爬虫)

    一.背景知识 爬虫的本质就是一个socket客户端与服务端的通信过程,如果我们有多个url待爬取,只用一个线程且采用串行的方式执行,那只能等待爬取一个结束后才能继续下一个,效率会非常低. 需要强调的是 ...

  3. 孤荷凌寒自学python第六十七天初步了解Python爬虫初识requests模块

    孤荷凌寒自学python第六十七天初步了解Python爬虫初识requests模块 (完整学习过程屏幕记录视频地址在文末) 从今天起开始正式学习Python的爬虫. 今天已经初步了解了两个主要的模块: ...

  4. 八、asynicio模块以及爬虫应用asynicio模块(高性能爬虫)

    asynicio模块以及爬虫应用asynicio模块(高性能爬虫) 一.背景知识 爬虫的本质就是一个socket客户端与服务端的通信过程,如果我们有多个url待爬取,只用一个线程且采用串行的方式执行, ...

  5. Python爬虫之urllib模块2

    Python爬虫之urllib模块2 本文来自网友投稿 作者:PG-55,一个待毕业待就业的二流大学生. 看了一下上一节的反馈,有些同学认为这个没什么意义,也有的同学觉得太简单,关于Beautiful ...

  6. Python爬虫之urllib模块1

    Python爬虫之urllib模块1 本文来自网友投稿.作者PG,一个待毕业待就业二流大学生.玄魂工作室未对该文章内容做任何改变. 因为本人一直对推理悬疑比较感兴趣,所以这次爬取的网站也是平时看一些悬 ...

  7. springboot~添加新模块的方法

    在springboot项目框架里,把一个项目两大模块,主项目main和测试项目test,而我们的测试项目根据功能又可以再分,比如可以有单元测试,集成测试,业务测试等等. 对于一个初学者来说,建立模块的 ...

  8. Anaconda安装新模块

    如果使用import导入的新模块没有安装,则会报错,下面是使用Anaconda管理进行安装的过程:1.打开Anaconda工具,如图: 2.可通过输入 conda list 查看已安装的模块 3.如果 ...

  9. ecmall 开发一个新模块

    要开发新模块,要借鉴原有模块的代码并进行修改. 首先打开目录external/modules 会有一个datacall文件夹,这个文件夹对应的就是一个模块. 复制datacall文件夹,重命名为tes ...

随机推荐

  1. ELK之elasticsearch删除索引

    参考文档:https://www.cnblogs.com/Dev0ps/p/9493576.html elasticsearch使用时间久了会产生大量索引占用磁盘空间,可以删除索引来释放 查看当前所有 ...

  2. 【ARTS】01_34_左耳听风-201900701~201900707

    ARTS: Algrothm: leetcode算法题目 Review: 阅读并且点评一篇英文技术文章 Tip/Techni: 学习一个技术技巧 Share: 分享一篇有观点和思考的技术文章 Algo ...

  3. Centos中阿里云yum源配置

    centos中阿里云yum源配置 1.首先备份系统自带yum源配置文件/etc/yum.repos.d/CentOS-Base.repo mv /etc/yum.repos.d/CentOS-Base ...

  4. [转帖][思路/技术]Mimikatz的多种攻击方式以及防御方式

    [思路/技术]Mimikatz的多种攻击方式以及防御方式 https://bbs.ichunqiu.com/thread-53954-1-1.html 之前学习过 抄密码 没想到还有这么多功能.   ...

  5. [转帖]删除一张大表时为什么undo占用空间接近原表两倍?

    删除一张大表时为什么undo占用空间接近原表两倍? https://www.toutiao.com/i6736735016492990983/ 原创 波波说运维 2019-09-22 00:01:00 ...

  6. Python基础系列讲解——时间模块详解大全之time模块

    Python中提供处理时间日期相关的内置模块有time.datetime和calendar. time模块中大多数函数调用了所在平台C library 的同名函数,因此更依赖于操作系统层面,所以tim ...

  7. 服务提供者框架讲解 之 myJDBC

    利用一个简单的myJDBC,讲一下'服务提供者框架'的思想.主要是思想 目录 什么是 服务提供者框架 代码讲解 服务接口 服务提供者接口 服务注册API.服务访问API 静态工厂方法 服务实现类 – ...

  8. PAT(B) 1012 数字分类(Java)

    题目链接:1012 数字分类 代码 /** * Score 20 * Run Time 142ms * @author wowpH * @version 1.1 */ import java.util ...

  9. 1,electron搭建

    electron可以用js来创建丰富的桌面应用 一个electron应用的目录结构 your-app/ ├── package.json ├── main.js └── index.html 1,安装 ...

  10. Message高级特性

    一.延迟和定时消息投递 1 xml中配置schedulerSupport属性为true 2 每小时都会发生消息被投递10次,延迟1秒开始,每次间隔1秒: TextMessage message = s ...