pyppeteer(五)--执行自定义js

直接上干货

注入拦截和筛选请求和返回

下面这个例子经常用来:

  • 加快网页加载速度
  • 快速筛选数据api接口

做新闻爬虫的时候,遇到网页有视频其实挺尴尬的,首先如果加载视频会导致打开网页比较慢,有时甚至会导致浏览器超时崩溃,其次是视频的加载可能不同时带入一些广告的超链接,对于提取新闻内容会造成干扰。
通过page.setRequestInterception参数开启注入。
先上整体代码

import asyncio
from pyppeteer import launch

async def inject_request(req):
    """
    resourceType:
        document, stylesheet, image, media, font, script, texttrack, 
        xhr, fetch, eventsource, websocket, manifest, other
    """
    if req.resourceType in ['media','image']:
        await req.abort()
    else:
        await req.continue_()

async def inject_response(res):

    if res.request.resourceType in ['xhr']:
        print(res.request.url)
    
async def main():
    browser = await launch({'headless':False})
    page = await browser.newPage()
    await page.setRequestInterception(True)
    page.on('request', inject_request)
    page.on('response',inject_response)
    await page.goto('https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0')
    await page.waitFor(5 * 1000)
    await browser.close()

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

先分析inject_request部分,

async def inject_request(req):
    if req.resourceType in ['media','image']:
        await req.abort()
    else:
        await req.continue_()

一般用得比较多的是一个属性两个方法,
一个属性:
resourceType,表示请求的资源类型,有document, stylesheet, image, media, font, script, texttrack, xhr, fetch, eventsource, websocket, manifest, other(加粗的是比较常用的资源类型)
两个方法:
abort(),跳过当前请求
continue_(),继续当前请求
上面代码段意思是,不请求图片和媒体资源。

inject_response部分

async def inject_response(res):

    if res.request.resourceType in ['xhr']:
        print(res.request.url)

一般js动态加载的数据连接在xhr资源,所以我这里把网页请求的xhr资源都打印出来,如果这里没有数据连接,那就是在document里面了,比F12清晰一点。

注入js

以淘宝登陆验证码为例

1.gif

淘宝的验证码验证模块会检测浏览器环境,主要是检测window.navigator.webdriver参数,如果是浏览器直接打开,如下图:
image.png

如果是使用webdriver驱动打开(selenium,puppeteer,pyppeteer),这个参数如下图:
image.png

尝试直接覆盖这个属性,但是没有效果。
image.png

通过查资料,发现

Object.defineProperty()
方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。如果不指定configurable, writable, enumerable ,则这些属性默认值为false,如果不指定value, get, set,则这些属性默认值为undefined

image.png

完整代码

import asyncio
import random
from pyppeteer import launch

def input_time_random():
    return random.randint(100, 151)

async def main():
    browser = await launch({'headless':False})
    page = await browser.newPage()
    await page.evaluateOnNewDocument(
        '''() =>{ Object.defineProperties(navigator,{ webdriver:{ get: () => false } }) }''')
    await page.evaluateOnNewDocument('''() =>{ window.navigator.chrome = { runtime: {},  }; }''')
    await page.evaluateOnNewDocument('''() =>{ Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] }); }''')
    await page.evaluateOnNewDocument('''() =>{ Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5,6], }); }''')
    await page.goto('https://login.taobao.com')
    await page.waitFor(4 * 1000)
    await page.click('#J_QRCodeLogin > div.login-links > a.forget-pwd.J_Quick2Static')
    await page.waitFor(3 * 1000)
    await page.type('#TPL_username_1', '123123', {'delay': input_time_random() - 50})
    await page.type('#TPL_password_1', '232322332', {'delay': input_time_random()})
    await page.waitFor(2 * 1000)
    el = await page.querySelector('#nc_1_n1z')
    box = await el.boundingBox()
    await page.hover('#nc_1_n1z')
    await page.mouse.down()
    await page.mouse.move(box['x']+1000,box['y'], {'delay': random.randint(1000, 2000),'steps':3})
    await page.mouse.up()
    await page.waitFor(5 * 1000)
    await browser.close()

asyncio.get_event_loop().run_until_complete(main())
1.gif

你可能感兴趣的:(pyppeteer(五)--执行自定义js)