Puppeteerでデータ取得

## やること

ログインがあるサイトのデータ取得

## 前提

以前作成した下記記事の環境からスタート

https://qiita.com/sh19982580/items/d0e4fde11e734bee8c76

## puppeteerインストール

`yarn add puppeteer puppeteer-core`

## サイトに入る

puppeteer.ts

    import puppeteer from "puppeteer"
    import dotenv from "dotenv"

    import { initLogger } from "../logger/index"

    dotenv.config()
    const { infoLogger, errorLogger } = initLogger("src/logger/index.ts")

    type ScrapingData = () => Promise<void>
    export const scrapingData: ScrapingData = async () => {
      const { URL } = process.env
      if (!URL) throw new Error("URLがありません")
      const browser = await puppeteer.launch({
        //開発時はヘッドレスモードオフで行う
        headless: false,
        args: ["--no-sandbox", "--disable-setuid-sandbox"],
      })
      const page = await browser.newPage()

      try {
        infoLogger("サイトに侵入開始")

        await page.setViewport({ width: 2000, height: 800 })
        await page.goto(URL, { waitUntil: "load" })

        //スクリーンショット
        await page.screenshot({ path: "test.png" })

        infoLogger("サイト侵入に成功")
        return Promise.resolve()
      } catch (error) {
        errorLogger("サイト侵入に失敗", { error })
        return Promise.reject(error)
      } finally {
        infoLogger("ブラウザクローズ開始")
        browser.close().then(() => infoLogger("ブラウザクローズ終了"))
      }
    }

`yarn run ts-node-dev src/puppeteer.ts`

勝手にブラウザが立ち上がり、`test.png`でそのページのスクリーンショットが撮れていればOK！

## ログイン

puppeteer.ts

    import puppeteer from "puppeteer"
    import dotenv from "dotenv"

    import { initLogger } from "../logger/index"

    dotenv.config()
    const { infoLogger, errorLogger } = initLogger("src/logger/index.ts")

    type ScrapingData = () => Promise<void>
    export const scrapingData: ScrapingData = async () => {
      const { URL, USERNAME, PASSWORD } = process.env
      if (!URL || !USERNAME || !PASSWORD) throw new Error("ログイン情報がありません")
      const browser = await puppeteer.launch({
        //開発時はヘッドレスモードオフで行う
        headless: false,
        args: ["--no-sandbox", "--disable-setuid-sandbox"],
      })
      const page = await browser.newPage()

      try {
        infoLogger("ログイン開始")

        await page.setViewport({ width: 2000, height: 800 })

        await page.goto(URL, { waitUntil: "load" })

        await page.type('input[name="user_name"]', USERNAME)
        await page.type('input[name="password"]', PASSWORD)

        await Promise.all([page.waitForNavigation({ waitUntil: "load" }), page.click('input[type="submit"]')])

        //スクリーンショット
        await page.screenshot({ path: "test1.png" })

        infoLogger("ログインに成功")
        return Promise.resolve()
      } catch (error) {
        errorLogger("ログイン失敗", { error })
        return Promise.reject(error)
      } finally {
        infoLogger("ブラウザクローズ開始")
        browser.close().then(() => infoLogger("ブラウザクローズ終了"))
      }
    }

- `USERNAME`と`PASSWORD`を追加
- `page.type`の中身はサイトの検証(Element)から確認
- `page.click`も同様

`yarn run ts-node-dev src/puppeteer.ts`

`test1.png`でログイン後のスクリーンショットが撮れていればOK！

## 要素が取得できているか確認する方法
ブラウザのコンソールを開く

    const a = document.querySelectorAll("要素"); 
    console.log(a)

要素の部分に記載してみてログに入っていればOK!

## データ取得

puppeteer.ts

    import puppeteer from "puppeteer"
    import dotenv from "dotenv"

    import { initLogger } from "../logger/index"

    dotenv.config()
    const { infoLogger, errorLogger } = initLogger("src/logger/index.ts")

    type ScrapingData = () => Promise<void>
    export const scrapingData: ScrapingData = async () => {
      const { URL, USERNAME, PASSWORD } = process.env
      if (!URL || !USERNAME || !PASSWORD) throw new Error("ログイン情報がありません")
      const browser = await puppeteer.launch({
        //開発時はヘッドレスモードオフで行う
        headless: false,
        args: ["--no-sandbox", "--disable-setuid-sandbox"],
      })
      const page = await browser.newPage()

      try {
        infoLogger("ログイン開始")

        await page.setViewport({ width: 2000, height: 800 })

        await page.goto(URL, { waitUntil: "load" })

        await page.type('input[name="user_name"]', USERNAME)
        await page.type('input[name="password"]', PASSWORD)

        await Promise.all([page.waitForNavigation({ waitUntil: "load" }), page.click('input[type="submit"]')])

        const list = await page.$eval("要素", (value) => {
          return value.textContent
        })

        console.log(list)

        infoLogger("ログインに成功")
        return Promise.resolve()
      } catch (error) {
        errorLogger("ログイン失敗", { error })
        return Promise.reject(error)
      } finally {
        infoLogger("ブラウザクローズ開始")
        browser.close().then(() => infoLogger("ブラウザクローズ終了"))
      }
    }

- `page.$eval`の追加

1. `yarn run ts-node-dev src/puppeteer.ts`

コンソールに取得したい文字が出力されればOK!
他にも取得の方法はありますが、[こちらの記事](https://qiita.com/go_sagawa/items/85f97deab7ccfdce53ea
)を参考にして試行錯誤してみると良いです。

#### +a
app.ts

    app.get("/", async (_req, res) => {
    scrapingData()
    res.end("Hello World")
    })

puppeteer.tsの関数をappに入れることでまとめることができる
- `yarn dev`
- `curl http://localhost:8080`
上記を実行するとデータ取得開始

#### 自分の解釈

`$`：要素取得
`$eval`：コールバックで要素取得
`$$`：複数要素取得
`$$eval`：コールバックで複数要素取得

## 最後に


本当に人が操作しているみたいに動かすので、１つ１つの動きを実際に手で動かしてみるとコードが書きやすいです。また、目で確認するためにスクリーンショットを挟み込みながら進めていくことをオススメします！



## 参考文献

https://github.com/puppeteer/puppeteer

https://qiita.com/go_sagawa/items/85f97deab7ccfdce53ea