カテゴリー

当サイトはアフィリエイトプログラムによる収益を得ています〈景品表示法に基づく表記です)

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

運営者のメガネです。YouTubeTwitterInstagram、自己紹介はこちら、お問い合わせはこちらから。

運営者メガネ

必要な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】世界地図に各国の首都の位置をプロット

続きを見る

ガジェット

2023/9/18

【デスクツアー2022下半期】モノは少なく、でも効率的に Desk Updating #0

今回はガジェットブロガーなのにデスク環境を構築していない執筆者の ...

ライフハック

2023/9/16

【Audible vs YouTube Premium】耳で聴く音声学習コンテンツを比較

ワイヤレスイヤホンが普及し耳で学習することへのハードルが格段に下 ...

完全ワイヤレスイヤホン(TWS)

2023/9/18

【SENNHEISER MOMENTUM True Wireless 3レビュー】全てが整ったイヤホン

今回は高音質・高機能なSENNHEISERのフラグシップ完全ワイヤレスイヤホン「SENNH ...

ライフハック

2023/3/11

【YouTube Premiumとは】メリットしかないから全員入れ

今回はYouTube Premiumを実際に使ってみてどうなのか、どんなメリット/デメリット ...

マウス

2023/8/17

【Logicool MX ERGOレビュー】疲れない作業効率重視トラックボールマウス

こんな人におすすめ トラックボールマウスの王道Logicool MX ERGOが気になるけどऩ ...

ベストバイ

2023/9/18

【ベストバイ2022】今年買って良かったモノのトップ10

2022年ベストバイ この1年を振り返って執筆者は何を買ったのか。ガジェッ& ...

スマホ

2023/1/15

【楽天モバイル×povo2.0の併用】月1,000円の保険付きデュアルSIM運用

こんな人におすすめ 楽天モバイルとpovo2.0のデュアルSIM運用って実際のとこ ...

マウス

2023/9/16

【Logicool MX ERGO vs MX Master 3】ERGOをメインにした決定的な理由

こんな疑問・お悩みを持っている人におすすめ 執筆者はLogicoolのハイエンӠ ...

macOSアプリケーション

2022/9/30

【Chrome拡張機能】便利で効率的に作業できるおすすめの拡張機能を18個紹介する

こんな人におすすめ Chromeの拡張機能を入れたいけど、調べても同じような ...

macOSアプリケーション

2023/5/3

【Automator活用術】Macで生産性を上げる作業の自動化術

今回はMacに標準でインストールされているアプリ「Automator」を使ってできる ...

Pythonを学びたいけど独学できる時間なんてない人へのすゝめ

執筆者は大学の研究室・大学院にて独学でPythonを習得した。

でも社会人になったら独学で行うには時間も体力もなくて大変だ。

時間がない社会人だからこそプロの教えを乞うのが効率的。

ここでは色んなタイプに合ったプログラミングスクールの紹介をする。

  • この記事を書いた人

メガネ

Webエンジニア駆け出し。独学のPythonで天文学系の大学院を修了。常時金欠のガジェット好きでM2 Pro MacBook Pro(30万円) x Galaxy S22 Ultra(17万円)使いの狂人。自己紹介と半生→変わって楽しいの繰り返しレビュー依頼など→お問い合わせ運営者情報、TwitterX@m_ten_pa、 YouTube@megatenpa、 Threads@megatenpa

-Python基礎
-,