beautifulsoupを使ったスクレイピングの基本操作

かばくん

最近よく聞くスクレイピングとはなんですか?
ぼくでもできますか??

へびせんせい

スクレイピングとは主にWebから自動的に情報を取得することを指します。
beautifulsoupというライブラリを使えば、簡単に実装可能です。

pythonによるbeautifulsoupを使ったスクレイピングの基本操作をまとめます

準備

必要なもの

pip install beautifulsoup4
pip install requests

実装するもの

スクレイピング用のサンプルサイトを用いて、スクレイピングを行ってみます。

サンプルサイトはこちら

次のことを実装してみます。

  1. テキスト情報の取得
  2. 表(Table)データの取得
  3. 画像のダウンロード
  4. テキストの入力とボタンのクリック

beautifulsoupを使ったスクレイピング

beautifulsoupを使ったスクレイピングは、seleniumのものと少し感覚が違います。
seleniumでは、実際のブラウザを指定して、それを自動的に動かすことによって情報の取得や入力を行っていました。
beautifulsoupでは、プログラム上でweb上にリクエストを送ってHTML情報を取得し、そのHTMLを解析することによってスクレイピングを行います。
beautifulsoupはHTMLの解析を担うライブラリであり、webにアクセスするのはrequestsライブラリを用います。

requestsライブラリでWebにアクセスしHTML情報を取得する
beautifulsoupライブラリでHTML情報を解析して、欲しい情報を取得する
beautifulsoupの良いところ
  • 処理が早い
  • ページ遷移を行いやすい
  • サーバー上で動かしやすい
beautifulsoupの悪いところ
  • ブラウザ表示はされないので、視覚的にわかりにくい
  • ボタンをクリックするという実際のアクションは行えない
  • スクレイピング対策にひっかかりやすい

ライブラリのインポート

import requests
from bs4 import BeautifulSoup
import pandas as pd

表(Table)形式のデータを取得するためにpandasをインポートしています。
不要であれば、インポートしなくてもよいです。

サイトへのアクセス

url = 'https://www.next1step.com/category/python/scraping_sample_page/'

# 指定したURLにrequestsを出す(成功すると200番が返る)
res = requests.get(url)

変数urlにスクレイピング用のサンプルページを指定しています。
まずは、requestsライブラリのgetメソッドでサーバーにリクエストを送ることができます。
正しくリクエストが送信できると、200番が返ってきて、サーバーからのレスポンスが格納されます。
この時点で、res.text属性でHTMLの中身を確認することができます。

requestsでURLにアクセスしても、ブラウザが起動してページが開くといった動作ではない

HTMLをパースする

soup = BeautifulSoup(res.text, 'html.parser')

ここで、さきほど取得したHTMLのテキスト情報をきちんとHTML構造として取得します。

要素の取得

スクレイピングで必要な情報を取得するには、必要なHTML要素にアクセスしなければなりません。
ここがスクレイピングの難しいところでもあり、技の見せ所でもあります。
タグ・ID・class・xpathなどのHTMLの知識も少なからず必要となります。

今回は、「へびせんせいについて」というテキスト、得意なプログラミングの一覧、へびせんせいの画像のダウンロード、日本に生息するへびの毒の有無の表データを取得してみます。
そして、inputボックスに名前とメールアドレスを入力して、ボタンを押す動作をプログラムしてみます。

見出しのテキスト情報を取得

## タグ指定:h2要素を取得する
elems = soup.find_all('h2')
elem = elems[0]

print(elem.text)

ページ内のすべてのh2要素をリスト形式で取得します。
リストの中から必要な要素だけを選択して、テキストを出力します。

箇条書きになっているテキストの取得

## liの取得
elems = soup.find_all('li') #これだと不要なliタグを取得してしまう
for elem in elems:
    print(elem.text)

elems = soup.find('article').find_all('li')
for elem in elems:
    print(elem.text)

「得意なプログラミング」の下にある箇条書き部分を取得しています。
h2要素と同じようにすべてのli要素をリスト形式で抽出でもよいのですが、ヘッダー部分の不要なliタグも取得してしまいます。
そのため、articleタグの中のすべてのliタグを指定することで、うまく箇条書き部分を取得しています。

画像のダウンロード

## 画像をダウンロードする
elem = soup.find('img', alt='へびせんせいのサンプル画像')
img_url = url + elem.get('src')

img = requests.get(img_url).content

with open('./sample.png', 'wb') as f:
    f.write(img)

保存したいimgタグを指定したあとで、その画像のURLを取得する必要があります。
imgタグのsrc属性にURLは入っているので、変数img_urlに格納しています。
そして、requestsのcontent属性でバイナリデータを取得できます。

表(Table)のデータの取得

## テーブルの情報を取得する
dfs = pd.read_html(url)
df = dfs[0]

df.to_csv('./sample.csv', index=False)
print(df)

表データはseleniumと同様にtableタグの中のtdタグを指定して取得することができます。
今回は、pandasライブラリを使って、簡単にテーブル情報を取得してみます。

pandasのread_htmlメソッドを使うとtableをリスト形式でDataFrameとして取得できます。
今回はtableタグは1つしかないので、0番目の要素をdfに代入します。
あとは、そのままto_csvメソッドでcsv出力できます。

テキスト入力、ボタンクリック

## テキストボックスに文字を入力し、ボタンを押す
data = {
  'name' : 'かばくん',
  'mail' : 'kabakun@xxxxxx.xx'
}

next_url = 'https://www.next1step.com/category/python/scraping_sample_page/sample.php'
ses = requests.Session()
res = ses.post(next_url, data=data)

print(res.text)

inputボックスへの入力はbeautifulsoupではできません。
では、どうやって名前とメールアドレスをサーバー側に送信するのでしょうか?
それは、データとしてサーバー側に送信してあげることで実現します。
名前とメールアドレスをdataという辞書型で定義して、postメソッドで送信しています。
実際に返ってきたHTMLを確認してみましょう。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>入力内容の確認</title>
</head>
<body>

<div>
  <h1>入力した内容</h1>
  
  <h2>名前</h2>
  <p>かばくん</p>
  
  <h2>メールアドレス</h2>
  <p>kabakun@xxxxxx.xx</p>
</div>

</body>
</html></code>

しっかり名前とメールアドレスが入力されていることがわかります。

かばくん

beautifulsoupとrequestsはブラウザが動くわけではないので、
要素が正しく指定できているか把握するのが難しいなぁ。


1つにまとめたファイルのGitリポジトリ

Download