カテゴリー

Python基礎

【python&Webスクレイピング】初心者のWebスクレイピング

2021年6月4日

こんな人にオススメ

pythonでWebスクレイピングできるけど、まずは何をすればいい?

モジュールは何を入れればいい?

ということで、今回は自分の勉強の記録としてWebスクレイピングの導入を記事にしてみた。Webスクレイピングはイメージはできていたが、実際に書いたことはなかった。

執筆者と同じくWebスクレイピング始めてみようと思う方は本記事も参考にしていただければ幸いだ。

python環境は以下。

  • Python 3.9.4
  • requests 2.25.1
  • beautifulsoup4 4.9.3
スポンサーリンク
スポンサーリンク

運営者のメガネです。TwitterInstagramも運営してます。

自己紹介はこちらから、お問い合わせはこちら。

運営者メガネ

必要なimport

必要なimportは以下の二つ。他にも方法はあるが、簡単かつメジャーなのは以下の二つ。

import requests
from bs4 import BeautifulSoup

anacondaで入れる際にはそれぞれ以下のコードでインストール可能。一応、ご自身で検索していただければ幸いだ。

  • requests: conda install -c anaconda requests
  • conda install: -c anaconda beautifulsoup4

流れ

  1. requestsでHTMLとしてデータを取得
  2. BeautifulSoupで必要なデータを抽出

requests

requestsモジュールは、Webサイトの情報を取得するためのモジュール。これがないとスクレイピングできない。anacondaのインストールコマンドは以下。

conda install -c anaconda requests

BeautifulSoup

BeautifulSoupモジュールは、HTMLからデータを取り出すためのモジュール。

conda install -c anaconda beautifulsoup4

WebサイトのデータをHTMLとして出力

サイトのステータスコードの取得

ステータスコードとは、Webサーバからのレスポンスを表す3桁の数字。有名なのが「404 Not Found」。ざっくりいうと、

  • 100番台: 情報レスポンス
    • 処理に時間がかかっているが継続中
  • 200番台: 成功レスポンス
    • 処理が成功して正常にレスポンスできている
  • 300番台: リダイレクション
    • リダイレクト(サイトが新しいURLになった時に自動で転送)などで追加の処理が必要
  • 400番台: クライアントエラー
    • 正常にレスポンスできない
  • 500番台: サーバーエラー
    • サーバーに問題がありエラー

requestsモジュールのgetメソッドの引数に見たいURLを指定し、サーバーからのレスポンスを取得。ステータスコードが200なので正常に処理されている。

# getメソッドは引数にURLを指定しwebページにアクセスしてサーバーからのレスポンスを取得
site = requests.get('<https://www.google.com>')

# サイトのステータスコード
# 正常にサイトにアクセスできていることを示す
print(site)
# <Response [200]>

サイトデータをHTMLとして出力

site.textでサイトのデータをHTMLとして出力。

# サイトのデータをHTMLとして出力
print(site.text)

初めの方の<meta contetn="&#19990;で始まる部分の&#...はHTMLエンティティと呼ばれるものらしく、デコードすると通常の文字として表現可能。HTMLエンティティとは&で始まり;で終わる文字列の一塊のこと。例えば上記だと

&#19990;&#30028;&#20013;&#12398;&#12354;&#12425;&#12422;&#12427;&#24773;&#22577;&#12434;&#26908;&#32034;&#12377;&#12427;&#12383;&#12417;&#12398;&#12484;&#12540;&#12523;&#12434;&#25552;&#20379;&#12375;&#12390;&#12356;&#12414;&#12377;&#12290;&#12373;&#12414;&#12374;&#12414;&#12394;&#26908;&#32034;&#27231;&#33021;&#12434;&#27963;&#29992;&#12375;&#12390;&#12289;&#12362;&#25506;&#12375;&#12398;&#24773;&#22577;&#12434;&#35211;&#12388;&#12369;&#12390;&#12367;&#12384;&#12373;&#12356;&#12290;

はデコードすると

世界中のあらゆる情報を検索するためのツールを提供しています。さまざまな検索機能を活用して、お探しの情報を見つけてください。

となる。初めの&#19990;は「世」に対応する。デコードは以下のサイトで行なった。

HTMLからタグを抽出

データの抽出にはBeautifulSoupを使用するのだった。

HTML全体を抽出

まずはHTML全体を抽出。parserはパース(解析)するための機能。いくつかの種類があるが使用するには別途モジュールのimportが必要。とりあえずpython標準のhtml.parserを使用。

data = BeautifulSoup(site.text, 'html.parser')
print(type(data))
# <class 'bs4.BeautifulSoup'>

print(data)

ここでは上記のデコードなされており日本語が散見される。

タグの抽出

HTML全体を抽出することができたので、続いてはそれぞれの要素を抽出。HTMLには「タグ」と呼ばれる箱?に文字が入っているので、それらタグを選択して目当ての要素を抽出する。

まずはタイトル(<title>タグ)から。.textでタグの中身だけ抽出可能。

# 引き出したデータに「.title」とつけるとHTMLのタイトルを取得
title_tag = data.title
print(title_tag)
# <title>Google</title>
print(type(title_tag))
# <class 'bs4.element.Tag'>

# 「.text」をつければタグの中身だけを取れる
print(title_tag.text)
# Google
print(type(title_tag.text))
# <class 'str'>

<a>タグはAnchorの略で、指定部分をハイパーリンクとして扱うことができるタグ。

# aタグも出力
a_tag = data.a
print(a_tag)
# <a class="gb1" href="<https://www.google.co.jp/imghp?hl=ja&amp;tab=wi>">画像</a>
print(type(a_tag))
# <class 'bs4.element.Tag'>

print(a_tag.text)
# 画像
print(type(a_tag.text))
# <class 'str'>

.find()でも同じ結果。

# .find()でも同じ結果
title_tag = data.find('title')
print(title_tag)
# <title>Google</title>
print(type(title_tag))
# <class 'bs4.element.Tag'>

a_tag = data.find('a')
print(a_tag)
# <a class="gb1" href="<https://www.google.co.jp/imghp?hl=ja&amp;tab=wi>">画像</a>
print(type(a_tag))
# <class 'bs4.element.Tag'>

タグの要素全てを抽出

前節でタグを抽出したが、このタグは実は初めの一つ。全てのタグを抽出したいのなら.find_all()を使用する。

# .find_allで全部抽出
title_tag_all = data.find_all('title')
print(title_tag_all)
# [<title>Google</title>]
print(len(title_tag_all))
# 1
print(type(title_tag_all))
# <class 'bs4.element.ResultSet'>

各要素(今回は1つしかないが)は前節のdata.titleの時と同じ。

# 各要素はdata.titleと同じ
print(title_tag_all[0])
# <title>Google</title>
print(type(title_tag_all[0]))
# <class 'bs4.element.Tag'>
print(title_tag_all[0].text)
# Google

aタグも同じように出力してみる。

# すべての「a」タグを出力する
a_tag_all = data.find_all('a')
print(a_tag_all)
print(len(a_tag_all))
# 18
print(type(a_tag_all))
# <class 'bs4.element.ResultSet'>

listっぽい形式なのでforループで要素を取り出し可能。

for element in a_tag_all:
    print(element)

他にも囲んだ範囲にCSSを適用するための<span>タグは以下。

span_tag_all = data.find_all('span')
print(span_tag_all)
print(len(span_tag_all))
# 8
for element in span_tag_all:
    print(element)

id属性とclass属性を抽出

最後はid属性とclass属性を抽出する。Webページは色々は要素の集まりでできており、それぞれの要素に名前をつけてあげないと区別することができない。人やものの名称をつけて区別するのと同じ。

そこで使用される考え方がid属性とclass属性。似たような使用用途であるが、明確に使い分けが必要。

id属性とclass属性

まずはid属性とclass属性とは何かというところから。いかに共通点とそれぞれの特徴を示す。

  • 共通
    • タグにつける(命名する)
    • 命名した部分だけにCSSを適用できる
  • id属性
    • 1つのページで1回しか使用できない
    • サイトの大きなレイアウトを決めるなどに使用
    • ヘッダやフッタに使用
  • class属性
    • 1つのページで何度でも使用できる
    • ページ内の具体的な表現などに使用
    • 頻繁に呼び出すCSSに使用

id属性を抽出

id属性の抽出には.find(id=(id属性))で可能。

# id属性は1つのページ内に1つしかない
mngb = data.find(id='mngb')
print(mngb)

class属性を抽出

class属性の場合はpythonのclassと区別するため、引数はclass_とする必要がある。また、class属性は1つのページ内で複数個存在させることが可能なのでfindでは初めの1つしか抽出できない。

# class属性は1つのページ内に複数ある場合がある=findだと初めの1つだけ抽出
gb1 = data.find(class_='gb1')
print(gb1)
# <b class="gb1">検索</b>

したがって、find_allで全て抽出する。

gb1 = data.find_all(class_='gb1')
print(gb1)

find_allで全部抽出したのでforでそれぞれの要素を確認。

for element in gb1:
    print(element)
# <b class="gb1">検索</b>
# <a class="gb1" href="<https://www.google.co.jp/imghp?hl=ja&amp;tab=wi>">画像</a>
# <a class="gb1" href="<https://maps.google.co.jp/maps?hl=ja&amp;tab=wl>">マップ</a>
# <a class="gb1" href="<https://play.google.com/?hl=ja&amp;tab=w8>">Play</a>
# <a class="gb1" href="<https://www.youtube.com/?gl=JP&amp;tab=w1>">YouTube</a>
# <a class="gb1" href="<https://news.google.com/?tab=wn>">ニュース</a>
# <a class="gb1" href="<https://mail.google.com/mail/?tab=wm>">Gmail</a>
# <a class="gb1" href="<https://drive.google.com/?tab=wo>">ドライブ</a>
# <a class="gb1" href="<https://www.google.co.jp/intl/ja/about/products?tab=wh>" style="text-decoration:none"><u>もっと見る</u> »</a>

id属性の中のaタグをさらに抽出

上記で抽出したid属性mngbからaタグを抽出。

# 取り出したid属性からaタグを抽出
a_tag_all_mngb = mngb.find_all('a')
print(a_tag_all_mngb)

それぞれの要素をforで抽出。

for elemnt in a_tag_all_mngb:
    print(elemnt)
# <a class="gb1" href="<https://www.google.co.jp/imghp?hl=ja&amp;tab=wi>">画像</a>
# <a class="gb1" href="<https://maps.google.co.jp/maps?hl=ja&amp;tab=wl>">マップ</a>
# <a class="gb1" href="<https://play.google.com/?hl=ja&amp;tab=w8>">Play</a>
# <a class="gb1" href="<https://www.youtube.com/?gl=JP&amp;tab=w1>">YouTube</a>
# <a class="gb1" href="<https://news.google.com/?tab=wn>">ニュース</a>
# <a class="gb1" href="<https://mail.google.com/mail/?tab=wm>">Gmail</a>
# <a class="gb1" href="<https://drive.google.com/?tab=wo>">ドライブ</a>
# <a class="gb1" href="<https://www.google.co.jp/intl/ja/about/products?tab=wh>" style="text-decoration:none"><u>もっと見る</u> »</a>
# <a class="gb4" href="<http://www.google.co.jp/history/optout?hl=ja>">ウェブ履歴</a>
# <a class="gb4" href="/preferences?hl=ja">設定</a>
# <a class="gb4" href="<https://accounts.google.com/ServiceLogin?hl=ja&amp;passive=true&amp;continue=https://www.google.com/&amp;ec=GAZAAQ>" id="gb_70" target="_top">ログイン</a>

さらに、それぞれの要素からaタグのテキストを抽出。

for elemnt in a_tag_all_mngb:
    print(elemnt.text)
# 画像
# マップ
# Play
# YouTube
# ニュース
# Gmail
# ドライブ
# もっと見る »
# ウェブ履歴
# 設定
# ログイン

class属性の中のaタグをさらに抽出

class属性でも同様にaタグを抽出しようとしたが、なぜかできなかった。

print(type(gb1[0]), type(mngb))
# <class 'bs4.element.Tag'> <class 'bs4.element.Tag'>

b_tag_all_gb1 = gb1[0].find_all('b')
print(b_tag_all_gb1)
# []

a_tag_all_gb1 = gb1[1].find_all('a')
print(a_tag_all_gb1)
# []

divタグの中じゃないからか?わからん。

HTML・CSSの知識がいるねこりゃ

今回はpythonのrequestsモジュールとBeautifulSoupモジュールを使用して、Webスクレイピングを始めてみたという内容だった。具体的には

  1. requestsでサイトデータを取得
  2. BeautifulSoupで取得データを抽出できる状態にする
  3. finf, find_allでタグや属性でフィルター

Webスクレイピングができるようになれば、Web上のデータ解析を自動で行えるようになるらしいので楽をするためにも勉強していきたい。

さらに、タグとかid属性とかHTMLの知識が必要なので、これを機に少しずつ覚えていきたい。

関連記事

【python&list】pythonのlistの超基礎

続きを見る

【python&~】数値にチルダ(~)をつけると値が+1されて負の数になる(ビット反転)

続きを見る

【px&バブルチャート】plotly.expressで各国の収入と平均寿命の時代変化をアニメーションで

続きを見る

【plotly&Scattergeo】世界地図に各国の首都の位置をプロット

続きを見る

関連コンテンツ

スポンサーリンク

Amazonのお買い物で損したない人へ

1回のチャージ金額通常会員プライム会員
¥90,000〜2.0%2.5%
¥40,000〜1.5%2.0%
¥20,000〜1.0%1.5%
¥5,000〜0.5%1.0%

Amazonギフト券にチャージすることでお得にお買い物できる。通常のAmazon会員なら最大2.0%、プライム会員なら2.5%還元なのでバカにならない。

ゲットしたポイントは通常のAmazonでのお買い物に使えるからお得だ。一度チャージしてしまえば、好きなタイミングでお買いものできる。

なお、有効期限は10年だから安心だ。いつでも気軽にAmazonでお買い物できる。

Amazonチャージはここから出来るで

もっとお得なAmazon Prime会員はこちらから

30日間無料登録

執筆者も便利に使わせてもらってる

スポンサーリンク

  • この記事を書いた人

メガネ

独学でpythonを学び天文学系の大学院を修了。 ガジェット好きでMac×Android使い。色んなスマホやイヤホンを購入したいけどお金がなさすぎて困窮中。 元々、人見知りで根暗だったけど、人生楽しもうと思って良い方向に狂ったために今も人生めちゃくちゃ楽しい。 pythonとガジェットをメインにブログを書いていますので、興味を持たれましたらちょこちょこ訪問してくだされば幸いです🥰。 自己紹介→変わって楽しいの繰り返し

-Python基礎
-, ,