13
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PuppeteerでReactの公式サイトを巡回してReactハンドブックを自作した

Last updated at Posted at 2019-03-26

ハンドブック作った

IMG_20190326_015314.jpg

Reactの翻訳完成率が100%になり、公式のドキュメントが日本語で読めるようになりました:clap: ありがてぇ。
スクリーンショット 2019-03-19 1.55.48.png
紙で読みたい人のために印刷用に整形してPDFにしたので、2019/03/20時点のものはここから落とせます。
追記:PDFにしちゃえばKindleでも読めるらしい。(参考: PDFの技術書をKindleで快適に読む
)


公式のドキュメントにはAPIや使い方だけでなく、流儀や設計なども書いてあるんで、そういうところが日本語で読めるようになるのはまじであざあすでしかない。

Puppeteerを使えば、PDFで保存できるので、プリントアウトしてハンドブック的な奴をサクッと作っみたいと思います!

全体のコードはここに置いてあります!


これからはPuppeteerのevaluate()pdf()の話しかしませんw さーせん!

他のサイトとかでやりたい人は参考になるかも?


なにはともあれ npm init

とりあえず Puppeteer があればOKなので下記を実行して、
$ npm init -y
$ npm i puppeteer

セットアップ完了。

スクリーンショット 2019-03-20 12.39.51.png

下記の記事を参考にindex.jsを作ってPDF出力にチャレンジしてみる。
参考: ヘッドレスブラウザの Puppeteer を利用して WEB ページを PDF 出力してみる。


PuppeteerでDocsのページをクローリング

css-ではじまるセレクタの部分はすぐに変わるはずなのでソッコーで動かなくなると思いますw

とりあえず、下記の画像の場所のhrefの一覧をPuppeteerで取得して、
そのリストにアクセスしていって、page.pdf()をキメれば多分やりたいことはできるな。
スクリーンショット 2019-03-19 20.14.30.png


とりあえずpage.evaluate()をすればPuppeteerがアクセスしたページでJSを実行してくれるっぽいのでクロームのインスペクタでセレクタ名を調べながら下記のcreateTarget関数を書いた。(使い捨てのスクリプトなので雑です。)

page.evaluate()内でのreturnpage.evaluate()の返り値で取れるからすごい。
あと、page.evaluate()内はコンテキストが違うので、外で定義している変数にはアクセスできない。

// サイドバーの見出しからページの一覧を取得する {見出し: [ページ1, ページ2 ...]} みたいな感じで返す
const createTarget = async page => {
  await page.goto("https://ja.reactjs.org/docs/getting-started.html");
  return await page.evaluate(({}) => {
    const contentsCss = ".css-1j8jxus";
    return Array.prototype.reduce.call(
      document.querySelectorAll(contentsCss),
      (acc, elem) =>
        Object.assign(acc, {
          [elem.getElementsByTagName("div")[0]
            .innerText]: Array.prototype.map.call(
            elem.nextElementSibling.children,
            children =>
              children
                .getElementsByTagName("a")[0]
                .href.replace("https://ja.reactjs.org/docs/", "")
                .replace(".html", "")
          )
        }),
      {}
    );
  }, {});
};

したら下に、見出しがkeyでページのIDの配列がvalueObjectが取得できるのでこれを使ってクローリングしていくっ!

{
    "INSTALLATION": [
        "getting-started",
        "add-react-to-a-website",
        "create-a-new-react-app",
        "cdn-links"
    ]...
}

PDFの作成!でも微調整が必要。

page.pdf()を使えば今いるページをPDFにしてくれる。素直にやると下記の画像みたいな感じになる。
スクリーンショット 2019-03-20 12.46.25.png
スクリーンショット 2019-03-20 12.47.13.png


これでもいいけど、実際に印刷する前に下記の点を改善したい。

  • ヘッダーがいらない
  • フッターがいらない
  • サイドバーがいらない(でもどこを見ているのかは見出しレベルでわかるようにしたい)
  • 文字はもっと小さくしたい
  • ページネーションがいらない

そこで微調整をするためにpage.pdf()にオプションを渡したり、page.evaluate()をしてstyleを変更していく!


page.pdf()にはこんな感じのオプションを設定した。
headerTemplateのプロパティにcreateTarget関数で取れる見出しの情報を見れるようにしたり、scaleプロパティで縮小表示にしたりまぁそんな感じ。

    await page.pdf({
      displayHeaderFooter: true,
      headerTemplate: `<div style="font-size: 10px; margin-left: 40px;"><span>${content}</span> / <span class="title"></span></div>`,
      margin: { top: 50, bottom: 50 },
      scale: 0.5,
      path: `pdf/${content}/${index}-${item}.pdf`
    });

スタイルの微調整はこんな感じ。ヘッダー、フッター、サイドバーなどを消したり、文字の間隔を狭めたり。

    await page.evaluate(({}) => {
      const paginationCss = ".css-uygc5k";
      const sideNavCss = ".css-1kbu8hg";
      const contentText = ".css-7u1i3w p";
      document.getElementsByTagName("header")[0].style.display = "none";
      document.getElementsByTagName("footer")[0].style.display = "none";
      document.querySelector(sideNavCss).style.display = "none";
      document.querySelectorAll(contentText).forEach(p => {
        p.style.maxWidth = "100%";
        p.style.marginTop = "0px";
      });
      const pagination = document.querySelector(paginationCss);
      if (pagination) pagination.style.display = "none"; // ページネーションがあれば非表示
    }, {});

あとはエントリーポイントを作って、実行するだけ!


$ node index.js

うん。結構、本っぽい!

スクリーンショット 2019-03-20 13.07.20.png


createTarget関数は見出しをキーにして各コンテンツを配列で返しているので下記の画像みたいにディレクトリに別れて出力している。
実行結果はこんな感じ。

スクリーンショット 2019-03-20 13.06.09.png

実行可能な全体のコードは全体のコードはここに置いてあります!


プリントアウトして本にする

今回はADVANCED GUIDESが読みたいなと思っていたので、これをPDF結合します。
Webで「PDF結合」とか調べると、下記がヒットしたのでそれを使って結合していきます。
https://smallpdf.com/jp/merge-pdf

83pのPDFができました。

スクリーンショット 2019-03-20 14.37.43.png

さあてネットプリントのクラウドにアップロードしたしコンビニに行って印刷してきますか!
コンビニ高かったんで(1枚 20円)、kinkos(1枚 8円)に行ってやった。


感想

  • 寝る前にソファーで読んだりしてる。いい。
  • kindleでも読みたいという人の意見もあった。できるっぽい。( PDFの技術書をKindleで快適に読む)
  • 久しぶりにdomを触ったら懐かしくもやはり辛かった。
  • ただのPuppeteerを使った話になってしまった :-)
13
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?