本日は、『独学プログラマー』第20章のウェブ・スクレイパー製作を行います。
ウェブ・スクレイパー
WWWに公開されている情報は、その殆どがHTMLです。Hyper Text Markup Language、要はテキストを超えるテキスト。今では、HTMLだけで動画の再生だってできます。
HTMLは、タグを使って記述します。ウェブブラウザは、一定の規則に従ってタグを解釈することによって、ブラウザ上にウェブサイトを表示します。
このHTMLから、必要な情報だけを抜き出すのがウェブ・スクレイパーです。HTMLのタグは、それぞれ特定の意味を持っているので、例えば記事のタイトルだけを抜き出す、といったことが可能です。
スクレイピングの流れ
スクレイピングするにあたって、HTMLを取得する必要があります。HTMLを取得するには、サーバーにhttpリクエストを送り、その返答を得る必要があります。
My PC --request -> Server My PC <-response -- Server
そして、そのレスポンスに含まれるHTMLをパース(構文解析)することで、プログラムで扱いやすい形にします。『独学プログラマー』では、requestとパースを行うモジュールとして、urllibとBeautifulSoupが使われています。
(書き直した)コード
『独学プログラマー』の第1版が発行されたのは2018年2月の終わりです。世の中の移り変わりは早いもので、この記事を書いている2019年の3月暮れにはGoogle Newsのサイトマップが変わっているようです。
そこで、本書に掲載されているコード(p243)を少し改良して、2019年3月版のGoogle Newsでも動作するように書き直しました。また、書き直しに当たり、urllibではなく、requestsを使うようにしました。理由は以下の通り。HTTPのモジュールについて調べていたら、requestsというHTTPモジュールのドキュメントを発見しました。そこで、「urllibは人間が使うものではない!(意訳)」と書かれていたからです。
リリース v1.0.4. (Installation)
Requestsは、人が使いやすいように設計されていて、Pythonで書かれている Apache2 Licensed ベースのHTTPライブラリです。 Pythonの標準の urllib2 モジュールは、必要とされるほとんどのHTTPの機能を備えていますが、APIがまともに 使えません 。 様々なウェブ用途に合わせて作られていて、何回も修正されてきました。 簡単なことを行う(メソッドの上書きでさえ)のに、 かなり の量の作業が必要になります。 それはPython的ではないので、そんなに複雑にするべきではありません。 (Requests: 人間のためのHTTP — requests-docs-ja 1.0.4 documentation)
さて、以下が書き直したコードです。
# -*- coding: utf-8 -*- """ Created on Tue Mar 19 16:04:02 2019 独学プログラマー 20章 @author: ell_Sub2 """ import requests from bs4 import BeautifulSoup class Scraper: def __init__(self, site): self.site_route = site self.articles = [] self.articles_title = [] def _parsed(self, site): """ requests.get([url]) -> Get Request Object Request.text -> Get HTML Data """ #htmlを取得 r = requests.get(self.site_route) #パースする parser = "html.parser" sp = BeautifulSoup(r.text, parser) return sp def get_articles_url(self): sp = self._parsed(self.site_route) #URLにarticlesが含まれるリンクのみを取得 for tag in sp.find_all("a"): url = tag.get("href") if url is None: continue if "articles" in url: self.articles.append(self.site_route + url) print(self.articles) url = "https://news.google.jp/" Scraper(url).get_articles_url()
おわりに
本当は記事の掲載先からタイトルを取得したいなァ、なんて思って書き直し始めたんですが、articlesのリンク先に行くと、どういうわけかリダイレクトされていて上手く取得できませんでした。requestsのドキュメントをちょっとだけ覗いてみると、どうも勝手にリダイレクトは解決してくれるような感じなんですけどね...。もしかして、リダイレクトとは別の自動遷移なのかしら。知識がなくてキツイ。