WEBその他

WEBスクレイピング入門(TypeScript)

WEB
この記事は約13分で読めます。

今回はWEB上の文言を集める、WEBスクレイピングについて書きます。
今回の内容では、nodeの実行環境で、TypeScript + Puppeteerを使ってみます。

jQueryの書き味が好きな人は、後述のCheerioなどを使用しても問題ないです。

今回の成果物

この記事では、これをターミナル上で出力します。
今回使用する技術の解説なんか要らない!という方は環境構築まで飛んでください。

[
  {
    title: 'Webスクレイピング禁止サイト5選!違法にならない ... - PigData',
    url: 'https://pig-data.jp/blog_news/blog/scraping-crawling/web5/#:~:text=%E3%82%B9%E3%82%AF%E3%83%AC%E3%82%A4%E3%83%94%E3%83%B3%E3%82%B0%EF%BC%88%E3%81%BE%E3%81%9F%E3%81%AF%E3%82%AF%E3%83%AD%E3%83%BC%E3%83%AA%E3%83%B3%E3%82%B0%EF%BC%89%E3%81%A8%E3%81%AF,%E3%81%99%E3%82%8B%E3%81%93%E3%81%A8%E3%81%8C%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82'
  },
  {
    title: 'スクレイピングとは?違法性があるデータの活用方法とその対処を解説',
    url: 'https://legalmedia.coconala.com/3182#:~:text=%E8%A7%A3%E8%AA%AC%E3%81%97%E3%81%BE%E3%81%99%E3%80%82-,%E8%91%97%E4%BD%9C%E6%A8%A9%E3%82%92%E4%BE%B5%E5%AE%B3%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B,%E3%81%82%E3%82%8B%E3%82%B1%E3%83%BC%E3%82%B9%E3%82%82%E5%A4%9A%E3%81%8F%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82'
  },
  {
    title: '図解!PythonでWEB スクレイピングを極めよう!(サンプルコード付き ...',
    url: 'https://ai-inter1.com/python-webscraping/'
  },
  // 省略
]

技術選定

今回の内容としては、下記のとおりです。

・Node.js 12.18.3
・Puppeteer 5.5.0
・TypeScript 4.1.3

スクレイピング技術の選択肢

WEBスクレイピングする上で、主に3つのライブラリが有名です。
それぞれの特徴についてまとめてみました。

Puppeteer

PuppeteerはGoogleによって開発されたNode.js用のライブラリで、Webブラウザを自動化することができます。

Puppeteerを使用すると、ブラウザの操作やDOMの解析が可能になります。

PuppeteerのコードはTypeScriptで記述されており、APIもTypeScriptで定義されているため、TypeScriptでの開発に適しています。

Puppeteer | Puppeteer
Build status

Cheerio

jQueryのような構文を使用してHTMLをスクレイピングすることができるNode.js用のライブラリです。

Cheerioは、DOMを解析するためのAPIを提供しており、jQueryと同じようにセレクタを使用してHTMLを取得できます。

TypeScriptで開発されているわけではありませんが、@types/cheerioというTypeScriptの型定義が用意されているため、TypeScriptでの開発に適しています。

cheerio-httpcli
http client module with cheerio & iconv(-lite) & promise. Latest version: 0.8.3, last published: 2 years ago. Start using cheerio-httpcli in your project by run...

JSDOM

JSDOMは、Node.js用のJavaScript実装であるV8エンジンを使用して、DOMを解析するためのAPIを提供するライブラリです。

ブラウザの動作をエミュレートすることができるため、ブラウザで実行されるJavaScriptをNode.js上で実行することができます。

TypeScriptで開発されているわけではありませんが、@types/jsdomというTypeScriptの型定義が用意されているため、TypeScriptでの開発に適しています。

jsdom
A JavaScript implementation of many web standards. Latest version: 24.0.0, last published: a month ago. Start using jsdom in your project by running `npm i jsdo...

Puppeteerにしてみた

今回はPuppeteer(パペッター)を選択しました。
下記、理由です。

比較的新しい技術である

リリースが新しい順に並べると、下記のような順になりました。

  • Puppeteer: 2017年4月
  • JSDOM: 2015年8月
  • Cheerio: 2010年9月

Puppeteerは、内部処理がTypeScriptで記述されているため、TypeScriptでの開発に適しています。

APIもTypeScriptで定義されているため、開発者がライブラリを使用する際には、受け取った値の型の情報が手に入ります。

これにより、開発者は型安全性を担保出来て、コードの可読性や保守性を向上させることができます。

ブラウザ自動化が可能

Puppeteerは、ChromeやChromiumといったブラウザを自動化することができます。

これにより、Webページの操作やスクレイピングを自動化することができ、動的なWebサイトのスクレイピングにも適しています。

そのため、スクレイピングに関して一日の長がある、Pythonと遜色ない挙動を実現する事が出来ます。

ユーザーが行う操作を再現できる

Puppeteerは、ブラウザでのユーザーの操作を自動化することができます。

例えば、ボタンのクリックやスクロールなどの操作を再現することができます。これにより、ログインやページ遷移に関しても忠実に再現可能です。

環境構築

まずは適当なディレクトリを作って、イニシャライズします。

$ mkdir sample-project
$ cd sample-project
$ npm init -y

上記を実行して、下記のログが出力されたら成功です。

Debugger attached.
Wrote to /Users/impl/Repos/Toys/misc/sample-project/package.json:

{
  "name": "sampel-project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}


Waiting for the debugger to disconnect...

それでは、関連するライブラリをインストールしていきます。
今回はTypeScriptとPuppeteer、追加でnode系のライブラリを一緒にインストールします。

$ npm i typescript @types/node @types/puppeteer

インストール出来たら、一応バージョンを確認します。
バージョンが確認出来たら、インストールが完了したことが把握できます。

$ npx tsc --version
> Version 4.9.5 

実行ファイルの作成

まずは、tsconfig.jsonを作成します。

$ npx tsc --init

その次に、実行環境としてsrcディレクトリを作成します。
その後、index.tsを作成しましょう。

$ mkdir src
$ touch src/index.ts

Hello, World!の実行

まずは、コードが実行可能かどうか確認します。
オーソドックスにHello, World!と出力してみましょう。

// index.ts
function sayHello(name: string): string {
  return `Hello, ${name}!`;
}

const greeting: string = sayHello('World');
console.log(greeting); // => "Hello, World!"

上記のコードをindex.tsに記載したら、tscコマンドで実行出来たか確認しましょう。

$ npx tsc

src内にindex.jsが生成されたら、実行環境が整っていることが確認されました。

それでは生成されたindex.jsを実行して、実際に挨拶してみましょう。
下記のように挨拶が出来たら、成功です。

$ node ./src/index.js                                  
Debugger attached.
Hello, World!
Waiting for the debugger to disconnect...

実際にスクレイピングのコードを書く

では、index.tsを書き換えます。
先ほど書いたものから、下記へ置換してください。

import puppeteer from 'puppeteer';

// スクレイピングするための関数
async function scrapeGoogle(query: string) {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto(`https://www.google.com/search?q=${query}`);

  const results = await page.$$eval('.tF2Cxc', (elements) =>
    elements.map((element) => ({
      title: element.querySelector('.DKV0Md')?.textContent,
      url: element.querySelector('.yuRUbf a')?.getAttribute('href'),
    }))
  );

  console.log(results);
  await browser.close();
}

// 関数を実行
scrapeGoogle('スクレイピング');

このコードは、Puppeteerを使用してブラウザを起動し、Googleの検索結果ページにアクセスします。

次に、$$evalメソッドを使用して、クラス名がtF2Cxcの要素をすべて取得、タイトルとURLを抽出します。

最後に、結果をコンソールに出力します。

実行してみる

このコードを実行すると、スクレイピングというキーワードでGoogle検索を行い、最初のページの検索結果のタイトルとURLが配列として出力されます。

// index.jsを生成
$ npx tsc
// 生成したindex.jsを実行
$ node ./src/index.js

今回の実行結果

Googleの検索結果に依存するため、毎回この配列にはなりません。
このような実行結果が出力されたら成功です。

[
  {
    title: 'Webスクレイピング禁止サイト5選!違法にならない ... - PigData',
    url: 'https://pig-data.jp/blog_news/blog/scraping-crawling/web5/#:~:text=%E3%82%B9%E3%82%AF%E3%83%AC%E3%82%A4%E3%83%94%E3%83%B3%E3%82%B0%EF%BC%88%E3%81%BE%E3%81%9F%E3%81%AF%E3%82%AF%E3%83%AD%E3%83%BC%E3%83%AA%E3%83%B3%E3%82%B0%EF%BC%89%E3%81%A8%E3%81%AF,%E3%81%99%E3%82%8B%E3%81%93%E3%81%A8%E3%81%8C%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82'
  },
  {
    title: 'スクレイピングとは?違法性があるデータの活用方法とその対処を解説',
    url: 'https://legalmedia.coconala.com/3182#:~:text=%E8%A7%A3%E8%AA%AC%E3%81%97%E3%81%BE%E3%81%99%E3%80%82-,%E8%91%97%E4%BD%9C%E6%A8%A9%E3%82%92%E4%BE%B5%E5%AE%B3%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B,%E3%81%82%E3%82%8B%E3%82%B1%E3%83%BC%E3%82%B9%E3%82%82%E5%A4%9A%E3%81%8F%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82'
  },
  {
    title: '図解!PythonでWEB スクレイピングを極めよう!(サンプルコード付き ...',
    url: 'https://ai-inter1.com/python-webscraping/'
  },
  {
    title: 'ウェブスクレイピング - Wikipedia',
    url: 'https://ja.wikipedia.org/wiki/%E3%82%A6%E3%82%A7%E3%83%96%E3%82%B9%E3%82%AF%E3%83%AC%E3%82%A4%E3%83%94%E3%83%B3%E3%82%B0'
  },
  {
    title: 'データ収集を大幅に効率化する「スクレイピング」とは ...',
    url: 'https://data.wingarc.com/scraping-27053'
  },
  {
    title: 'Webスクレイピングとは?基本や仕組み、活用事例まで解説',
    url: 'https://www.octoparse.jp/blog/web-scraping/'
  },
  {
    title: 'データ収集できるスクレイピングとは?効率化にツールが必要 ...',
    url: 'https://www.tryeting.jp/column/6325/'
  },
  {
    title: 'PythonでWebスクレイピングをする方法を解説!【入門編】',
    url: 'https://udemy.benesse.co.jp/development/python-work/web-scraping.html'
  },
  {
    title: 'スクレイピングとは何かやさしく解説。違法?クローリングと ...',
    url: 'https://www.sbbit.jp/article/cont1/71102'
  },
  {
    title: '【初心者向け】PythonでWebスクレイピングをしよう!',
    url: 'https://www.pasonatech.co.jp/workstyle/column/detail.html?p=2638'
  },
  {
    title: 'Octoparse (オクトパース)でスクレイピングをしよう ...',
    url: 'https://nocodedb.world/archives/6252'
  },
  {
    title: '使える!データ収集術「ウェブスクレイピング」を伝授します',
    url: 'https://www.idnet.co.jp/column/page_240.html'
  }
]
Waiting for the debugger to disconnect...