Puppeteer 是 Google 基于 Node.js 开发的一个工具,有了它我们可以通过 JavaScript 来控制 Chrome 浏览器的一些操作,当然也可以用作网络爬虫上,其 API 极其完善,功能非常强大。Pyppeteer 是 Puppeteer 的 Python 版本的实现,但他不是 Google 开发的,是一位来自于日本的工程师依据 Puppeteer 的一些功能开发出来的非官方版本。
安装:pip install pyppeteer
浏览器驱动自动会安装
import asynci
import time
from pyppeteer import launcher
# 去除浏览器自动化参数,隐藏自动化工具特征
launcher.DEFAULT_ARGS.remove("--enable-automation")
from pyppeteer import launch
params={
# 关闭无头浏览器
"headless": False,
'dumpio':'True', # 防止浏览器卡住
r'userDataDir':'./cache-data', # 用户文件地址
"args": [
'--disable-infobars', # 关闭自动化提示框
'--window-size=1920,1080', # 窗口大小
'--log-level=30', # 日志保存等级, 建议设置越小越好,要不然生成的日志占用的空间会很大 30为warning级别
'--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36',
'--no-sandbox', # 关闭沙盒模式
'--start-maximized', # 窗口最大化模式
'--proxy-server=http://localhost:1080' # 代理
],
}
# 创建浏览器对象
browser=await launch(**params)
# 创建一个页面对象
page=await browser.newPage()
# 设置ua
await page.setUserAgent( 'Mozilla/5.0 (Windows NT 100; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36'
)
# 修改navigator.webdriver检测
# 各种网站的检测js是不一样的,这是比较通用的。有的网站会检测运行的电脑运行系统,cpu核心数量,鼠标运行轨迹等等。
# 反爬js
js_text="""
() =>{
Object.defineProperties(navigator,{ webdriver:{ get: () => false } });window.navigator.chrome = { runtime: {}, };
Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] });
Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5,6], });
}
"""
# 本页刷新后值不变,自动执行js
await page.evaluateOnNewDocument(js_text)
await asyncio.sleep(3)
# 打开一个页面
await page.goto(url)
# 定位账号输入框输入账号delay为输入限定时间
await page.type('#fm-login-id',username,{'delay':input_time_random()-50})
# 输入密码
await page.type('#fm-login-password',password,{'delay':input_time_random()})
time.sleep(2)
# Jeval获取定位元素的属性,来检测是否有滑块
slider=await page.Jeval('#nocaptcha','node=>node.style')
# 账号密码输入完毕进行滑块验证后键盘按下enter进行登录
await page.keyboard.press('Enter')
# 等待自定义js渲染完成
await page.waitFor(20)
# 等待自定义导航栏渲染完成
await page.waitForNavigation()
# 依据id定位元素并输入关键字
await page.type('#kw','python')
# 依据id定位执行点击
await page.click('#su')
# 依据classname进行定位执行点击
await page.click('.fm-btn>button')
# 模拟真实点击
page.mouse
await asyncio.sleep(3)
# 输出网页源码
text=await page.content()
# print(text)
# 关闭浏览器
await browser.close()
import asyncio
import random
import time
from retrying import retry
from pyppeteer import launcher
# 去除浏览器自动化参数,隐藏自动化工具特征
launcher.DEFAULT_ARGS.remove("--enable-automation")
from pyppeteer import launch
def input_time_random():
return random.randint(100,200)
def retry_if_result_none(result):
return result is None
# retry装饰器可给鼠标滑动函数增加多次测试的功能
@retry(retry_on_result=retry_if_result_none)
async def mouse_slide(page=None):
await asyncio.sleep(2)
try:
# 鼠标移动到滑块上
await page.hover('#nc_1_n1z')
# 按下鼠标
await page.mouse.down()
# 滑动到头,并延时,x,y为鼠标移动的像素位置
await page.mouse.move(2000,0,{'delay':random.randint(1000,2000)})
# 松开鼠标
await page.mouse.up()
except Exception as e:
print(e,':验证失败')
return None,page
else:
await asyncio.sleep(2)
# 判断是否通过
slider_again=await page.Jeval('.nc-lang-cnt','node=>node.textContent')
if slider_again !='验证通过':
return None,page
else:
# 截图测试
await page.screenshot({'path':'./slider-result.png'})
print('验证通过')
return 1,page
async def login(url,username,password):
params={
# 关闭无头浏览器
"headless": False,
'dumpio':'True', # 防止浏览器卡住
r'userDataDir':'./cache-data', # 用户文件地址
"args": [
'--disable-infobars', # 关闭自动化提示框
'--window-size=1920,1080', # 窗口大小
'--log-level=30', # 日志保存等级, 建议设置越小越好,要不然生成的日志占用的空间会很大 30为warning级别
'--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36',
# UA
'--no-sandbox', # 关闭沙盒模式
'--start-maximized', # 窗口最大化模式
# '--proxy-server=http://localhost:1080' # 代理
],
}
# 创建浏览器对象
browser=await launch(**params)
# 创建一个页面对象
page=await browser.newPage()
# 设置ua
# await page.setUserAgent( 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36'
# )
# await page.setViewport(viewport={'width':width,'height':height})
# 修改navigator.webdriver检测
# 各种网站的检测js是不一样的,这是比较通用的。有的网站会检测运行的电脑运行系统,cpu核心数量,鼠标运行轨迹等等。
# 反爬js
js_text="""
() =>{
Object.defineProperties(navigator,{ webdriver:{ get: () => false } });
window.navigator.chrome = { runtime: {}, };
Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] });
Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5,6], });
}
"""
# 本页刷新后值不变,自动执行js
await page.evaluateOnNewDocument(js_text)
await asyncio.sleep(3)
# 打开一个页面
await page.goto(url)
# 定位账号输入框输入账号delay为输入限定时间
await page.type('#fm-login-id',username,{'delay':input_time_random()-50})
# 输入密码
await page.type('#fm-login-password',password,{'delay':input_time_random()})
time.sleep(2)
# Jeval获取定位元素的属性,来检测是否有滑块
slider=await page.Jeval('#nocaptcha','node=>node.style')
if slider:
print("出现滑块")
# 截图测试
await page.screenshot({'path':'./login-slider.png'})
# 执行滑块滑动函数获取标签
flag,page=await mouse_slide(page=page)
if flag:
# 账号密码输入完毕进行滑块验证后键盘按下enter进行登录
await page.keyboard.press('Enter')
# 如果回车键没起作用,可调用模拟点击登录的js代码点击登录
await page.evaluate('''document.getElementByclassname('fm-btn').click()''')
time.sleep(2)
cookies_list=await page.cookies()
print(cookies_list)
# 导出cookie来进行后续数据提取
return await get_cookie(page)
else:
print('')
await page.keyboard.press('Enter')
# 等待自定义js渲染完成
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('请输入正确的账号密码')
else:
print(page.url)
return await get_cookie(page)
# 获取登录后的cookie
async def get_cookie(page):
# 获取网页源代码
# res=await page.content()
# 获取cookies列表
cookies_list=await page.cookies()
c_dict={}
cookies=''
# 构建cookie格式
for cookie in cookies_list:
str_cookie='{0}={1};'
str_cookie=str_cookie.format(cookie.get('name'),cookie.get('value'))
cookies+=str_cookie
if __name__=='__main__':
url='https://login.taobao.com/member/login.jhtml?'
username=''
password=''
# 创建异步池,并执行主函数
asyncio.get_event_loop().run_until_complete(login(url,username,password))