puppeteer で対象の特定方法

 puppeteer で要素を特定して操作する場合、基本は、id や class などを使うことで特定します。id や class 属性がない場合は、他の属性を使うこともできます。しかし、属性があっても他の要素でも同じ属性を使っていたりすると区別できません。

一意に決まらない要素

 例えば、次のような html で特定の details タグをクリックさせて、詳細を表示させたい場合を考えます。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name='robots' content='noindex,nofollow'>
  <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes">
  <title>puppeteer のテストページ</title>
  <style>
    body { background-color: #efefef; }
  </style>
</head>
<body>
<h1>puppeteer の操作テスト</h1>

<h2>親要素を使って区別する</h2>
<ul>
  <li>PhantomJS<br>
    <details>
      <summary>説明</summary>
       WebKit ベースのヘッドレスブラウザです。WebKit とは主に Web ブラウザーで用いられているレンダリングエンジンのことです。PhantomJS は WebKit に内蔵の JavaScriptCore という JavaScript エンジンを採用しています。スクレイピングやスクリーンキャプチャなどにも活用可能です。
    </details>
  </li>
  <li>Puppeteer<br>
    <details>
      <summary>説明</summary>
       Puppeteer は DevTools プロトコルでヘッドレス Chrome または Chromium を制御するための高水準 API を提供する Node ライブラリです。ヘッドレスではないフルの Chrome または Chromium を使用することもできます。
    </details>
  </li>
  <li>PlayWright<br>
    <details>
      <summary>説明</summary>
       PlayWright とは Microsoft が中心になって開発する Node.js 上からブラウザを操作するためのライブラリです。対象ブラウザが Chromium / Firefox / WebKit となっており、現在主流の レンダリングエンジン および JavaScript エンジン を押さえています。
    </details>
  </li>
</ul>

<h2>親要素で区別できない場合</h2>
・Chromium<br>
<details>
  <summary>説明</summary>
   米 Google 社が開発に深く関与するオープンソースの Web ブラウザです。同社の Google Chrome はこれを元に開発されています。
</details>
・Edge<br>
<details>
  <summary>説明</summary>
   Microsoft Edge は、Microsoft 社が開発した Web ブラウザです。当初は独自開発でしたが、現在は、オープンソースの Chromium をベースとして開発されています。Windows 10 の標準ブラウザです。
</details>
・FireFox<br>
<details>
  <summary>説明</summary>
   Mozilla Firefox は、Mozilla Foundation およびその傘下の Mozilla Corporation によって開発されているフリーかつオープンソースの Web ブラウザです。
</details>

</body>
</html>

 この html でPuppeteer の説明を開いたり、FireFox の説明を開いたりする方法を考えてみます。この html を ここに置きました。

サンプルの html

親要素で特定できる場合

 html で次の部分があります。

<ul>
  <li>PhantomJS<br>
    <details>
      <summary>説明</summary>
       WebKit ベースのヘッドレスブラウザです。WebKit とは主に Web ブラウザーで用いられているレンダリングエンジンのことです。PhantomJS は WebKit に内蔵の JavaScriptCore という JavaScript エンジンを採用しています。スクレイピングやスクリーンキャプチャなどにも活用可能です。
    </details>
  </li>
  <li>Puppeteer<br>
    <details>
      <summary>説明</summary>
       Puppeteer は DevTools プロトコルでヘッドレス Chrome または Chromium を制御するための高水準 API を提供する Node ライブラリです。ヘッドレスではないフルの Chrome または Chromium を使用することもできます。
    </details>
  </li>
  <li>PlayWright<br>
    <details>
      <summary>説明</summary>
       PlayWright とは Microsoft が中心になって開発する Node.js 上からブラウザを操作するためのライブラリです。対象ブラウザが Chromium / Firefox / WebKit となっており、現在主流の レンダリングエンジン および JavaScript エンジン を押さえています。
    </details>
  </li>
</ul>

 この場合は、id がついていませんし、その他の属性もありません。そこで、親要素を取得して、それから子要素を取得し操作します。

 Puppeteer の説明をクリックするにはまず、親要素の li を取得します。親要素の li タグは内部に「Puppeteer」という文字列があるので、XPath を使って要素を取得できます。

let parent = await page.$x('//li[contains(text(), "Puppeteer")]');

 この親要素を使って、子要素の details タグを取得し、クリックします。

if( parent.length > 0 ) {
    let detailsTags = await parent[0].$x('.//details');
    if( detailsTags.length > 0 ) {
        await detailsTags[0].click();
    } else {
        console.log("details タグがありません。");
    }
} else {
    console.log("親要素がありません。");
}
Puppeteer の説明 (details) をクリック

特定ができない場合

 親要素が使えない場合は、もう仕方がありません。ページ内の何番目の details タグということでクリックさせるしかありません。

 html の次の部分です。

・Chromium<br>
<details>
  <summary>説明</summary>
   米 Google 社が開発に深く関与するオープンソースの Web ブラウザです。同社の Google Chrome はこれを元に開発されています。
</details>
・Edge<br>
<details>
  <summary>説明</summary>
   Microsoft Edge は、Microsoft 社が開発した Web ブラウザです。当初は独自開発でしたが、現在は、オープンソースの Chromium をベースとして開発されています。Windows 10 の標準ブラウザです。
</details>
・FireFox<br>
<details>
  <summary>説明</summary>
   Mozilla Firefox は、Mozilla Foundation およびその傘下の Mozilla Corporation によって開発されているフリーかつオープンソースの Web ブラウザです。
</details>

 この場合、FireFox のリンクをクリックするには次のようにします。

let detailsTags = await page.$x('//details');
if( detailsTags.length > 5 ) {
    await detailsTags[5].click();
} else {
    console.log("対象の details タグがありません。");
}

 これでクリックできます。

FireFox の説明 (details) をクリック

XPath を使うと簡単

 実は、XPath を使うと、もっと簡単に要素を取得できます。例えば、Puppeteer の説明をクリックするコードは以下のようになります。

let target = await page.$x('//details[text()[contains(., "Puppeteer は DevTools")]]');
if( target.length == 0 ) {
    console.log("対象が見つかりません。");
} else {
    await target[0].click();
}

 対象の details タグは、「Puppeteer は DevTools」という内容があるので、XPath で探すことができます。

 ただし、XPath の書き方に気をつけないと見つけ出せません。次の書き方では要素を取得できませんでした。

await page.$x('//details[contains(text(), "Puppeteer は DevTools")]');

 この書き方で取得できたのは、以下のような html でした。

<details>
   Puppeteer は DevTools プロトコルでヘッドレス Chrome または Chromium を制御するための高水準 API を提供する Node ライブラリです。ヘッドレスではないフルの Chrome または Chromium を使用することもできます。
  <summary>説明</summary>
</details>

 「[contains(text(), “Puppeteer は DevTools")]」 は最初に見つけたテキストノードのチェックしかしないようです。

 FireFox の details タグも同様です。

pupeeteer,Raspberry Pi

Posted by sirius