PythonでWebサイトをスクレイピングして目的のタグを取得する手順

先日、某サイトの自動スクレイピングソフト作成を依頼された。
ソフトは1日で完成したのだけど、そのときにいろいろと調べることもありました。

ここにスクレイピングするために必要なことを1から10まで書き残しておこうとおもいます。
スクレイピングしたい人は応用してみてください。

この記事では、例としてYahooニュースのTOPページからニュース記事をスクレイピングするプログラムを作ります。
赤色で囲った部分のリンク先ページにアクセスし、そこからニューズ記事を取得してくるというものです。

環境構築する

今回は以下の環境で開発します。

  • Python3.6
  • BeautifulSoup
  • urllib

ここで使うBeautifulSoupとはスクレイピングの定番ライブラリです。
HTMLを解析する機能が強力で、たいていのことはこれひとつで事足ります。

HTMLを解析する

環境構築ができたら、まずは対象となるページのHTMLを解析します。
対象ページの構造をブラウザのデベロッパーツールを使って見ていきます。


これで見ると、目的の部分は以下のような構造になっていることがわかりました。

<div id=”epTabTop” class=”epContents current hasBigImg top”>

というタグの下に
<ul class=”topics”>

というタグがあり、その下に

<li>

タグがズラリと並び、その下の

<a>

タグに記事ページへのURLがある。
ということは、まずはこの<a>タグのURLを全て取得してリスト化することが目標となります。

BeautifulSoupで対象ページのHTMLを取得する

まずはYahooニューストップページを取得するために以下のようなコードを書きました。

試しにPythonのシェルを起動してこのコードを実行してみます。

これで、取得したページが変数”html”に代入されます。
今回はヤフーニュースのトップページを引数として渡しているので、トップページのHTMLが代入されているはずです。
print(html)などで確認してみましょう。

取得したHTMLから目的の情報を取得する

次に、目的のタグのみを抽出して、そこから必要な情報を抜き取るコードを書いていきます。
今回のお題では記事ページにある記事が欲しいわけですから、ここでは<a>タグにある記事ページへのURLを取得してリストに格納します。

それでは、さきほどのget_yahoo.pyのConnect_webクラスにそのためのメソッドを追加します。

結構シンプルなコードです。
これだけで記事ページのURLを取得できます。
それでは、このコードをひとつづつ解説していきましょう。

このコードで、Yahooニュースのトップページを取得します。

最初にHTMLを解析したとき、記事ページへのリンクは
<ul class=”topics”>というタグの下に全てありました。
なので、このコードでタグを抜き出します。

BeautifulSoupオブジェクトで使えるselect_oneメソッドではタグの属性を指定して抜き出すことができます。

例:<div>タグの場合

id=”topics”の場合 class=”topics”の場合
select_one(‘div#topics’) select_one(‘div.topics’)

今回は<ul>タグのclass=”topics”だったので上のようなコードとなりました。

このコードで抜き出した<ul>タグから<a>タグを全て取得します。
このfind_allメソッドはよく使うので覚えておくと便利です。

例:<a>タグの場合

<a>タグを全て取得する 最初の<a>タグのみを取得する
find_all(‘a’) find(‘a’)

このコードでは、抜き出した<a>タグからURLのみを抽出します。
find_allメソッドで取得したオブジェクトは、リスト型になっているのでfor文でURLを抜き出し、抜き出したURLを新しいリストに格納していきます。

2つめのforでは、不要なURLを削除しています。
欲しいのは記事ページのURLだけですが、リストの最後から2つ目までは記事ページへのURLではないので削除します。

それでは、ためしにここまで書いたコードの動作確認をしてみましょう。
シェルを起動して、以下のコードを実行します。

これで変数”url”に目的のページのURLのリストが代入されるはずです。
print(url)などで確認してみてください。

ここまでの工程で、URLのリストを作るところまではできました。
次はそのリストにあるページに移動して目的のテキストを抽出するプログラムを書いていきます。

目的のページのHTML構造を把握する

今回の目的はニュース記事の取得ですので、最初の工程でやったようにニュース記事のあるページに移動してデベロッパーツールを使い、HTMLの構造を把握しましょう。

最初の工程とまったく同じです。記事の本文があるタグを特定します。
Webスクレイピングにおいて最も重要なことはプログラムのコードを書くことではなく、この工程といっても過言ではありません。

デベロッパーツールで見ると、以下のようなタグに記事本文があることがわかりました。

<div class=”headlineTxt”>

このタグの下にある、

<h2>タグに記事タイトル

<p>タグに記事本文

がそれぞれ格納されているようです。

記事タイトルと記事本文を抽出する

ここから記事本文と記事タイトルのテキストのみを抜き出し、辞書型のデータで返すコードを書いてみます。

こんな感じですね。
この関数を実行すると、記事タイトルと記事本文がリスト内包の辞書型のデータとして返ってきます。

それでは、関数の中身を1行づつ見ていきましょう。

変数”page”にURLのリストを代入します。
そして、この変数をfor文にURLを1件づつ取り出して繰り返し処理にかけます。

このコードで最初に作った関数を使って記事ページのHTMLを取得します。
そして次に、

変数”main”で記事があるタグを抜き出し、つぎに抜き出したタグの下にある<h2>タグと<p>タグからテキストのみを抽出します。
get_text()メソッドを使うと、タグからテキストのみを抽出することが可能です。

辞書型のデータ”dic”を作り、そこにタイトルと記事本文を格納します。
そして、for文の直前につくっておいたリスト型データの”text_list”にその辞書型データを加えます。

そして、for文を抜けたところでこのリスト型データ”text_list”を返すようにします。

以上でヤフーニュースからニュース記事を取得してくるという目的を果たすことができました。
最後に今回作ったプログラムのコード全文を掲載しておきます。

全コード