Help us understand the problem. What is going on with this article?

Beautiful Soup での スクレイピング基礎まとめ [初学者向け]

More than 1 year has passed since last update.

概要

pythonを使って何かやりたいと思っている今日このごろ、、、
エロい健全な画像を自動収集したいなーと思って今流行りのスクレイピングをやってみました。
Beautiful Soupについて調べたので、基礎的なことをまとめておきます。
作成者が初学者のため、完全初学者向けです。

スクレイピングとは?

まずはスクレイピングとは何かの確認。
wikipedia先生より。

ウェブスクレイピング(英: Web scraping)とは、ウェブサイトから情報を抽出するコンピュータソフトウェア技術のこと。
~中略~
ウェブスクレイピングではウェブ上の非構造化データの変換、一般的にはHTMLフォーマットからデータベースやスプレッドシートに格納・分析可能な構造化データへの変換に、より焦点が当てられている。

構造化データ/非構造化データとは、簡単にまとめると

  • 構造化データ
    • CSVファイル, Excelファイル 等
    • 「行」, 「列」 によって、データが明確に分類できる。
  • 非構造化データ
    • htmlファイル, Jsonファイル, テキストデータ 等
    • 「行」, 「列」 だけでは分類ができない。

「行」, 「列」でデータを管理したほうが、コンピュータ的に都合がいい。
つまるところ、スクレイピングとは
「非構造化データから情報を抽出して、コンピュータがより扱い易い構造化データに格納する」
ことが目的ともいえる。

ちなみに、webサイトからデータを取得する「クローリング」というものもある。
クローリングは情報の抽出ではなく、任意のデータを取得することを指す。
「スクレイピング」は、htmlファイル全体を取得しその中から目的のデータを抽出すること。
「クローリング」は、htmlファイル全体, あるいは目的のデータをそのまま取得すること。
クローリング」したhtmlファイルを「スクレイピング」する
と考えるとわかりやすい。

Beautiful Soupとは?

Pythonのライブラリの一つで、スクレイピングに特化したモジュール
htmlファイルをタグ情報から解析し、抽出データを格納したインスタンスを返す。
htmlの構造とpythonの基礎が分かっていれば、非常に使いやすい。

やってみよう

環境

  • Mac OS High Sierra ver 10.13.4
  • Python 3.6.5 (anaconda)

環境構築

仮想環境の作成

スクレイピング用の仮想環境を作成する。

mkdir [dir_name]
cd [dir_name]
python -m venv [env_name]
source [env_name]/bin/activate

仮想環境を構築完了。

仮想環境にBeautiful Soupをインストール

pip install beautifulsoup4
pip list

beautifulsoup4 が表示されていたら成功。

Beautiful Soupを動かしてみる

htmlファイルの取得には、pythonの標準搭載モジュールであるurllibを使用。
読売新聞のヘッドラインを取得するコードを書いた。
読売新聞のページソースを確認しながらだと、以下の記事が理解しやすい。
"list-main-news"クラス内の"headline"クラスのテキストを取得する。

コード

#coding: UTF-8
from urllib import request
from bs4 import BeautifulSoup

def scraping():
    #url
    url = "http://www.yomiuri.co.jp/"

    #get html
    html = request.urlopen(url)

    #set BueatifulSoup
    soup = BeautifulSoup(html, "html.parser")

    #get headlines
    mainNewsIndex = soup.find("ul", attrs={"class", "list-main-news"})
    headlines = mainNewsIndex.find_all("span", attrs={"class", "headline"})

    #print headlines
    for headline in headlines:
        print(headline.contents[0], headline.span.string)

if __name__ == "__main__":
    scraping()

実行結果(2018/5/21)

省庁データ、近く西暦で統一…来春は間に合わず (07:16)
内閣支持、3ポイント増の42%…読売世論調査 (06:00)
政党支持、自民37%・立民7%…読売世論調査 (22:33)
働き方法案「今国会で」25%…読売世論調査 (23:10)
米朝会談で核解決「期待」66%…読売世論調査 (06:00)
ヒデキにこの勝利捧げる…交流のJ1川崎が追悼 (07:29)
日大監督「かんさい学院」連呼、謝る大学名誤る (12:46)
駅を1900m通過、時速60キロで後進し戻る (19:22)
スマホで徘徊者捜索実験、GPS内蔵靴「有用」 (07:38)

解説

html parser

html parserとは、htmlのタグ情報から情報を解釈するプログラムのこと。

パースとは、プログラムのソースコードやXML文書など、一定の文法に従って記述された複雑な構造のテキスト文書を解析し、プログラムで扱えるようなデータ構造の集合体に変換することである。
パースを行うためのプログラムの総称を「パーサ/パーザ」という。

(Proto Solutionより)

html parserは、html.parser以外にも多数存在する。
本記事では標準搭載の「html.parser」を使用。

soup = BeautifulSoup(html, "html.parser")

BeautifulSoupにhtmlファイルとhtml parserを渡し、インスタンス作成。

Beautiful Soupの操作

  • find()
    • 一番最初に合致した結果のみを返す
  • find_all()
    • 合致した結果を全てリストで返す

この2つのメソッドが主に使用される。
引数でフィルタをかけることにより、任意のhtmlタグ内の情報を保持した
bs4.element.Tag型のインスタンスを取得できる。

mainNewsIndex = soup.find("ul", attrs={"class", "list-main-news"})
headlines = mainNewsIndex.find_all("span", attrs={"class", "headline"})

まず、読売新聞のページには"list-main-news"クラスが一つしか存在しない。
そのため、find()を使用する。(find_all()だと、htmlファイル全体を探索してしまう。)
htmlファイル全体から<ul>タグの "list-main-news" クラスを抽出し、
mainNewsIndexにインスタンスを格納。
mainNewsIndexから、さらに"headline"クラスを抽出。
取得したい<span>タグの"headline"クラスは複数存在するので、find_all()でまとめて抽出。
これで最終的には、"bs4.element.Tag"型のインスタンスのリストがheadlinesに格納される。

  • find()
  • find_all()

以上2つのメソッドは、フィルターをかけて要素を取得する。
フィルターのかけ方については、わかりやすくまとめてくださっています。
PythonとBeautiful Soupでスクレイピング
萬九郎の硬い船

bs4.element.Tag とは

  • find()
  • find_all()

これらを用いると最終的に返されるインスタンス。
中身を見てみる。

コード

import pprint

~(中略)~

for headline in headlines:
    print(type(headline))
    pprint.pprint(headline.__dict__)

実行結果

<class 'bs4.element.Tag'>
{'attrs': {'class': ['headline']},
'can_be_empty_element': False,
'contents': ['栃ノ心、無傷の9連勝…白鵬と鶴竜は1敗守る', <span class="update">(18:05)</span>],
'hidden': False,
'known_xml': False,
'name': 'span',
'namespace': None,
'next_element': '栃ノ心、無傷の9連勝…白鵬と鶴竜は1敗守る',
'next_sibling': '\n',
'parent': <a href="http://www.yomiuri.co.jp/sports/sumo/20180521-OYT1T50054.html?from=ytop_main9">
         <span class="headline">栃ノ心、無傷の9連勝…白鵬と鶴竜は1敗守る<span class="update">(18:05)</span></span>
         <span class="icon-photo"></span>
         </a>,
'parser_class': <class 'bs4.BeautifulSoup'>,
'prefix': None,
'preserve_whitespace_tags': {'textarea', 'pre'},
'previous_element': '\n',
'previous_sibling': '\n'}

このように様々な情報が辞書型で格納されている。
もちろん、「.key」でつなぐことでこれらのvalueを取得できる。

#タグ直下のテキストを取得する
headline.contents[0]
#時刻を取得する
headline.span.contents[0]
  • .string
  • .text (指定場所以下のテキストを全て取得)

としてもテキスト内容は取得できる。
しかし、タグが多重構造の場合、外側のみのテキスト内容取得ができなかったので
.contents[] で指定して取得するのがよさそう。

まとめ

スクレイピングの基礎とBeautiful Soup4についてまとめました。
次回は一定時間毎にこれらを動作させるプログラムを書いてみたいと思いますー

U-MA
22歳のぺーぺー 職場ではJava研修。 プライベートではPythonで遊んでいる18卒です。 学んだことやプロダクトをアウトプットしていきます。 よろしくお願いします。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした