昨日までのはこちら
100日後にエンジニアになるキミ - 70日目 - プログラミング - スクレイピングについて
100日後にエンジニアになるキミ - 66日目 - プログラミング - 自然言語処理について
100日後にエンジニアになるキミ - 63日目 - プログラミング - 確率について1
100日後にエンジニアになるキミ - 59日目 - プログラミング - アルゴリズムについて
100日後にエンジニアになるキミ - 53日目 - Git - Gitについて
100日後にエンジニアになるキミ - 42日目 - クラウド - クラウドサービスについて
100日後にエンジニアになるキミ - 36日目 - データベース - データベースについて
100日後にエンジニアになるキミ - 24日目 - Python - Python言語の基礎1
100日後にエンジニアになるキミ - 18日目 - Javascript - JavaScriptの基礎1
100日後にエンジニアになるキミ - 14日目 - CSS - CSSの基礎1
100日後にエンジニアになるキミ - 6日目 - HTML - HTMLの基礎1
今回もスクレイピングの続きです。
前回はリクエストを行い情報取得をするところまで行いました。
今回からは通信後のデータの解析方法をやっていきます。
HTMLを解析する方法
レスポンスボディは基本テキスト型(文字列)構造であるため
そのままでは必要な情報を取り出すのに都合が悪いです。
HTMLの構文を解析するにはPython言語ではBeautifulSoup
ライブラリを用います
BeautifulSoup
ライブラリを用いて、文字列型のデータを
BeautifulSoup型
に変換します。
from bs4 import BeautifulSoup
変数名 = BeautifulSoup(レスポンスオブジェクト名.content , "HTMLパーサー名")
これでBeautifulSoup型
にデータ変換できます。
試しに生のHTMLを変換してみましょう。
from bs4 import BeautifulSoup
html='''
<HTML>
<head><title>タイトルだよ</title></head>
<body>
<h1>h1だよ</h1>
<h2>h2だよ</h2>
<div class='c1'>
<a class='a1' href='http://sample.com'><p>sampleへのリンク</p></a>
</div>
<div id='id1'>
<p><a href='http://sample.com'>aaa</a></p>
</div>
</body>
</HTML>
'''
# html.parserを用いてレスポンスをBeautifulSoupに変換
soup = BeautifulSoup(html , "html.parser")
print(type(soup))
データ型はbs4.BeautifulSoup
です。
変数をそのままprintして中身をみると文字列型と同じように見ることができます。
これ以降はBeautifulSoup型
のメソッドなどがつかえるようになり
それを使ってHTMLの構文にしたがって処理をすることが出来ます。
HTMLパーサー
パース
とは一定の規則で記述されたテキストを解析し、プログラムで扱いやすいようなデータに変換する処理のことです。
パーサーはHTMLをパース
する際のプログラムです。
Python言語で指定できるHTMLパーサー
は主に次の3つがあります。
パーサー名 | 内容 |
---|---|
html.parser | デフォルトのパーサー |
lxml | C言語の高速実装な解析器,複雑な構造や動的な物に少し弱い |
html5lib | html5の規則に対応したパーサー |
BeautifulSoup
での変換時には何かしらのパーサー
を指定します。
HTMLについて
HTMLは木構造(入子構造)のマークアップ言語で、ハイパーリンクや画像等のマルチメディアを埋め込むハイパーテキストとしての機能、見出しや段落といったドキュメントの抽象構造フォントや文字色の指定などの見た目の指定、などといった機能があります。
タグ
とは、<
で始まり、>
で終わっている部分(マークアップ)のみを指し
要素(エレメント)
は開始タグ~終了タグ
に囲まれた全体を指す概念です。
要素(エレメント)
<開始タグ>コンテンツ</終了タグ>
HTMLには様々なタグ
が存在し、構文解析はタグ
の構造を読み解いてゆく方法で行います。
BeautifulSoupでの構文解析
さて構文解析をするサンプルを用意して構文解析してみましょう。
from bs4 import BeautifulSoup
html='''
<HTML>
<head><title>タイトルだよ</title></head>
<body>
<h1>h1だよ</h1>
<h2>h2だよ</h2>
<div class='c1'>
<a class='a1' href='http://sample.com'><p>sampleへのリンク</p></a>
</div>
<div id='id1'>
<p><a href='http://sample.com'>aaa</a></p>
</div>
</body>
</HTML>
'''
soup = BeautifulSoup(html , "html.parser")
任意のタグを指定して要素の取得
以下、BeautifulSoup型の変数をsoup
とします。
soup.タグ
#任意の部分を個別抽出
h1 = soup.html.body.h1
p1 = soup.html.body.p
a1 = soup.html.body.a
z1 = soup.html.body.z
print(h1)
print(p1)
print(a1)
print(z1)
print(type(a1))
-------------------------------------------
<h1>h1だよ</h1>
<p>sampleへのリンク</p>
<a class="a1" href="http://sample.com"><p>sampleへのリンク</p></a>
None
<class 'bs4.element.Tag'>
タグが複数ある場合は最初に見つかったものが返り、見つからない場合はNoneが返ります。
任意のidやクラスで要素を探す
soup.find(id="id名")
soup.find(class_="クラス名")
soup.find(text="テキスト")
任意で検索したものが複数有った場合は最初に見つかった要素(HTMLタグ)が取得できます。この場合も取得できない場合はNone
となります。
div = soup.find('div',id='id1')
p = div.find('p')
a = p.find('a')
print(div.a)
------------------------------------
<a href="http://sample.com">aaa</a>
title = soup.find(id="id1")
body = soup.find(class_="c1")
text = soup.find(text="aaa")
print(title)
print(body)
print(text)
------------------------------------
<div id="id1">
<p><a href="http://sample.com">aaa</a></p>
</div>
<div class="c1">
<a href="http://sample.com"><p>sampleへのリンク</p></a>
</div>
aaa
複数の条件で任意のidやクラスで要素を探す
soup.find('タグ名',attrs={'要素名':'値','要素名':'値'})
# attrs = の後に辞書型で指定する
a_tag = soup.find("a", attrs={"class": "a1", "href": "http://sample.com"})
print(a_tag)
------------------------------------
<a class="a1" href="http://sample.com"><p>sampleへのリンク</p></a>
任意のidやクラスで複数の要素を取得する
find_all('タグ名')
soup.find_all(id="id名")
soup.find_all(class_="クラス名")
soup.find_all(text="テキスト")
soup.find_all('タグ名' , attrs={'要素名':'値' , '要素名':'値'})
links = soup.find_all("a")
print(links)
----------------------------
[<a class="a1" href="http://sample.com"><p>sampleへのリンク</p></a>,
<a href="http://sample.com">aaa</a>]
find_all
を用いると条件に該当するHTMLタグの情報全てが取得され
結果はリスト型になります。
何も取得できない場合は要素なしの空のリスト型になります。
タグはリスト型で複数指定が出来ます
links = soup.find_all(["a", "h1"])
for link in links[0:5]:
print(link)
----------------------------
<h1>h1だよ</h1>
<a class="a1" href="http://sample.com"><p>sampleへのリンク</p></a>
<a href="http://sample.com">aaa</a>
正規表現を用いる方法
タグやid,クラス名での検索方法では完全一致で検索されます。
部分一致で検索したい場合はre
ライブラリを用いて探すことが出来ます。
re.compile('検索文字列')
この条件で指定した要素は部分一致で検索されます。
import re
soup.find_all("タグ名", text=re.compile("検索文字列"))
import re
# re.compile でテキストに「aa」が含まれるものを抽出
links = soup.find_all("a", text=re.compile("リ"))
for link in links[0:5]:
print(link)
----------------------------
<a class="a1" href="http://sample.com"><p>sampleへのリンク</p></a>
cssセレクタを使ったタグの取得
CSSセレクタ
とは、どの要素がそのスタイル規則によって影響されるかを指定するものでスクレイピングでは指定方法を工夫することで、特定の部分の要素を抽出することができます。
なおBeautifulSoupを使ったスクレイピングでCSSセレクタ
はHTMLパーサー
にも依存します。
CSSセレクタで要素を一つだけ取り出す
soup.select_one(セレクタ)
CSSセレクタで複数要素を取り出す
soup.select(セレクタ)
# select 結果はリスト型
links = soup.select('a[href^="http://s"]')
for link in links[0:5]:
print(link)
---------------------------
<a class="a1" href="http://sample.com"><p>sampleへのリンク</p></a>
<a href="http://sample.com">aaa</a>
CSSセレクタの種類
下記のようなセレクタの指定ができます。
| セレクタ | 例 | 例の説明
|----------------------|-----------------------|------------------------------------------------------------------------------|---|
| .class | .intro | class="intro" を持った全要素を選択する | |
| #id | #firstname | id="firstname" を持った要素を選択する | |
| * | * | 全要素を選択する | |
| element | p | 全ての p 要素を選択する | |
| element,element | div, p | 全ての div 要素と、全ての p 要素を選択する | |
| element element | div p | div 要素内の、全ての p 要素を選択する | |
| element>element | div > p | 親要素が div 要素である、全ての p 要素を選択する | |
| element+element | div + p | div 要素の直後に配置された全ての p 要素を選択する | |
| element1~element2 | p ~ ul | p 要素が先行しているすべての ul 要素を選択する | |
| [attribute] | [target] | target 属性を持った全ての要素を選択する | |
| [attribute=value] | [target=_blank] | target="_blank" を持った全ての要素を選択する | |
| [attribute~=value] | [title~=flower] | 単語 "flower" を含む title 属性を持った全ての要素を選択する | |
| [attribute^=value] | a[href^="https"] | href 属性値が "https" で始まるすべての a 要素を選択する | |
| [attribute*=value] | a[href*="w3schools"] | href 属性値が部分文字列 "w3schools" を含んでいるすべての a 要素を選択する | |
属性の取得
上記で取得したものはタグ(要素)になります。
要素の中から属性を取り出すには下記のように行います。
タグ.get("属性名")
例:
aタグのhref属性
aタグ.get('href')
テキストの取得
開始 - 終了タグ
で囲まれた部分がテキストになります。
テキストはタグ.text
で抽出できますが、タグが取得できていない場合は
抽出はできないので注意が必要です。
print(soup.a)
print(soup.a.text)
----------------------------
<a class="a1" href="http://sample.com"><p>sampleへのリンク</p></a>
sampleへのリンク
まとめ
HTMLからBeautifulSoupへの変換方法
BeautifulSoupからタグの取得の仕方
タグから属性やテキストの取得の仕方をやりました。
これで情報のほとんどを取得できたはずです。
様々なやり方があるので、試しながら少しづつ覚えましょう。
君がエンジニアになるまであと28日
作者の情報
乙pyのHP:
http://www.otupy.net/
Youtube:
https://www.youtube.com/channel/UCaT7xpeq8n1G_HcJKKSOXMw
Twitter:
https://twitter.com/otupython