0
1

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 3 years have passed since last update.

100日後にエンジニアになるキミ - 72日目 - プログラミング - スクレイピングについて3

Posted at

昨日までのはこちら

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

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?