見出し画像

Webスクレイピング始めの一歩(Using Python to Access Web Data: Week 4)

引き続き、ミシガン大学がCoursera上で開講しているPython for Everybody Specializationの第3コース、Using Python to Access Web Dataを受講した記録です。前回のWeek 3では、HTTPとTCPによってWebサーバにアクセスし、データを受信するまでを学びました。

Week 4では、いよいよ取得したHTMLデータを解析したり、HTMLに埋め込まれているリンク先をたどったり、Webスクレイピングの初歩的な技術を学んでいきます。

<テキストの範囲>
Chapter 12: Networked Programsのつづき


1.ASCII

私たちが日常的にコンピューターにおいて使っているアルファベットは、元はシンプルなコードでした(今もですが)。1970年代当時は、コンピューターにアルファベットを認識させるように、特定の値を持つコードをアルファベットに対応させるようマッピングをすることでコードとアルファベットを一対一の対応ができるようにしました。1980年代に、ASCIIという統一的なマッピングのテーブルが完成しました。これにより、54は6、80はP、116はtというように、128個のコードが数字やアルファベットの大文字、小文字という文字を表すようになりました。ちなみに日本のひらがなやカタカナは、JISが標準規格になっています。

あるアルファベットがASCIIコード上のどの数値と対応しているかは、ord()関数で知ることができます。

>>> print(ord('C'))
67
>>> print(ord('\n'))
10

ASCIIでは、特殊な信号、アルファベット、数値および基本的な記号が0から127までの数値と対応しています。\nもASCIIに含まれています。


2.マルチバイトの文字

しかしながら、最近のコンピューターはASCIIだけではなく、他の言語や様々な記号に対応しています。これは、コンピューターが取り扱える情報量が増えたことに加え、より統一的な文字コードが取り扱えるようなテクノロジーが進化したことによります。

文字コードの形式であるUTF-16は2バイトの固定値に対応する文字コードです。また、UTF-32は4バイトの固定値に対応する文字コードですので、扱える文字や記号のパターンは非常に多くなっています。

そのような中、UTF-8という文字コードの利用が近年増えてきています。これは1~4バイトの可変の長さを持つ文字コードで、ASCIIだけでなく他の文字コードも取り扱え、またデータのサイズも取り扱う文字コードによって柔軟に変えられるというメリットがあります。


3.インターネット標準の文字コードとPython標準の文字コード

インターネット上で扱われる標準の文字コードが徐々にUTF-8という規格に統一されてきている一方で、Pythonが取り扱うことができる文字コードはUnicodeという規格となっています。

したがって、Pythonで作られた信号はUnicodeになっていますので、socketオブジェクトで送信処理をする前にUTF-8に変換しなければなりません。この処理を前の講義の最後で取り扱ったコードの中のencode()で行っています。
他方、Webサーバからrecv()で取得したデータはUTF-8の規格になっていますので、decode()でPython用に変換してあげる必要があります。

import socket
mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mysock.connect(('data.******.org', 80))
cmd = 'GET http://data.******.org/test.txt HTTP1.0\r\n\r\n'.encode()
mysock.send(cmd)
while True:
   data = mysock.recv(512)
   if (len(data) < 1):
       break
   print(data.decode())
mysock.close()


4.Urllibライブラリを使ってシンプルなコードにする

今やHTTP通信は一般的なものですので、Pythonにも便利なライブラリが存在しています。今回は、urllib.request、urllib.parse、urllib.errorの3種のライブラリをインポートしてプログラミングしていきます。

import urllib.request, urllib.parse, urllib.error
fhand = urllib.request.urlopen('http://www.******.org/test.txt') #...[1]
for line in fhand: #...[2]
    print(line.decode().strip()) #...[3]

[1]では、ファイルのopen()関数のようにURLだけを指定しています。この方法では、Webサーバのポートが80であるか8080であるかは特に指定しなくてもよいことになります。
[2]においても、ファイルの操作と同様、file handleの要領でfor文で処理できます。
[3]では、取得したデータをdecodeし、左右にある空白や最後の改行をstrip()メソッドで削除して表示します。取得したデータの改行を削ったとしても、printが改行してくれますので大丈夫です。

この方法では、encode()やsend()、recv()が使われていません。つまり、urlopenで開こうとするアドレスを打ち込むことは、encodeやsendする命令は"GET URL名"と分かっているわけですし、ポート番号は80または8080といったものが一般的ですし、欲しい情報はメタデータではなくHTML本文であるケースが多いですから、そのような処理をライブラリとしてまとめ、プログラム自体をシンプルにできるのはとても便利です。


5.Webスクレイピングに挑戦する

次に、Pythonプログラムを通して、Webからデータを自動取得する処理を見ていきます。このような処理をWebスクレイピングなどと言いますが、このようにプログラムがブラウザを通じたアクセスでない方法で自動的にWeb上にあるページを自動取得することがホームページの利用規約に違反するケースがありますので、必ず取得したいページの利用規約を読むようにしてください。例えば、TwitterはWebスクレイピングを明示的に禁止しています。

ユーザーはまた、たとえばTwitterサービスの妨害や当社が提供するインターフェースおよび手順以外の方法を使ったTwitterサービスへのアクセスにより、Twitterサービスの不正利用をしないことにも同意するものとします。ユーザーは、本サービスへのアクセスまたはその使用中に、次のいずれも行ってはなりません。(i)本サービス、Twitterのコンピュータシステム、またはTwitterプロバイダーのテクニカルデリバリーシステムの非公開部分へのアクセス、不正な改ざんもしくは使用、(ii)システムもしくはネットワークの脆弱性の探索、スキャンもしくはテスト、またはセキュリティもしくは認証方法の侵害もしくは回避、(iii)Twitterから提供される(かつ該当する利用条件に従う場合にのみ提供される)、当社の現在利用可能な公開インターフェース以外の方法(自動プログラムか否かを問わない)で、本サービスへのアクセスもしくはその探索またはアクセスもしくは探索の試み(ただし、Twitterとの個別契約で特に許可されている場合は除く)(注:本サービスへのクローリングは、robots.txtファイルの定めによる場合は認められていますが、Twitterによる事前の同意がないまま本サービスのスクレイピングをすることは明示的に禁止されています)
Twitter サービス利用規約より)

Dr. ChuckいわくHTMLは洗練された構造を持つ言語ではないため、スクレイピングをするには技術的に難しいと述べています。しかしながら、BeautifulSoupと呼ばれるライブラリを導入することによって、スクレイピングをよりしやすくなります。筆者の環境では、Anacondaのインストール時点でBeautifulSoupが既にインストールされていました。

ライブラリをインポートするには、

from bs4 import BeautifulSoup

という一文でOKです。

例えば、あるWebページの<a href="">タグのリンク先だけを取得してくるプログラムは、

import urllib.request, urllib.parse, urllib.error
from bs4 import BeautifulSoup

url = input('Enter URL - ')
html = urllib.request.urlopen(url).read() #...[1]
soup = BeautifulSoup(html, 'html.parser') #...[2]

tags = soup('a') #...[3]
for tag in tags:
    print(tag.get('href', None)) #...[4]

といった形で書くことができます。[1]で、read()を使っていますが、これによりHTMLファイル全体をひとまず読み込んでいます。HTMLファイルのサイズが非常に大きい場合はそうそうないと思いますが、膨大なHTML記述があるファイルを読み込むと、大量のデータをメモリに読み込むため処理が重くなってしまう可能性があります。

[2]で、BeautifulSoupのライブラリを使っています。(html, 'html.parser')の意味は特に細かく理解する必要はありませんが、大雑把に言うとHTMLの構造をBeautifulSoupライブラリが解析し、soupオブジェクトとしてツリー状に整理(クリーンアップ)しています。

Soupオブジェクトには大量のタグに関する情報などが入っていますので、その中から[3]で<a>タグのみをリストとして取り出します。あとは、このリストをfor文で順番に見ていき、<a>タグの中にあるhref=""の中身を[4]で取り出しています。


今回のエントリはここまで。複雑なHTMLデータから<a>タグに含まれるリンク先だけを抜き出すことができるようになりました。簡単ではありますが、Webスクレイピングのスキルが身についたと言えるでしょう。
次のWeek 5ではXMLを取り扱っていきます。それでは、次回のエントリもお楽しみに!

この記事が気に入ったらサポートをしてみませんか?