Skip to content

Puppeteer

待验证

  • 截取特定区域,如推文卡片

缺失能力与替代方法

  • 无法处理权限对话框,可指定用户文件夹,在指定一次后记住

状态条件

js
// networkidle0 所有请求加载完
// domcontentloaded 只关心 markup
await page.goto(url, {waitUtil: 'domcontentloaded'})

监听页面变化

js
const watchDog = page.waitForFunction('window.innerWidth < 100');

缓存

js
new Map
set
has

启动参数

js
const chromeConfig = {
  headless: false, // 为假时打开浏览器窗口,服务端直接注释掉
  args: [
    '--no-sandbox',
    '--disable-setuid-sandbox',
    '--proxy-server=socks5://127.0.0.1:1081'  // 本地最好使用代理
    '--window-size=0,0', // 小窗口,用途是需要声音时,headless 没声音
    '--window-position=25,25',
    `--disable-extensions-except=${CRX}`,
    `--load-extension=${CRX}`
  ]
}

无法选中元素的处理

CSS 选择器中,没有选择父元素的选择器 利用puppeteer.evaluate,加上 ID

js
// 点击 input name=x 的下拉框中的Item1
let name = 'x'
let value = 'Item1'
let result = await this.page.evaluate((name, value) => {
  let result = -1
  let list = document.querySelector('[name=' + name + ']').parentElement.parentElement.children[1].children)
  for (let i = 0; i < list.length; i++) {
    let c = list[i]
    c.id = '_select_' + name + '_' + i
    if (c.innerText === value) { // found ?
      result = i
    }
  }
  return result
}, name, value)
if (result == -1) {
    throw new Error(value + ' not found!!')
}
await this.page.click('#_select_x_' + result)
js
var resp = await page.goto(url, {timeout:120000}); var html = await resp.text();

保存和恢复 localStorage

js
const restoreLocalStorage = async () => {
    let json = JSON.parse(fs.readFileSync(`${__dirname}/local.json`));
    await page.evaluate(json => {
      localStorage.clear();
      for (let key in json)
        localStorage.setItem(key, json[key]);
    }, json);
  }

  const saveLocalStorage = async () => {
    console.log("saving");
    const json = await page.evaluate(() => {
      let json = {};
      for (let i = 0; i < localStorage.length; i++) {
        const key = localStorage.key(i);
        json[key] = localStorage.getItem(key);
      }
      return json;
    });
    console.log(json);
    fs.writeFileSync(`${__dirname}/local.json`, JSON.stringify(json));
  }

等待元素可见

js
await page.waitForSelector('#element', {
  visible: true,
})

登陆

标准的网站,允许使用Post方法发送用户名及密码,返回对应的Token,之后的请求即可使用该Token,这时候我们可以直接使用Request包即可。

但是遇到一些网站,并没有对外开放API接口,每次请求数据是通过登录后的Cookis进行判断。这时候我们也可以使用Request,截取Set-Cookie 头部信息即可。

但是,还有一些网站,在登录时候,需要添加服务器发送给客户端的安全码,这个时候如果单单使用Request就有些费力了。

js
page.on('response', res => {
    if(res.hasOwnProperty('headers')){
        for(let key in res.headers){
            if(key === 'set-cookie'){
               // 在这里进行获取Cookie信息操作
            }else{
                continue;
            }
        }
    }
});
js
// here --->
const sessionCookies = await page.cookies();

// and in another session --->
await page.setCookies(sessionCookies);

let cookies = JSON.parse(fs.readFileSync(`${dir}/cookie.txt`, 'utf8'))
if (cookies) {
  log('login by cookie')
  await page.setCookie(...cookies)
}

log('update cookies')
cookies = await page.cookies();
fs.writeFileSync(`${dir}/cookie.txt`, JSON.stringify(cookies, null, '\t'))

结合 cheerio

js
const puppeteer = require('puppeteer');
const cheerio = require('cheerio');
(async function () {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto('https://www.zhihu.com/people/zhang-shu-yuan-18/following');
    let pageContent =await page.content();
    const $ = cheerio.load(pageContent);
    $('.UserLink-link').each((index, item) => {
        console.log($(item).text());
    })
    browser.close();
})()

指定语言

javascript - How to specify browser language in Puppeteer - Stack Overflow

下载图片

Question: How do I get puppeteer to download a file? · Issue #299 · GoogleChrome/puppeteerSaving Images from a Headless Browser