直接上干货
注入拦截和筛选请求和返回
下面这个例子经常用来:
- 加快网页加载速度
- 快速筛选数据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
以淘宝登陆验证码为例
淘宝的验证码验证模块会检测浏览器环境,主要是检测
window.navigator.webdriver
参数,如果是浏览器直接打开,如下图:
如果是使用webdriver驱动打开(selenium,puppeteer,pyppeteer),这个参数如下图:
尝试直接覆盖这个属性,但是没有效果。
通过查资料,发现
Object.defineProperty()
方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。如果不指定configurable, writable, enumerable ,则这些属性默认值为false,如果不指定value, get, set,则这些属性默认值为undefined
完整代码
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())