安装

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. Spring Cloud(6.2):搭建OAuth2 Client

    配置web.xml 添加spring-cloud-starter-security,spring-security-oauth2-autoconfigure和spring-boot-starter-o ...

  2. nginx限流方案的实现(三种方式)

    通过查看nginx官方文档,小弟查看到了三种nginx限流方式. 1.limit_conn_zone 2.limit_req_zone 3.ngx_http_upstream_module 前两种只能 ...

  3. linux SSH 隧道

    一 什么是SSH隧道 首 先看下面这张图,我们所面临的大部分情况都和它类似.我们的电脑在右上角,通过公司带有防火墙功能的路由器接入互联网(当然可能还有交换机什么的在中间连 接着你和路由器,但是在我们的 ...

  4. vue启动时报 This relative module was not found

    This relative module was not found: * ../../vue-temp/vue-editor-bridge in ./node_modules/babel-loade ...

  5. [学习笔记] Blender layout 视图切换

    layout 数字键5  --- 正交视图/透视图 切换 数字键0 -- 摄像机视图 数字键7 -- 顶视图 数字键1 --- 前视图 数字键3 --- 右视图 ctrl +数字键3 --- 左视图 ...

  6. [翻译向] 当flush privileges生效时

    #前言: 最近频繁在mysql权限控制这里栽跟斗,在翻阅了一些资料之后,简单地翻译一下官网关于flush privileges的描述,抛砖引玉.   #翻译正文: If the mysqld serv ...

  7. v-bind 绑定属性

    与mustache相区别,他是对内容(content内部)进行修改的.v-bind的语法糖写法是   : v-bind 动态绑定class属性:v-bind:class="对象名" ...

  8. js 读取文本文件,日志内容

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  9. Feign【首次请求失败】

    当feign和ribbon整合hystrix之后,可能会出现首次调用失败的问题,出现原因分析如下: hystrix默认的超时时间是1秒,如果接口请求响应超过这个时间,将会执行fallback,spri ...

  10. 【C++札记】new和delete

    介绍 1.malloc,free和new,delete区别. a.malloc,free是C/C++的标准库函数.new,delete是c++的操作符. b.malloc申请的是内存,严格意义不是&q ...