使用pyppeteer的原因:正常浏览情况下浏览器的window.navigator.webdriver的值为undefined,在用selenium模拟情况下其值为true,基于这个机制有些网站会对selenium进行反爬。此外selenium需要配置对应的浏览器驱动,其配置会比pyppeteer麻烦些。
安装:pip install pyppeteer
,在首次使用时会自动下载安装Chromeium。或者
from pyppeteer import chromium_downloader
关于Chrome,Chromeium,puppereer,pyppeteer
Chromium 是谷歌为了研发 Chrome 而启动的项目,是完全开源的,二者基于相同的源代码构建。Puppeteer 是 Google 基于 Node.js 开发的一个工具,可以通过JavaScript 来控制 Chrome 浏览器的一些操作。Pyppeteer是一位来自于日本的工程师依据 Puppeteer 的一些功能开发出来的非官方版本。
文档:
我是参考的puppeteer文档。puppeteer的中文文档链接:https://zhaoqize.github.io/puppeteer-api-zh_CN/
使用:
import asyncio
from pyppeteer import launch
async def main():
# 使用launch方法调用浏览器,其参数可以传递关键字参数也可以传递字典。
browser = await launch({'headless': False, 'args': ['--disable-infobars', '--window-size=1920,1080', '--no-sandbox']})
# 打开一个页面
page = await browser.newPage()
await page.setViewport({'width': 1920, 'height': 1080}) # 设置页面的大小
# 打开链接
await page.goto('https://login.taobao.com/member/login.jhtml')
# 调用
asyncio.get_event_loop().run_until_complete(main())
launch可接收的参数非常多,其中headless指定浏览器是否以无头模式运行,默认是True。args指定给浏览器实例传递的参数,'--disable-infobars'
代表关闭浏览上方的“Chrome 正受到自动测试软件的控制”,'--window-size=1920,1080'
是设置浏览器的显示大小,--no-sandbox
是 在 docker 里使用时需要加入的参数。其他很多参数可以参考puppeteer的文档https://zhaoqize.github.io/puppeteer-api-zh_CN/#?product=Puppeteer&version=v2.1.1&show=api-class-puppeteer
设置浏览器的window.navigator.webdriver的值
# evaluate()是执行js的方法,js逆向时如果需要在浏览器环境下执行js代码的话可以利用这个方法
# js为设置webdriver的值,防止网站检测
await page.evaluate('''() =>{ Object.defineProperties(navigator,{ webdriver:{ get: () => false } }) }''')
输入账号和密码
# waitForSelector(selector[, options])
# 等待指定的选择器匹配的元素出现在页面中,如果调用此方法时已经有匹配的元素,立即返回。 如果指定的选择器在超时后不出现则抛出异常。
# 也可用waitForXPath()使用xpath选择器
await page.waitForSelector('#J_QRCodeLogin > div.login-links > a.forget-pwd.J_Quick2Static', {'timeout': 3000})
# 点击“账号密码”,css选择器
await page.click('#J_QRCodeLogin > div.login-links > a.forget-pwd.J_Quick2Static')
# 输入账号和密码,css选择器
await page.type('#TPL_username_1', '')
await page.type('#TPL_password_1', '')
# 点击“登录”
await page.click('#J_SubmitStatic')
也可以使用其他选择器找出节点后再调用点击输入等方法
# 利用xpath选择器选择出登录按钮
longin_key = await page.Jx('//*[@id="J_SubmitStatic"]')
# longin_key = await page.xpath('//*[@id="J_SubmitStatic"]')
# 点击
await login_key[0].click()
支持的选择器有
# 在页面内执行 document.querySelector。如果没有元素匹配指定选择器,返回值是 None
J = querySelector
# 在页面内执行 document.querySelector,然后把匹配到的元素作为第一个参数传给 pageFunction
Jeval = querySelectorEval
# 在页面内执行 document.querySelectorAll。如果没有元素匹配指定选择器,返回值是 []
JJ = querySelectorAll
# 在页面内执行 Array.from(document.querySelectorAll(selector)),然后把匹配到的元素数组作为第一个参数传给 pageFunction
JJeval = querySelectorAllEval
# XPath表达式
Jx = xpath
完整代码:
import asyncio
from pyppeteer import launch
async def main():
browser = await launch({'headless': False, 'args': ['--disable-infobars', '--window-size=1920,1080']})
page = await browser.newPage()
await page.setViewport({'width': 1920, 'height': 1080})
await page.goto('https://login.taobao.com/member/login.jhtml')
await page.evaluate('''() =>{ Object.defineProperties(navigator,{ webdriver:{ get: () => false } }) }''')
await page.waitForSelector('#J_QRCodeLogin > div.login-links > a.forget-pwd.J_Quick2Static', {'timeout': 3000})
await page.click('#J_QRCodeLogin > div.login-links > a.forget-pwd.J_Quick2Static')
await page.type('#TPL_username_1', '') # 账号
await page.type('#TPL_password_1', '') # 密码
await asyncio.sleep(5)
slider = await page.Jeval('#nocaptcha', 'node => node.style') # 是否有滑块,ps:试了好多次都没出滑块
if slider:
print('出现滑块')
await page.click('#J_SubmitStatic')
await asyncio.sleep(5)
cookie = await page.cookies()
print(cookie)
await browser.close()
asyncio.get_event_loop().run_until_complete(main())