(十九) Pyppeteer模块的基本使用

 

引言

Selenium 在被使用的时候有个麻烦事,就是环境的相关配置,得安装好相关浏览器,比如 Chrome、Firefox 等等,然后还要到官方网站去下载对应的驱动,最重要的还需要安装对应的 Python Selenium 库,确实是不是很方便,另外如果要做大规模部署的话,环境配置的一些问题也是个头疼的事情。那么本节就介绍另一个类似的替代品,叫做 Pyppeteer。

Pyppeteer简介

注意,本节讲解的模块叫做 Pyppeteer,不是 Puppeteer。Puppeteer 是 Google 基于 Node.js 开发的一个工具,有了它我们可以通过 JavaScript 来控制 Chrome 浏览器的一些操作,当然也可以用作网络爬虫上,其 API 极其完善,功能非常强大。 而 Pyppeteer 又是什么呢?它实际上是 Puppeteer 的 Python 版本的实现,但他不是 Google 开发的,是一位来自于日本的工程师依据 Puppeteer 的一些功能开发出来的非官方版本。

在 Pyppetter 中,实际上它背后也是有一个类似 Chrome 浏览器的 Chromium 浏览器在执行一些动作进行网页渲染,首先说下 Chrome 浏览器和 Chromium 浏览器的渊源。

 

Chromium 是谷歌为了研发 Chrome 而启动的项目,是完全开源的。二者基于相同的源代码构建,Chrome 所有的新功能都会先在 Chromium 上实现,待验证
稳定后才会移植,因此 Chromium 的版本更新频率更高,也会包含很多新的功能,但作为一款独立的浏览器,Chromium 的用户群体要小众得多。两款浏览
器“同根同源”,它们有着同样的 Logo,但配色不同,Chrome 由蓝红绿黄四种颜色组成,而 Chromium 由不同深度的蓝色构成。

 

 Pyppeteer 就是依赖于 Chromium 这个浏览器来运行的。那么有了 Pyppeteer 之后,我们就可以免去那些繁琐的环境配置等问题。如果第一次运行的时候,Chromium 浏览器没有安装,那么程序会帮我们自动安装和配置,就免去了繁琐的环境配置等工作。另外 Pyppeteer 是基于 Python 的新特性 async 实现的,所以它的一些执行也支持异步操作,效率相对于 Selenium 来说也提高了。

环境安装

由于 Pyppeteer 采用了 Python 的 async 机制,所以其运行要求的 Python 版本为 3.5 及以上

pip3 install pyppeteer

快速上手

例: 爬取http://quotes.toscrape.com/js/ 全部页面数据

import asyncio
from pyppeteer import launch
from lxml import etree

async def main():
    browser = await launch()  # 新建一个browser对象
    page = await browser.newPage()  # 在浏览器中新建一个选项卡
    await page.goto('http://quotes.toscrape.com/js/')  # 在浏览器中输入URL,相当于selenium里面的get
    page_text = await page.content()  # 使用.content()方法获取页面源码
    tree = etree.HTML(page_text)
    div_list = tree.xpath('//div[@class="quote"]')
    print(len(div_list))

    await browser.close()  # 关闭浏览器

asyncio.get_event_loop().run_until_complete(main())

运行结果:10
解释:launch 方法会新建一个 Browser 对象,然后赋值给 browser,然后调用 newPage 方法相当于浏览器中新建了一个选项卡,同时新建了一个 Page 对象。然后 Page 对象调用了 goto 方法就相当于在浏览器中输入了这个 URL,浏览器跳转到了对应的页面进行加载,加载完成之后再调用 content 方法,返回当前浏览器页面的源代码。然后进一步地,我们用 pyquery 进行同样地解析,就可以得到 JavaScript 渲染的结果了。在这个过程中,我们没有配置 Chrome 浏览器,没有配置浏览器驱动,免去了一些繁琐的步骤,同样达到了 Selenium 的效果,还实现了异步抓取,爽歪歪!

详细用法

开启浏览器,调用 launch 方法即可,相关参数介绍:

ignoreHTTPSErrors (bool):  是否要忽略 HTTPS 的错误,默认是 False。

headless (bool):  是否启用 Headless 模式,即无界面模式,如果 devtools 这个参数是 True 的话,那么该参数就会被设置为 False,否则为 True,即默认是开启无界面模式的。

executablePath (str):  可执行文件的路径,如果指定之后就不需要使用默认的 Chromium 了,可以指定为已有的 Chrome 或 Chromium。

args (List[str]):  在执行过程中可以传入的额外参数。

devtools (bool):  是否为每一个页面自动开启调试工具,默认是 False。如果这个参数设置为 True,那么 headless 参数就会无效,会被强制设置为 False。

关闭提示条:”Chrome 正受到自动测试软件的控制”,这个提示条有点烦,那咋关闭呢?这时候就需要用到 args 参数了,禁用操作如下:

browser = await launch(headless=False, args=['--disable-infobars'])

处理页面显示问题:访问淘宝首页

import asyncio
from pyppeteer import launch

async def main():
    browser = await launch(headless=False)
    page = await browser.newPage()
    await page.goto('https://www.taobao.com')
    await asyncio.sleep(10)

asyncio.get_event_loop().run_until_complete(main())

发现页面显示出现了问题,需要手动调用setViewport方法设置显示页面的长宽像素。设置如下:

import asyncio
from pyppeteer import launch
 
width, height = 1366, 768
 
async def main():
    browser = await launch(headless=False)
    page = await browser.newPage()
    await page.setViewport({'width': width, 'height': height})
    await page.goto('https://www.taobao.com')
    await asyncio.sleep(3)
 
asyncio.get_event_loop().run_until_complete(main())

执行js程序:拖动滚轮。调用evaluate方法。

import asyncio
from pyppeteer import launch
width, height = 1366, 768

async def main():
    browser = await launch(headless=False)
    page = await browser.newPage()
    await page.setViewport({'width': width, 'height': height})
    await page.goto('https://movie.douban.com/typerank?type_name=%E5%8A%A8%E4%BD%9C&type=5&interval_id=100:90&action=')
    await asyncio.sleep(3)
# evaluate可以返回js程序的返回值 dimensions = await page.evaluate('window.scrollTo(0,document.body.scrollHeight)') await asyncio.sleep(3) print(dimensions) await browser.close() asyncio.get_event_loop().run_until_complete(main())

规避webdriver检测

import asyncio
from pyppeteer import launch

async def main():
    browser = await launch(headless=False, args=['--disable-infobars'])
    page = await browser.newPage()
    await page.goto('https://login.taobao.com/member/login.jhtml?redirectURL=https://www.taobao.com/')
    await page.evaluate( '''() =>{ Object.defineProperties(navigator,{ webdriver:{ get: () => false } }) }''')
    await asyncio.sleep(10)

asyncio.get_event_loop().run_until_complete(main())

UA伪装

await self.page.setUserAgent('xxx')

节点交互

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})

    await page.goto('https://www.baidu.com/')
    # 节点交互
    await page.type('#kw','周杰伦',{'delay': 1000})
    await asyncio.sleep(3)
    await page.click('#su')
    await asyncio.sleep(3)
    # 使用选择器选中标签进行点击
    alist = await page.querySelectorAll('.s_tab_inner > a')
    a = alist[3]
    await a.click()
    await asyncio.sleep(3)
    await browser.close()
    
asyncio.get_event_loop().run_until_complete(main())

综合练习

爬取头条和网易的新闻标题

import asyncio
from pyppeteer import launch
from lxml import etree

async def main():
    # headless参数设为False,则变成有头模式
    browser = await launch(headless=False)

    page1 = await browser.newPage()

    # 设置页面视图大小
    await page1.setViewport(viewport={'width': 1280, 'height': 800})

    await page1.goto('https://www.toutiao.com/')
    await page1.evaluate('window.scrollTo(0,document.body.scrollHeight)')
    await asyncio.sleep(2)
    # 打印页面文本
    page_text = await page1.content()

    page2 = await browser.newPage()
    await page2.setViewport(viewport={'width': 1280, 'height': 800})
    await page2.goto('https://news.163.com/domestic/')
    await page2.evaluate('window.scrollTo(0,document.body.scrollHeight)')
    page_text1 = await page2.content()

    await browser.close()

    return {'wangyi':page_text1,'toutiao':page_text}

def parse(task):
    content_dic = task.result()
    wangyi = content_dic['wangyi']
    toutiao = content_dic['toutiao']
    
    tree = etree.HTML(toutiao)
    a_list = tree.xpath('//div[@class="title-box"]/a')
    print("头条新闻爬取数量: ", len(a_list))
    for a in a_list:
        title = a.xpath('./text()')[0]
        print('toutiao:',title)

    tree = etree.HTML(wangyi)
    div_list = tree.xpath('//div[@class="data_row news_article clearfix "]')
    print("网易新闻爬取数量: ", len(div_list))
    for div in div_list:
        title = div.xpath('.//div[@class="news_title"]/h3/a/text()')[0]
        print('wangyi:',title)
 
tasks = []
task1 = asyncio.ensure_future(main())
task1.add_done_callback(parse)
tasks.append(task1)

asyncio.get_event_loop().run_until_complete(asyncio.wait(tasks))

爬取结果:

头条新闻爬取数量:  28
toutiao: 港媒:黄之锋被裁定参选区议会提名无效
toutiao: 焯水用沸水or冷水?这些常识,很多人都错
toutiao: 滕昀轩出征第59届国际小姐全球总决赛
toutiao: 加州野火快速蔓延致20万人紧急疏散 全州进入紧急状态
toutiao: 黑道混混为追女生,7年画300本绘本,变身畅销作家
toutiao: 荷枪实弹!1500人清晨5点搬迁,竟出动2300多名公安武警
toutiao: 结婚前 女子突然发现未婚夫还有几场婚礼要办
toutiao: 乌克兰夫妇用LV限量皮箱装玉米“不知道它那么贵”
toutiao: 苹果凌晨发布新耳机!灵感来自豌豆射手?网友评论笑疯
toutiao: 中美将提前签署部分贸易协议?外交部:工作层将持续抓紧磋商
toutiao: 报告称支付宝成国内第二大APP
toutiao: 航母上生活用的淡水是哪来的
toutiao: 3名高级别干部被断崖式降级,有人被从中央委员降到调研员……
toutiao: 墨西哥警方发现毒贩窝点祭坛藏有大量人骨
toutiao: 小车内饰10年没有洗,5名洗车工奋战8小时,顾客:挺不好意思
toutiao: 央行重申违法!网红人民币蛋糕大众点评、饿了么仍有售
toutiao: 夫妇装修房子前买26桶油送邻居 留下致歉纸条:打扰了
toutiao: 韩国大白菜价格暴涨至34元1颗 网友:吃不起泡菜了
toutiao: 下班在家用电脑能做什么兼职补贴家用?
toutiao: 韩国白菜价暴涨34元一颗!韩媒:简直是吃金菜
toutiao: 格力“招亲”人选敲定!15%股权转让,董小姐的绣球为何抛向TA?
toutiao: 猪价上涨将终结?中科院院士饶子和发现非洲猪瘟病毒结构
toutiao: 广西一矿业公司发生冒顶事故已致2人遇难
toutiao: 本人一米六左右,想买个摩托车旅游,两万左右的有没有推荐下?
toutiao: 欧盟同意英国“脱欧”再延期
toutiao: 女护士在明星睡过的床上打滚取乐?别穿着职业制服去追星
toutiao: 多多自走棋野兽战阵容搭配推荐 野兽战阵容如何搭配
toutiao: 如何利用短信营销提升转化率?
网易新闻爬取数量:  69
wangyi: 退休14年后 山西一厅级干部被开除党籍并入狱三年
wangyi: 美监管机构将禁止华为参与政府补贴项目 中方回应
wangyi: 何君尧被英大学剥夺名誉博士学位:英真实面目暴露
wangyi: 林郑月娥:从未与暴力示威者对话 坚定支持警方止暴
wangyi: 台媒:大陆游客每月少10万人次 业者损失51亿新台币
wangyi: 港警对特首说:我们不怕流汗流血 但别让我们流泪
wangyi: 湖南500余名处级干部家属被召集 现场通报典型案例
wangyi: 11个月战胜癌症重返蓝天 女飞行员升任军级
wangyi: 教育部:落实学校负责人陪餐制 严查不履行责任学校
wangyi: 广州海关通报侵权案情况 销毁14.17万件侵权货物
wangyi: 猪肉上涨对学校食堂影响如何?市场监管总局回应
wangyi: 前港督:香港是中国的 我们不能告诉特区政府该做啥
wangyi: 陕西榆林人大常委会原副主任被双开:三观严重扭曲
wangyi: 林郑月娥:香港或进入技术经济衰退 全年或负增长
wangyi: 选举主任:黄之锋不符合候选人资格 选举提名无效
wangyi: 蔡当局选前大手笔 或将"债留子孙3500亿元新台币"
wangyi: 人民日报:挺身制暴是香港社会共同的责任
wangyi: 人民日报:区块链技术创新不等于炒作虚拟货币 
wangyi: 部分城市放松购房限制 经济日报:炒房没有捷径
wangyi: 稳外资政策增强外企信心“坚定看好中国投资前景”
wangyi: 人民日报解读就业数据:下行压力加大影响就业吗?
wangyi: 媒体:不止对中国"乱"提问 这些年CNN欠世界一堆账
wangyi: 新加坡第一夫人:香港人应找准在中国定位
wangyi: 前三季三大运营商营收均下滑 日均约赚4.03亿元
wangyi: 村支书受贿获刑:老板自愿送钱是看得起我 多有面子
wangyi: 董明珠来了"新老板":张磊狂砸400亿买下格力大股东
wangyi: 来了!四中全会这个“看点”你必须知道
wangyi: 山东辱母案新进展:讨债伤者起诉于欢索赔近20万
wangyi: 人民日报:外媒借"货车藏尸案"抹黑中国 用心险恶
wangyi: 教育部:"康复大学"依规不能冠以"中国"字样
wangyi: 人民日报谈网红带货:产品真的值得买吗?
wangyi: "电筒主任"再回应质疑: 在干旱田里种菜当地很常见
wangyi: 央视再怼西方媒体:近期的热闻照出了一些人真面目
wangyi: 四中全会看点:处分刘士余 谁来递补中央委员空缺?
wangyi: 持星条旗追打内地记者付国豪的香港暴徒 有新消息
wangyi: 四川一局长主动投案:100万退回了 我可以走了吗?
wangyi: 香港大学校委会主席批举美国旗学生:非常可悲 可耻
wangyi: 村主任回应"深夜挑灯干农活":为了还原事实摆拍
wangyi: 为重案犯调监狱的湖北省监狱管理局原副局长判9年
wangyi: 紧邻香港的他们,立了怎样的集体一等功?
wangyi: 女子为男友信用卡透支47万 对方却不承认这段关系
wangyi: 央视:未成年人立法 要不要降低刑事责任年龄?
wangyi: 新任江苏省委常委郭元强已就任省委秘书长 
wangyi: 香港警方:一周内206人被捕最小12岁 7名警员受伤
wangyi: 越南人移民英国大都从事美甲理发行业 年赚30万
wangyi: 杭州至德清城铁发招标公告 系2022年亚运会交通项目
wangyi: 香港反对派议员动议废除《禁蒙面法》 立法会否决
wangyi: 美海岸警卫队闯入黄海 中国万吨海警船近距离监视 
wangyi: 西藏航空一航班备降贵阳 疑似风挡玻璃出现裂纹
wangyi: 英国39名遇难者是不是持假中国护照?外交部回应
wangyi: 中纪委连续点名3次的司长被查后 7人主动交代问题
wangyi: 安徽供销社原理事会主任钱斌被捕 受贿数额特别巨大
wangyi: 这名司长被中纪委点名3次 查处后7人主动交代问题
wangyi: 河北应急厅:兴华钢铁“10.24”致7死火灾涉嫌迟报
wangyi: 教育部确认:“康复大学”不冠以“中国”字样
wangyi: 陕西延长车载试验装置爆炸致8人死亡 5名伤者送医
wangyi: 韩国瑜公开表态:"台独"可能吗?战争没有赢家
wangyi: 中共第十九届中央委员会第四次全体会议在京召开
wangyi: 美国海岸警卫队闯入黄海 中国万吨海警船近距监视
wangyi: 中国书法家协会原副主席赵长青接受审查和调查
wangyi: 拒向黑暴低头 香港市民唱勇敢的中国人力挺建制派
wangyi: 人民日报:中共十九届四中全会值得期待
wangyi: 十九届四中全会的三大看点:不寻常的议题
wangyi: 四中全会连开4天 回顾历届四中全会看点
wangyi: 四中全会召开在即 一图带你了解中央全会
wangyi: 职工嫖娼受留用察看处分后正常上班 纪委严肃纠正
wangyi: 中央机关公开遴选选调318名公务员 今起开始报名
wangyi: "65后"副省长郭元强履新 曾经历三次干部公开选拔
wangyi: 他主动退百万贿赂以为能继续当局长 结果被"拿下"
View Code

 

posted @ 2019-10-28 21:19  tiger_li  阅读(508)  评论(0编辑  收藏  举报