别只用 Selenium,新神器 Pyppeteer 更强大!

现在大多数人在使用模拟浏览器进行数据获取的时候, 用的都是Selenium .以至于现在很多网站已经对它做了很多针对性的反爬(比如检测浏览器的webdriver属性). 而Pyppeteer 作为一个新的工具在绕过这些反爬措施中表现的很好. 本文借鉴了部分'原创: 崔庆才  进击的Coder, 别只用 Selenium,新神器 Pyppeteer 绕过淘宝更简单!' 的内容. 所以很多细节的东西就不说了, 主要记录一下在使用Pyppeteer 时遇到的一些问题和处理方法.
附上Pyppeteer的文档地址: https://miyakogi.github.io/pyppeteer/#
大家可能接触过Puppeteer, Puppeteer 是 Google 基于 Node.js 开发的一个工具,有了它我们可以通过 JavaScript 来控制 Chrome 浏览器的一些操作,当然也可以用作网络爬虫上,其 API 极其完善,功能非常强大。 而 Pyppeteer 又是什么呢?它实际上是 Puppeteer 的 Python 版本的实现,但他不是 Google 开发的,是一位来自于日本的工程师依据 Puppeteer 的一些功能开发出来的非官方版本。

安装

首先就是安装问题了,由于 Pyppeteer 采用了 Python 的 async 机制,所以其运行要求的 Python 版本为 3.5 及以上。
​
安装方式非常简单:
​
pip3 install pyppeteer
好了,安装完成之后我们命令行下测试下:
​
>>> import pyppeteer
如果没有报错,那么就证明安装成功了。python -c 'import pyppeteer; pyppeteer.chromium_downloader.download_chromium()'   直接下载pyppeteer

快速上手

import asyncio
from pyppeteer import launch
from pyquery import PyQuery as pq
​
async def main():browser = await launch()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()
​
asyncio.get_event_loop().run_until_complete(main())
那么这里面的过程发生了什么?
​
实际上,Pyppeteer 整个流程就完成了浏览器的开启、新建页面、页面加载等操作。另外 Pyppeteer 里面进行了异步操作,所以需要配合 async/await 关键词来实现。
​
首先, launch 方法会新建一个 Browser 对象,然后赋值给 browser,然后调用 newPage  方法相当于浏览器中新建了一个选项卡,同时新建了一个 Page 对象。然后 Page 对象调用了 goto 方法就相当于在浏览器中输入了这个 URL,浏览器跳转到了对应的页面进行加载,加载完成之后再调用 content 方法,返回当前浏览器页面的源代码。然后进一步地,我们用 pyquery 进行同样地解析,就可以得到 JavaScript 渲染的结果了。
​
另外其他的一些方法如调用 asyncio 的 get_event_loop 等方法的相关操作则属于 Python 异步 async 相关的内容了,大家如果不熟悉可以了解下 Python 的 async/await 的相关知识。
​
好,通过上面的代码,我们就可以完成 JavaScript 渲染页面的爬取了。

webdriver 检测问题怎样来解决呢?其实这类网站主要通过 window.navigator.webdriver 来对 webdriver 进行检测,所以我们只需要使用 JavaScript 将它设置为 false 即可,代码如下:

class GetJsEncryptPage():
​def __init__(self):self.loop = asyncio.get_event_loop()self.log = ICrawlerLog('spider').save
​async def main(self, url, ):  # 定义main协程函数,# 以下使用await 可以针对耗时的操作进行挂起browser = await launch({'headless': True, 'args': ['--no-sandbox', '--disable-infobars',# '--proxy-server={}'.format(get_ip()),],})  # 启动pyppeteer 属于内存中实现交互的模拟器page = await browser.newPage()  # 启动个新的浏览器页面标签await page.setUserAgent("Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36")cookies = {}try:await page.goto(url)  # 访问页面# 始终让window.navigator.webdriver=false# navigator是windiw对象的一个属性,同时修改plugins,languages,navigator 且让# await page.setJavaScriptEnabled(enabled=True)  # 使用 JS 渲染await page.evaluate('''() =>{ Object.defineProperties(navigator,{ webdriver:{ get: () => false } }) }''')  # 以下为插入中间js,将淘宝会为了检测浏览器而调用的js修改其结果。await page.evaluate('''() =>{ window.navigator.chrome = { runtime: {},  }; }''')await page.evaluate('''() =>{ Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] }); }''')await page.evaluate('''() =>{ Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5,6], }); }''')await page.goto(url)  # 访问页面# content = await page.content()  # 获取页面内容await asyncio.sleep(2)except:await page.evaluate('''() =>{ Object.defineProperties(navigator,{ webdriver:{ get: () => false } }) }''')await page.evaluate('''() =>{ window.navigator.chrome = { runtime: {},  }; }''')await page.evaluate('''() =>{ Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] }); }''')await page.evaluate('''() =>{ Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5,6], }); }''')# await page.evaluate('window.open("{}");'.format(url))await page.evaluate('window.location="{}";'.format(url))# await page.goto(url)  # 访问登录页面try:cookies = await self.get_cookie(page)except Exception as e:await browser.close()finally:await browser.close()
​return cookies
​async def get_cookie(self, page):# res = await page.content()cookies_list = await page.cookies()cookies = {}for cookie in cookies_list:cookies[cookie.get('name')] =  cookie.get('value')return cookies
​def retry_if_result_none(self, result):return result is None
​def input_time_random(self, ):return random.randint(100, 151)
​def work(self, url):pass
​def run(self, url, func):result = {}try:# task = asyncio.wait([])result = self.loop.run_until_complete(func(url))  # 将协程注册到事件循环,并启动事件循环except Exception as e:self.log.info('协程被动结束, chrome关闭')for task in asyncio.Task.all_tasks():task.cancel()self.loop.stop()self.loop.run_forever()# self.loop.close()return result

需求一: 请求网页时, 遇到到网络异常 --> 自定义page.goto请求

async def goto(self, page, url):while True:try:await page.goto(url, {'timeout': 0, 'waitUntil': 'networkidle0'})breakexcept (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:raise

需求二: Pyppeteer执行JS 获取返回值

修改浏览器属性
async def change_status(self, page):  await page.evaluate('''() =>{ Object.defineProperties(navigator,{ webdriver:{ get: () => false } }) }''')await page.evaluate('''() =>{ window.navigator.chrome = { runtime: {},  }; }''')await page.evaluate('''() =>{ Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] }); }''')await page.evaluate('''() =>{ Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5,6], }); }''')----------------------------------------
执行JS
await page.evaluate('''() =>{ return 'python' } }) }''')

需求三: page.on监听请求与响应, 并对请求和响应进行修改和过滤

page.on(event, function) ,指定监听事件, 与处理函数
例如: page.on('request', intercept_response)
​
# 请求处理函数
async def request_check(req):'''请求过滤'''if req.resourceType in ['image', 'media', 'eventsource', 'websocket']:await req.abort()else:await req.continue_()
​
# 响应处理函数
async def intercept_response(res):resourceType = res.request.resourceTypeif resourceType in ['image', 'media']:resp = await res.text()print(resp)
​

需求四: 进行网页截图

# 依据Xpath 进行网页截图
async def get_picture(page, xpath):# 进行截图picture = ''try:for _ in range(6):tdContent = await page.xpath(xpath)clip = await tdContent[0].boundingBox()picture = base64.b64encode(await page.screenshot({'path': './dashboard_shot.png',                  # 图片路径, 不指定就不保存'clip': clip,                                     # 指定图片位置,大小# 'encoding': 'base64',                           #  返回的图片格式, 默认二进制}))if picture != '':breakexcept Exception as e:self.log.info('截图获取失败')return picture

需求五: 初始化, 设置代理IP, 设置浏览器UA, 设置浏览器大小, 设置无头浏览

browser = await launch({'headless': True, 'timeout': 500, 'args': ['--disable-extensions','--hide-scrollbars','--disable-bundled-ppapi-flash','--mute-audio','--no-sandbox',  '--disable-setuid-sandbox','--disable-gpu',  '--proxy-server={}'.format(get_ip()),], })
page = await browser.newPage()
await page.setUserAgent("Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36")
await page.setViewport({'width': 1000,'height': 3480,})

需求六: 获取浏览器依据加载的图片内容, Selenium与Pyppeteer相同

 执行JS, 返回图片的二进制的Base64编码, 参照: https://www.w3ctech.com/topic/767
'''
() => {
var img = document.getElementById("%s");
var canvas = document.createElement("canvas");
canvas.width = %s;
canvas.height = %s;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
var dataURL = canvas.toDataURL("image/png");
return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");}''' % (id, width, height)

需求七: 切换浏览器的tag

在Pyppeteer中每一个标签页就是一个page对象, 切换page对象就是切换标签页
for _page in await browser.pages() :if _page != page:await _page.close()

学习记录, 带你玩转Pyppeteer (全干货)相关推荐

  1. 深度学习手势识别带你玩转神庙逃亡

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 来源 | 公众号「开源中国」 随着经济社会的进步,人们对 ...

  2. A-level 计算机科学学习记录:系统软件system software(全英)

    目录 introduction Operating system memory management Interrupt schedulling First Come First Serve (FIF ...

  3. 收藏 | 100+篇大数据学习资讯,带你玩转大数据分析!

    2019独角兽企业重金招聘Python工程师标准>>> 深度解析如何挑选适合自己的Hadoop平台 什么是Hadoop,怎样学习Hadoop 分布式文件系统HDFS解析 Hadoop ...

  4. (私人收藏)[开发必备]HTML5最全快速查找离线手册(可查询可学习,带实例)...

    [开发必备]HTML5最全快速查找离线手册(可查询可学习,带实例) HTML5最全快速查找离线手册:https://pan.baidu.com/s/19seE8TJQSx4IsWgXtKQS0A j9 ...

  5. (私人收藏)[开发必备]最全JQuery离线快速查找手册(可查询可学习,带实例)

    [开发必备]最全JQuery离线快速查找手册(可查询可学习,带实例) https://pan.baidu.com/s/16bUd4iA3p0c5RHbzaC60IQ e4zh

  6. 金士顿固态硬盘不认盘修复_#原创新人#老司机带你玩转PC,故障之SSD篇 篇一:金士顿 V300 240G SATA3 固态硬盘 丢盘掉速解决记录...

    #原创新人#老司机带你玩转PC,故障之SSD篇 篇一:金士顿 V300 240G SATA3 固态硬盘 丢盘掉速解决记录 2016-10-25 11:14:08 12点赞 72收藏 23评论 小编注: ...

  7. 来吧!带你玩转 Excel VBA

    来吧!带你玩转 Excel VBA(含CD光盘1张)(双色)(附带近500个VBA思考练习题,Exceltip.net出品) 罗刚君  杨嘉恺编著 ISBN 978-7-121-20627-6 201 ...

  8. 21.08.01 cnvoron带你玩转Voron2.4

    树哥带你玩Voron之用蜘蛛8轴主板玩转Voron2.4 ​ 2021.08.01 第一版 ​ 本教程版权所有,未经许可,切勿用作商业用途,违者必究! ​ ​ VORON2.4使用者(大树-执笔) 文 ...

  9. 微信小游戏开发学习记录2

    接上一篇:微信小游戏开发学习记录_寂静流年韶华舞的博客-CSDN博客_微信小游戏开发学习 目录 一.UI系统 1.基础渲染组件-精灵组件 (1)操作: (2)Sprite 属性 (3)渲染模式 2.L ...

最新文章

  1. Mongodb的权限管理
  2. 业界丨2018深度学习十大趋势:元学习成新SGD,多数硬件创企将失败
  3. ucache来广营(望京)机房
  4. vuex 编译项目_俺咋能看懂公司前端项目?
  5. 禁用浏览器滚动条的解决方案
  6. python3.7 安装pip3_Ubuntu16.04 安装python3.7和pip3
  7. android 置顶窗口位置,Android 滑动悬浮置顶指南
  8. RMAN catalog 的创建和使用
  9. 单元测试 jest 从零开始搭建简易的单元测试
  10. Python - shutil模块(2)——压缩目录、文件
  11. 消息中间件的使用场景
  12. Kubernetes集群管理部署
  13. dell自带的测试软件,Dell System Detect
  14. 阿里云CentOS7服务器搭建邮件服务器,端口:465
  15. Kettle的改名由来
  16. 华为云服务器安全组端口开放教程
  17. 前端程序员从菜鸟到大神必学的七本前端书籍
  18. so库你应该知道的基础知识
  19. csr867x入门之按键配置(九)
  20. 《白帽子讲Web安全》memo0

热门文章

  1. 使用python的turtle库画表情包
  2. 2023最新最全vscode插件精选
  3. 引流效果差?一文详解轻松获取优质流量的两大要点
  4. 物流快递发货单接口API代码-快递100API
  5. cadence 旋转快捷键_cadence快捷键
  6. 蓝桥杯之单片机设计与开发(18)——模数转换A/D与数模转换D/A
  7. Python 创建加密压缩文件
  8. python逆向爬取网易云评论进行情感分析!网易评论才是高手
  9. Android华为推送踩坑,极光推送集成华为遇到的坑?
  10. 计算机颜色显示器,电脑显示器怎么选,看这一篇就够了