Web スクレイピング入門

Python の使い方も学び、Web ページの構造も理解したので、早速 Web スクレイピングをしていきましょう。 まず、このページでは手始めに Yahoo news のトピックス一覧 から、各記事のタイトルを収集することを目指します。

requests

まず、python を使って、Web ページのコンテンツをとってみましょう。 これには、 requests というモジュールを使います。 Python にも似たようなものがありますが、 requests の方が使いやすいです。 コンテンツが欲しい Web ページの URL について、 requests.get(URL) とすると、Web サーバーに Web ページのコンテンツを送ってくれという要求をすることができます。

[1]:
import pandas as pd
from bs4 import BeautifulSoup
import requests
url = "https://news.yahoo.co.jp/topics"
response = requests.get(url)
response.status_code
[1]:
200

最後の行は、ステータスコードというものを表していてます。 ステータスコードは Web サーバーへの要求が上手くいったかを判別することができるので、毎回チェックしておきましょう。 200 は、Web サーバーの要求が無事成功したことを示しています。 ステータスコードは 200 以外にも、様々な値を返すので、やりながら学んでいけば良いでしょう。

BeautifulSoup

次に、Web ページのコンテンツからデータを取りやすいようにします。 ここでは、BeautifulSoup を用います。 BeautifulSoup は使い方がわかりやすいので、入門としては良いでしょう。

[2]:
bs = BeautifulSoup(response.content, "lxml")

lxml というのは、htmlのパーサーの一つです。 パーサーというのは、HTML を解析して分析しやすくしてくれます。 また、タグの閉じ忘れなどを直してくれます。 BeautifulSoup には 4 つほどのパーサーを使えますが、lxml は使いやすさと早さを兼ね備えているので、これを使います。

HTML の章で解説しましたが、Web ページは様々な要素が入れ子になっています。 したがって、自分の欲しい情報をとるには、その情報が置いてある要素を上手く指定することが大事です。 要素を指定する方法は、CSS のところで解説しました。 それでは、我々の欲しい情報は一体どこに位置しているのでしょうか?

実は、Google Chrome や Firefox などのモダンブラウザには、それを分かりやすくする機能が備わっています。 Web ページを開いて、Ctrl + Shift + I を押すか、右クリックを押してから、検証(インスペクタ)を押してみましょう。 画面が 2 分割され、左側に Web ページ、右側に html が表示されるでしょう。 右側の左上のカーソルのマークをクリックしてから、左側の適当なところを押してみましょう。 すると、そのテキストが html 内のどこにあるかが、右側に表示されます。

この機能を使って、欲しい情報はどこにあるのかを探っていきます。 ここでは、トピックス一覧の内容が欲しいので、その内のどれかを押してみましょう。 一覧の内容は全てリンクが張られているので、 a 要素に含まれていることがわかりました。

a

BeautifulSoupselect で CSS セレクターを使うことができます。 下の例では a 要素を取ってきています。 select は CSS セレクターで指定した要素をタグごとにリストに含めます。

[3]:
print(len(bs.select('a')))
152

返ってくる要素が多すぎます。 Web ページは多くのところでリンクを貼っているので、a 要素だと制限が緩すぎます。 別の方法を考えましょう。 各トピックの全体を検証してみると、トピック毎に div 要素でくくられていることがわかります。 それでは、div 要素を指定してみましょう。

ul

[4]:
# 表示は省略
# bs.select('div')

先程よりはましですが、まだ余計なものが残っています。 よく見ると、この div 要素には topicsList というクラス名が割り当てられています。 .topicsList として、このクラスを持つ要素を取ってみましょう。

[5]:
topics = bs.select('.topicsList')
topics[0]
[5]:
<div class="topicsList"><p class="topicsList_title"><a data-ylk="rsec:tpc_dom;slk:top;" href="/categories/domestic">国内</a></p><ul class="topicsList_main"><li class="topicsListItem" data-ual="" data-ual-view-type="list"><a data-ual-gotocontent="true" data-ylk="rsec:tpc_dom;slk:title;pos:1;" href="https://news.yahoo.co.jp/pickup/6336338">昨年度の年金未払い 5.7億円</a></li><li class="topicsListItem" data-ual="" data-ual-view-type="list"><a data-ual-gotocontent="true" data-ylk="rsec:tpc_dom;slk:title;pos:2;" href="https://news.yahoo.co.jp/pickup/6336344">小泉環境相「福島を後押し」<span aria-label="NEW" class="labelIcon labelIcon-NEW"></span></a></li><li class="topicsListItem" data-ual="" data-ual-view-type="list"><a data-ual-gotocontent="true" data-ylk="rsec:tpc_dom;slk:title;pos:3;" href="https://news.yahoo.co.jp/pickup/6336315">安定と挑戦 改造内閣が始動<span aria-label="動画" class="labelIcon labelIcon-VIDEO"></span></a></li><li class="topicsListItem" data-ual="" data-ual-view-type="list"><a data-ual-gotocontent="true" data-ylk="rsec:tpc_dom;slk:title;pos:4;" href="https://news.yahoo.co.jp/pickup/6336342">新内閣で17人交代 閣僚の横顔<span aria-label="NEW" class="labelIcon labelIcon-NEW"></span></a></li><li class="topicsListItem" data-ual="" data-ual-view-type="list"><a data-ual-gotocontent="true" data-ylk="rsec:tpc_dom;slk:title;pos:5;" href="https://news.yahoo.co.jp/pickup/6336345">共産・れいわ会談 協力で一致<span aria-label="NEW" class="labelIcon labelIcon-NEW"></span></a></li><li class="topicsListItem" data-ual="" data-ual-view-type="list"><a data-ual-gotocontent="true" data-ylk="rsec:tpc_dom;slk:title;pos:6;" href="https://news.yahoo.co.jp/pickup/6336337">長期停電 家庭でできる備え</a></li><li class="topicsListItem" data-ual="" data-ual-view-type="list"><a data-ual-gotocontent="true" data-ylk="rsec:tpc_dom;slk:title;pos:7;" href="https://news.yahoo.co.jp/pickup/6336302">歩きスマホ 法令規制すべき?</a></li><li class="topicsListItem" data-ual="" data-ual-view-type="list"><a data-ual-gotocontent="true" data-ylk="rsec:tpc_dom;slk:title;pos:8;" href="https://news.yahoo.co.jp/pickup/6336318">大阪地検 前堺市長の自宅捜索</a></li></ul><div class="topicsList_button"><p class="topicsList_button_more"><a data-ylk="rsec:tpc_dom;slk:more;" href="/topics/domestic">もっと見る</a></p></div></div>

上手くいきました!各トピックがリストの各要素に入ってます。 それでは、ここからトピック毎に記事名を格納していきましょう。 topicsList_title クラスには、トピックのカテゴリーが入ってます。 各 li 要素(あるいは、topicsListItem クラス)には、各記事が入っています。 要素ごとに分けたら、text メソッドを使って、要素の内容を取り出します。

[6]:
print(topics[0].select('.topicsList_title')[0].text)
print(topics[0].select('li')[0].text)
国内
昨年度の年金未払い 5.7億円

この作業をループ化して、dict = {トピックのタイトル:[記事A, 記事B]} というように、辞書型にしていきます。

[7]:
news_topics = {}
for topic in topics:
      topic_title = topic.select('.topicsList_title')[0].text
      news_topics[topic_title] = []
      for news in topic.select('li'):
              news_topics[topic_title].append(news.text)

[8]:
news_topics['国内']
[8]:
['昨年度の年金未払い 5.7億円',
 '小泉環境相「福島を後押し」',
 '安定と挑戦 改造内閣が始動',
 '新内閣で17人交代 閣僚の横顔',
 '共産・れいわ会談 協力で一致',
 '長期停電 家庭でできる備え',
 '歩きスマホ 法令規制すべき?',
 '大阪地検 前堺市長の自宅捜索']

ちなみに、さきほどの処理は次のようにもかけます。 [news.text for news in topic.select('li')] はリスト内包表記というものです。 ここでは、li 要素を順に news に格納し、その要素の内容を news.text で取り出し、リストに入れていく処理をしています。 リスト内包表記は、普通にループ文を書くよりもスッキリとして書け、また早く処理することができます。

[9]:
# news_topics = {}
# for topic in topics:
#     topic_title = topic.select('.topicsList_title')[0].text
#     news_topics[topic_title] = [news.text for news in topic.select('li')]

せっかくなので、pandasDataFrame に変換しましょう。 dict から DataFrame にするには、from_dict を使います。

[10]:
topics_dt = pd.DataFrame.from_dict(news_topics)
topics_dt
[10]:
国内 国際 経済 エンタメ スポーツ IT 科学 地域
0 昨年度の年金未払い 5.7億円 「善意」対中関税を2週間延期 消費増税 日付またぐと税率は 本田翼 ゲーム実況は素が出る 渋野 オーバーパーなし新記録 千葉市長投稿「自粛遠慮を」 地球型惑星に水蒸気 初確認 停電で作業員1万1000人を動員
1 小泉環境相「福島を後押し」 被害甚大のバハマ 2500人不明 ゆうちょ銀1.9万件不適切販売 綾小路翔 音楽で千葉を支援 嘉風引退 関取最年長の37歳 千葉で公衆電話無料 注意点は 超精密 原子核時計開発へ前進 停電長期化 物資に長蛇の列
2 安定と挑戦 改造内閣が始動 香港証取 英の証取買収を提案 JR西 サングラスで安全確保 おっさんず 10月に再び連ドラ マラソン 聖域壊した選考会 auも端末最大半額 新プラン 絶滅危惧種 駆除用わなで死ぬ 台風15号 離島でも爪痕残す
3 新内閣で17人交代 閣僚の横顔 英議会閉鎖は違法 政府が上訴 北九州にIR? 香港大手が関心 新井被告出演 映画への注目 大谷が18号 米通算40本塁打に 5G未対応 中国でiPhone苦戦? 9.11の粉じん影響か がん増加 4歳死亡 出水市長が対応謝罪
4 共産・れいわ会談 協力で一致 米国 電子たばこの販売禁止へ 台風 東電に残した痛い「傷」 渡部建 生まれ変わるなら児嶋 163km右腕 1位指名撤退の動き Apple 価格競争の消耗戦へ? 人工血液 動物実験に成功 中学生11人 ハチに刺され搬送
5 長期停電 家庭でできる備え 内閣改造 韓国の報道は批判的 NEC 新卒年収1000万円の衝撃 医師タレ 友利新が第3子出産 競輪選手 千葉で給油手助け Apple Watch 常時点灯18時間 9月にインフル 学級閉鎖続々 愛知あおり 京都でも被害か
6 歩きスマホ 法令規制すべき? 「旭日旗禁止」要請をIOC静観 中国産梅を国産と偽装 福岡 藤原竜也 南国で見せた父の顔 ソフトテニス 国内初プロの道 イヤホン線路落下 JR注意喚起 断水時 水の確保・利用法は テント飛び園児3人けが 静岡
7 大阪地検 前堺市長の自宅捜索 MVで露政府称え 低評価最多 補聴器 敬老の日前にフル生産 ドクターXにオリラジ藤森ら 久保の五輪出場 レアル認める NEM流出 消えた「北関与」 H2Bロケットの打ち上げ中止 高槻水難事故 重体女児も死亡