
HTMLが取得できたら、そのページの情報は、手中に収めたようなものです。
でも、スクレイピングは結構難しいというのも事実で、技術的アプローチと、その特性についても考えてみるのもいい機会かもしれません。
手始めのスクレイピングから、深い情報取得、安定したスクレイピング手法などについてサンプルソースコードを元に解説したいと思います。
プログラミングが苦手な人(とくに学習中の人)にも、理解しやすいように学習を進めていきます。
スクレイピングはDOM操作
取得したWebページのHTMLから何かしらの情報を取得するには、DOM (Document Object Model) と言われるHTMLの構造を理解して、
その中の特定の要素 (Element) の文字情報や属性情報などを取得する処理をします。
DOMは、Webページごとにそれぞれ独自でセットされているので、同じサイトであれば同じルールになっている場合もあるかもしれませんが、基本的にルールは全て違うという理解をしておかなければいけません。
HTMLの基本構造
多くのページでよくある構成として、次のHTMLタグと属性について必要最低限理解しておかなければいけません。
主要タグ
div, span, a, table, ul, li
その他色々なDOM構造に合わせたタグを読み取れるようにしましょう。
タグ属性
class, id
属性は、data属性などのように、無限にセットできてしまうので、HTMLを見て特性を判断することも重要です。
共通情報
ページタイトル : titleタグ
言語情報 : htmlのlang属性
メインヘッダ : h1タグ(複数の場合もある)
ブラウザを使ってDOMを理解する
GoogleChromeやFirefox、Safari、Operaなど、どのブラウザにも、「ディベロッパツール」という開発用のサポートツールが用意されています。
それらを使ってDOM構造を読み解いてみましょう。
GoogleChromeの場合
ブラウザの右上にある、縦の3点リーダーをクリックすると表示されるリストの、
「その他のツール」 - 「ディベロッパ ツール」を選択すると、表示されます。
Firefoxの場合
上部メニューの「ツール」 - 「ブラウザツール」 - 「ウェブ開発ツール」を選択すると、表示されます。
Safariの場合
上部メニューの「Safari」 - 「設定」を開き、
「詳細タブ」を開き、「Webディベロッパ用の機能を表示」にチェックをいれます。
次に、上部メニューの「開発」-「Webインスペクタを表示」を選択。
もっと手軽にアクセスする方法
GoogleChromeは、Cmmand + Option + I
FirefoxやSafariは、F12キー
を押す事で、上記のWebディベロッパツールを素早く起動できます。
また、画面を右クリックして、「検証」や「詳細」という項目(Safariは、「要素の詳細を表示」)を選択すると、ディベロッパツールを立ち上げる事もできます。
プログラムでデータ取得
前回のHTMLを取得するプログラムで、Yahooのニュースページのトピック一覧を取得するプログラムに書き換えてみましょう。
少しプログラムに構造体を意識した構造に変えました。(少し難しく感じたらごめんなさい)
Yahooニュース取得スクレイピング
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSONPスクレイピング</title>
<link rel="stylesheet" href="style.css" />
<script type="module" src="main.js"></script>
</head>
<body>
<h1>JSONPデータ表示</h1>
<div id="output">読み込み中...</div>
</body>
</html>
style.css
#output{
border:1px dashed #AAA;
white-space: pre-wrap;
word-break:break-all;
padding:10px;
}
main.js
import { GetHtml } from "./get_html.js"
class Main{
constructor(){
new GetHtml().then(this.html_loaded.bind(this))
}
get output(){
return document.getElementById(`output`)
}
html_loaded(data){
this.output.textContent = JSON.stringify(data, null, " ")
}
}
// ページ読み込み後に起動する処理
switch(document.readyState){
case "complete":
case "interactive":
new Main();break
default:
window.addEventListener("DOMContentLoaded", (()=>new Main()))
}
get_html.js
export class GetHtml{
gas_deploy_id = `AKfycbz2t8hLsEELqeZzbtQzjRW8IZVAP_MmSoaUFKsAT0sFKPjhFDXF42L2wdX-Z8-i3RZxcQ`
target_url = "https://news.yahoo.co.jp/"
constructor(){
this.promise = new Promise((resolve, reject) => {
this.resolve = resolve
this.reject = reject
this.load()
})
this.then = this.promise.then.bind(this.promise)
}
load(){
const url = `https://script.google.com/macros/s/${this.gas_deploy_id}/exec?url=${encodeURI(this.target_url)}`
fetch(url)
.then(e => e.text())
.then(this.loaded.bind(this))
}
loaded(e){
const data = JSON.parse(e)
const doc = new DOMParser().parseFromString(data.html, "text/html")
this.finish({
title : this.get_title(doc),
lists : this.get_news_lists(doc),
})
}
get_title(doc){
return doc.querySelector("title").textContent
}
get_news_lists(doc){
const lists = doc.querySelectorAll(`#contentsWrap .sc-1d6xg0e-3 > div > ul > li > a`)
return lists && lists.length ? Array.from(lists).map(e => e.textContent) : null
}
finish(data){
this.resolve(data)
}
}
実行結果
コード解説
基本の仕組みとしては、htmlに書かれているdivタグのid="output"属性に、取得したデータを書き込みます。
Javascript内で、主要の関数などをピックアップしておきます。
getElementById( id名 )
属性がidの値を指定して、elementの取得を行います。
idは、ページ内でユニークの仕様なので、取得できるelementが1つの単体です。
classを取得する場合は、"getElementsByClassName( class名 )" で取得できますが、複数のelementが配列(elementArray)で返ってくるので、その違いに注意しましょう。
new Promise()
非同期の完了イベントを取得する事ができるようになります。
new Promise()が設定された場合、作成されたインスタンスの .then() プロパティで、完了イベントをゲットできます。
また、Promise内では、resolve() に値を渡す事で、then プロパティの受け渡し値として扱えます。
※初心者の人は、レベルの高い使い方になるので、classの使い方をまずは学習してから、Promiseを覚える順番に覚えるといいでしょう。
参考 :
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise
new DOMParser()
HTMLをDOMオブジェクトとして扱えるようにするクラス処理です。
今回のソースでは、以下のように使っていて、htmlの部分を、任意のタグ構造で入れ替えると、DOM操作ができるオブジェクトに変換してくれます。
const doc = new DOMParser().parseFromString(data.html, "text/html")
querySelector()とquerySelectorAll()
jQueryからJavascriptに移植されたかなり便利な関数です。
CSSのDOMセレクタを指定して、任意の element を取得できるパワフルな関数です。
querySelector()は、指定するセレクタが複数ある場合は、最初に見つかった1つのみのエレメントを返すのに対して、
querySelectorAll()は、戻り値が配列になる点で、適切に使用する事で非常に流用度の高い使い方ができるでしょう。
あとがき
URLを変えて、色々なサイトでの情報を取得してみるといいと思います。
おそらく自分でやってみると、スクレイピングの難しさに直面すると思いますが、必ず取得できる方法はあるので、心が折れないようにやるのがポイントかもですね。
分からない時は、「知っている人に聞く」というのは、鉄則です。
でも、取得したいサイト側で、非同期処理で表示されていたり、ログインを伴う画面遷移などがある場合に、まずはどうやってデータをスクレイピングすればいいのか迷うと思いますが、
この辺もjavascriptのプログラミングレベルが上がれば、難なく取得できるようになる事も多いので、今できなくても諦める必要はありません。
そして、次回はスクレイピングのルールとマナーについて学習を進めていきましょう。
0 件のコメント:
コメントを投稿