BeautifulSoupを使って、ブログ記事の情報をいろいろ絞り込んでみた

アイキャッチ

サーモン大好き、横山です。

今回はBeatifulSoupを使ってブログの記事情報を絞り込んで取得してみました。

準備

今回は、python3 + Beautiful Soup を使いました。

環境準備

$ pwd
/tmp/bs4

$ virtualenv --python=`which python3` venv
$ . venv/bin/activate
$ pip install -U pip
$ pip install beautifulsoup4

コード

  • main.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals

from bs4 import BeautifulSoup
import re
try:
    # for python3
    from urllib.request import urlopen
except:
    # for python2
    from urllib2 import urlopen 

url = 'https://dev.classmethod.jp/etc/remote-work-bad-communication/'
html_page = urlopen(url)
soup = BeautifulSoup(html_page, 'html.parser')

### この部分に、 以下の「コード」の部分を貼り付けて実行しています ###

ブログの記事タイトルを取得する

ブログのタイトルを抜き出すために、h1タグを抽出します。

コード

title = soup.find('h1')
print(title)
print(type(title))

結果

<h1 class="single_article_title">[働き方] リモートワークにおけるコミュニケーションについて</h1>
<class 'bs4.element.Tag'>

find 関数で見つけて来た要素をそのままprintするとHTMLタグ付で表示します。このobjectからtagのattributeやtextにアクセスするには次のサンプルのように値を取得します。
因みにfind関数は、該当するタグがなければ None 、複数該当する場合は最初にマッチした要素を返します。

コード

title = soup.find('h1')
print(title)
print(title.text)
print(title['class'])

結果

<h1 class="single_article_title">[働き方] リモートワークにおけるコミュニケーションについて</h1>
[働き方] リモートワークにおけるコミュニケーションについて
['single_article_title']

見出しを抜き出す

記事の見出しを抜き出すためにh2のタグを全て抜きだします。先程は find で見つけて来ましたが、今度は find_all 関数を使い全て取得します。

コード

for subheading in soup.find_all('h2'):
    print(subheading)

結果(2017/08/28時点)

<h2 id="toc-">リモートワークにおけるコミュニケーション</h2>
<h2 id="toc-1">チャットは日常会話の延長ではない</h2>
<h2 id="toc-2">よろしくないコミュニケーションの例</h2>
<h2 id="toc--">[追記] 電話・音声通話について</h2>
<h2 id="toc-3">まとめ</h2>
<h2 id="toc-4">参照</h2>
<h2>脚注</h2>
<h2 class="name"><i class="icon-user"></i> <a href="https://dev.classmethod.jp/author/komuro-hiraku/" title="執筆者:小室 啓"><strong>小室 啓</strong> について詳しくみる <i class="icon-chevron-right"></i></a></h2>
<h2 class="single_article_aside_sub_title"><i class="icon-folder-close"></i> 設定されているカテゴリー</h2>
<h2 class="single_article_aside_sub_title"><i class="icon-tag"></i> 設定されているタグ</h2>
<h2 class="single_article_aside_sub_title"><i class="icon-tag"></i> 同じタグが設定された記事</h2>
<h2 class="title">
<a href="https://dev.classmethod.jp/etc/extreme-attendance-sapporo/">札幌オフィスにエクストリーム出社してみました</a>
</h2>
<h2 class="title">
<a href="https://dev.classmethod.jp/remote-work/skype-beginner/">[初心者向け]Skypeで知っておくと便利なこと[ちょっとだけ]</a>
</h2>
<h2 class="single_article_aside_sub_title"><i class="icon-calendar"></i> 開催予定のイベント</h2>
<h2 class="title">
<a href="https://dev.classmethod.jp/news/akiba-aws-170831/">【8月31日(木)東京】「AKIBA.aws 第1回 基礎編」を開催します</a>
</h2>
<h2 class="title">
<a href="https://dev.classmethod.jp/news/jobfair-170905/">【9/5 東京】クラスメソッドの会社説明会を開催します。〜大阪・札幌からリモート参加もOK〜</a>
</h2>
<h2 class="title">
<a href="https://dev.classmethod.jp/news/jobfair-170920-osaka/">【9/20 大阪】クラスメソッドの会社説明会を開催します。</a>
</h2>
<h2 class="title">
<a href="https://dev.classmethod.jp/news/developers-io-2017-world-osaka/">9/23(土)『Developers.IO 2017 WORLD in 大阪』を開催します!</a>
</h2>
<h2 class="title">
<a href="https://dev.classmethod.jp/news/developers-io-2017-world-nagoya/">9/28(木)『Developers.IO 2017 WORLD in 名古屋』を開催します!</a>
</h2>
<h2 class="option_nav_popup_section_title"><i class="icon-folder-open"></i> カテゴリー一覧</h2>
<h2 class="option_nav_popup_section_title"><i class="icon-tags"></i> タグ一覧</h2>
<h2 class="option_nav_popup_section_title">絞り込むカテゴリーを選択</h2>

余分な情報も取れたので、もう少し絞り込みます。

コード

for subheading in soup.find_all('h2', id=re.compile('toc-.*')):
    print(subheading)

タグ名の他に、id名に toc-.* の正規表現でマッチするものと追加しました。

結果

<h2 id="toc-">リモートワークにおけるコミュニケーション</h2>
<h2 id="toc-1">チャットは日常会話の延長ではない</h2>
<h2 id="toc-2">よろしくないコミュニケーションの例</h2>
<h2 id="toc--">[追記] 電話・音声通話について</h2>
<h2 id="toc-3">まとめ</h2>
<h2 id="toc-4">参照</h2>

いい感じにしぼりこめましたが、「脚注」は id 指定されてないので抜けてしまいました。

コード

for subheading in soup.find('article').find_all('h2'):
    print(subheading)

切り口を変えて、記事ブロック ( <article> ) tagで絞り込んでから、h2でさらに絞り込む

結果

<h2 id="toc-">リモートワークにおけるコミュニケーション</h2>
<h2 id="toc-1">チャットは日常会話の延長ではない</h2>
<h2 id="toc-2">よろしくないコミュニケーションの例</h2>
<h2 id="toc--">[追記] 電話・音声通話について</h2>
<h2 id="toc-3">まとめ</h2>
<h2 id="toc-4">参照</h2>
<h2>脚注</h2>

目的の見出しを絞り込めました。

og:image に指定している画像URLを取得する

<head> タグの metaタグにある

<meta property="og:image" content="https://cdn-ssl-devio-img.classmethod.jp/wp-content/uploads/2015/12/communication-320x256.png" />

https://cdn-ssl-devio-img.classmethod.jp/wp-content/uploads/2015/12/communication-320x256.png を取得する

コード

og_img = soup.find('meta', attrs={'property': 'og:image', 'content': True})
if og_img is not None:
    print(og_img['content'])
else:
    print('!!not found og:image tag!!')

'content': True は attribute にcontentが存在するものを取ってくるようにしています。
前の見出しのh2の脚注だけ除きたい場合は、 find_all('h2', id=True) とやればできます。

結果

https://cdn-ssl-devio-img.classmethod.jp/wp-content/uploads/2015/12/communication-320x256.png

まとめ

BeatifulSoupのObject作って、find、find_allを駆使すると、簡単にHTMLページの欲しい情報を取得できました。

階層が深い場合でも、調べたい要素がタグ名やid名、class名が分かれば、狙いうちでその要素を抜き出せます。
例えば、とあるページの画像URLだけ抜き出したいとかは、 [img['src'] for img in soup.find_all('img') if img.get('src', None) is not None] とか雑に呼ぶとそのページのimgタグを使用している画像URLを取得することができます。

参照