JavaScript - Puppeteer - テーブルから正しい形式でデータをスクレイピング

okwaves2024-01-25  7

私はいくつかのデータを収集するために人形遣いアプリに取り組んでいます。

このコードは正常に動作しますが、データを取得できるように改善できる可能性があります。作業できる構造化された方法でデータを取得できるように改善したいと考えています。

const table1 = await page.$$eval('table:nth-child(3) tbody', tbodys => tbodys.map((tbody) => {
  return tbody.innerText;
}));

つまり、tbody を使用すると、テーブル内のタグの数に関係なく、すべての TR タグと TD タグをスクレイピングできますが、テーブルにテーブル行があり、そのテーブル行内に 2 つのテーブルセルがあるという問題があります。最初の TD は、2 番目の TD のデータのヘッダーです。

次の HTML があります:

<tr class="header1"><th colspan="2">COS-MOD-000-CAB-PAP-123202</th></tr>

body > center > table > tbody > tr:nth-child(2) > td:nth-child(2) > div:nth-child(3) > table:nth-child(3) > tbody > tr:nth-child(2)

//THIS IS THE BODY WHICH MY ORIGINAL CODE IS PULLING OUT THE TEXT OF. MY CODE LOOKS AT TDS ONLY WITHIN TRs.
<tbody><tr class="header1"><th colspan="2">COS-MOD-000-CAB-PAP-123202</th></tr>
<tr class="light">
    <td style="text-align: right; width: 100px;"><strong>Status:</strong></td>//HEADER
    <td valign="top">Wrong&nbsp;</td> //VALUE
</tr>
<tr class="dark">
    <td style="text-align: right; width: 100px;"><strong>Created:</strong></td>//HEADER
    <td valign="top">2019-09-09 17:18:53&nbsp;</td>//VALUE
</tr>
<tr class="light">
    <td style="text-align: right; width: 100px;"><strong>Modified:</strong></td>//HEADER
    <td valign="top">2019-09-09 17:21:19&nbsp;</td>//VALUE
</tr>
<tr class="dark">
    <td style="text-align: right; width: 100px;"><strong>User:</strong></td>//HEADER
    <td valign="top">fbibsan&nbsp;</td>//VALUE
</tr>
<tr class="light">
    <td style="text-align: right; width: 100px;"><strong>BMS Account:</strong></td> //HEADER
    <td valign="top">ABC123 SAS. (SAS)&nbsp;</td> //VALUE
</tr>
<tr class="dark">
    <td style="text-align: right; width: 100px;"><strong>Mode:</strong></td>//HEADER
    <td valign="top">FAF&nbsp;</td>//VALUE
</tr>
<tr class="light">
    <td style="text-align: right; width: 100px;"><strong>Type:</strong></td>
    <td valign="top">BOP&nbsp;</td>
</tr>
</tbody>

テーブル内の各行に必要な構造は次のとおりです。

HEADER:'VALUE'

誰かが助けてくれることを願っています。今、何日もかけて探していたので、とても感謝しています。



------------------------

タスクを正しく理解していれば、テーブルから構造化データを取得する方法の簡単な例を次に示します。

const html = `
  <!doctype html>
  <html>
    <head><meta charset='UTF-8'><title>Test</title></head>
    <body>
      <table><tbody>
        <tr><th>Header</th><th>Header</th></tr>
        <tr><td>Key 1</td><td>Value 1</td></tr>
        <tr><td>Key 2</td><td>Value 2</td></tr>
      </tbody></table>
  </html>`;

const puppeteer = require('puppeteer');

(async function main() {
  try {
    const browser = await puppeteer.launch({ headless: false, defaultViewport: null });
    const [page] = await browser.pages();

    await page.goto(`data:text/html,${html}`);

    const data = await page.evaluate(() => {
      const dataObject = {};
      const tbody = document.querySelector('table tbody');

      for (const row of tbody.rows) {
        if (!row.querySelector('td')) continue; // Skip headers.

        const [keyCell, valueCell] = row.cells;
        dataObject[keyCell.innerText] = valueCell.innerText;
      }
      return dataObject;
    });

    console.log(data); // { 'Key 1': 'Value 1', 'Key 2': 'Value 2' }

    // await browser.close();
  } catch (err) {
    console.error(err);
  }
})();

6

エラーが発生します: 評価に失敗しました: TypeError: プロパティ 'innerText' を読み取れません未定義の。 TR を行として定義する必要はありませんか?

– スキルを見せてください

2020 年 9 月 5 日 13:27

いいえ、tbody.rows はすでにテーブルの TR です。このエラーは、TD が 2 未満の TR が存在することを意味している可能性があります。これは可能ですか?

– vsemozhebuty

2020 年 9 月 5 日 13:37

エラーは、そもそもテーブル要素を見つけることにあるようです....テーブルはテーブル内のテーブルであるため、セレクターを使用して正確なテーブルを見つけることができません....これはセレクター const tbody = ドキュメントent.querySelector('テーブル:nth-child(3) tbody');それはうまくいきませんでしたが、HTML だけを使用してコードのテストを行ったところ、うまくいきました。ブラウザ内の特定のテーブルで動作させる方法はありますか?お時間と専門知識をありがとうございました!

– スキルを見せてください

2020 年 9 月 5 日 13:47

表のあるページの URL を教えていただけますか?

– vsemozhebuty

2020 年 9 月 5 日 13:51

OK - 問題が見つかりました - おっしゃるとおりです - テーブルの最初の TR に TD がありません....<tr class="header1"><thcolspan="2"> ;text</th></tr>...スキップできますか?

– スキルを見せてください

2020 年 9 月 5 日 13:54



------------------------

マップ コールバックでの tbody のタイプに応じて異なります。何らかの方法でその tbody オブジェクトを解析できることを願っています。

追加の PA が必要なだけだと思いますrsing を実行し、おそらく既存の関数にロジックを追加するだけで済みます。

私ならこうします:

const table1 = await page.$$eval('table:nth-child(3) tbody', tbodys => tbodys.map((tbody) => {
  // add logic here!
  let parsedTable = '';
  let extractedTRs = tbody.match(/<tr>(.*?)<\/tr>/g); // find a way to deconstruct this or regex. what is the type of tbody?
  extractedTRs.map( tr => {
  const tr= str.match(/<td>(.*?)<\/td>/g); //this should return an array...someone check me :)
  parsedTable += `tr[0]:'${tr[1]}' \n`); 
}
  
  return parsedTable;
}));

2020 年 9 月 4 日 21:49 に回答

オマール

オマール

442

4

銀バッジ 4 個

10 個

銅バッジ 10 個

2

この解決策を試したところ、tr=str.match がすでに宣言されているという構文エラーが発生しました。 T彼は私の質問のHTMLコードに本文があります...それが完全な本文です。私の元のコードは trs 内の tds を取り出しますが、行の最初の列が実際にはヘッダーであり、2 番目の列が値である必要な形式ではありません。

– スキルを見せてください

2020 年 9 月 4 日 22:28

ヘッダーと本文の値を明確にするために HTML コードを編集しました。

– スキルを見せてください

9 月 4 日2020 年 22:36

総合生活情報サイト - OKWAVES
総合生活情報サイト - OKWAVES
生活総合情報サイトokwaves(オールアバウト)。その道のプロ(専門家)が、日常生活をより豊かに快適にするノウハウから業界の最新動向、読み物コラムまで、多彩なコンテンツを発信。