今回のPythonのプログラムは特定のURLを指定するとそのサイトをスクレイピングして、タイトルとHタグ(H1からH6タグ)をGoogleスプレッドシートに記録してくれるプログラムです。
このプログラムを通してPythonを使った簡単なスクレイピングの基礎を学ぶことが可能です。
このページを通して学べること
- BeautifulSoupとrequestsを使ったpythonでの基本的なHTTPリクエストとスクレイピングの方法
- PythonでスクレイピングのデータをGoogleスプレッドシートの読み込みと書き込む方法
URLをスクレイピングして、Googleスプレッドシートにタイトルと見出しを書き出すプログラムのソースコード
ファイル名:script.py
from bs4 import BeautifulSoup import requests import gspread from gspread.exceptions import * from oauth2client.service_account import ServiceAccountCredentials from datetime import datetime import sys def scrape(url, worksheet): html = requests.get(url) #取得したHTMLをパース soup = BeautifulSoup(html.content, "html.parser") r = next_available_row(worksheet) datetimestr = datetime.now().strftime("%Y/%m/%d %H:%M:%S") worksheet.update_acell('A' + str(r), datetimestr) worksheet.update_acell('B' + str(r), url) worksheet.update_acell('C' + str(r), soup.title.get_text()) start_ascii = 67 for i in range(1, 7): elems = soup.find_all('h' + str(i)) text_list = [] for elem in elems: text_list.append(elem.get_text().strip()) text = ','.join(text_list) worksheet.update_acell(chr(start_ascii + i) + str(r), text) def next_available_row(worksheet): str_list = list(filter(None, worksheet.col_values(1))) # fastest return str(len(str_list) + 1) def get_gspread_book(secret_key, book_name): scope = ['https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/drive'] credentials = ServiceAccountCredentials.from_json_keyfile_name(secret_key, scope) gc = gspread.authorize(credentials) book = gc.open(book_name) return book ''' メイン処理 ''' if __name__ == '__main__': url = 'https://hashikake.com/scraping-python' print('url: ' + url + ' のTitle、hタグを抽出します。') secret_key = 'My Project 〇〇〇〇.json' book_name = 'HTMLスクレイピングテスト' sheet_name = 'シート1' try: sheet = get_gspread_book(secret_key, book_name).worksheet(sheet_name) except SpreadsheetNotFound: print('Spreadsheet: ' + book_name + 'が見つかりませんでした') sys.exit() except WorksheetNotFound: print('Worksheet: ' + sheet_name + 'が見つかりませんでした') sys.exit() scrape(url, sheet) print('処理が完了しました。')
【最新】はじめてPythonをインストールするための手順についてOS別(Windows10, Mac)で解説
ソースコードの詳細な解説
ではここからソースコードの詳細な解説に移りたいと思います。
7つのライブラリをimportする
今回はスクレイピングを行うことと、グーグルスプレッドシートを扱うために、7つのライブラリをインポートします。
Pythonの【モジュール】の使い方。パッケージやライブラリとの違いも解説
HTMLの構造を解析するためのBeautifulSoup
BeautifulSoupは、HTMLの構造を解析するためのスクレイピングに特化した外部ライブラリです。
スクレイピングの際にはよく、このBeautifulSoupがインポートされます。
※まず始めにBeautifulSoupをプログラムの実行の前にインストールしましょう。
コマンドプロンプトで
pip install beautifulsoup4
と入力してEnterを押し、インストールして下さい。
1行目:
from bs4 import BeautifulSoup
ソースコードの冒頭では、BeautifulSoupというライブラリを使用するのでbs4モジュールをimportします。
ライブラリの中ではさらにクラスというもので機能が細分化されており、
今回はBeautifulSoupというクラスをimportしています。
HTTP通信を行うrequestsモジュール
Requestsモジュールは、Http(s)サイトにGETリクエストやPOSTリクエストを送るために使われる外部ライブラリで、とても簡単にHttp(s)サイトに対して色々な操作を行うことができます。
※インストールがまだの方はコマンドプロンプトで
pip install requests
と入力してインストールして下さい。
2行目:
import requests
RequestsはWebページを取得するために使います。
流れとしてはRequestsでWebページを取得し、BeautifulSoupでスクレイピングをします。
グーグルスプレッドシートを操作できるgspread
gspreadはGoogleスプレッドシートを操作するためのライブラリです。
※インストールがまだの方はコマンドプロンプトで
pip install gspread
と入力してインストールして下さい。
ソースコードの冒頭では、下記のようにインポートしています。
3行目:
import gspread
gspread利用時のエラー内容が書いてあるexceptions.py
4行目:
from gspread.exceptions import *
gspreadフォルダのexceptions.pyというモジュールをimportします。
これは、gspreadライブラリを使用する際に発生するエラーが記述されたファイルになります。
‘*’を指定することで、exceptionsファイル内に記述されたクラスや関数全てを使用することができます。
グーグルのサービスと連携するために必須のServiceAccountCredentials
5行目:
from oauth2client.service_account import ServiceAccountCredentials
ServiceAccountCredentialsはGoogleの各種サービスへサービスアカウントを使ってアクセスできるようにするクラスです。
これによってグーグルスプレッドシートAPIにアクセスするための認証情報を設定していきます。
※インストールがまだの方はコマンドプロンプトで
pip install oauth2client
と入力してインストールして下さい。
日時の処理をしてくれるdatetime
日時の処理ができるdatetimeライブラリをimportしています。
6行目:
from datetime import datetime
標準ライブラリーなので、インストールの必要はありません。
Pythonのシステムに関わる処理を行う関数が含まれたsys
Pythonのシステムに関わる処理を行うsysモジュールをimportしています。
7行目:
import sys
標準ライブラリーなのでインストールの必要はありません。
sysモジュールは、Pythonのインタプリタで使用している変数や、インタプリタの関数を定義しています。
スクレイピングのためのscrape関数の定義
8~11行目:
def scrape(url, worksheet): html = requests.get(url) #取得したHTMLをパース soup = BeautifulSoup(html.content, "html.parser")
WebページのResponseオブジェクトを取得
9行目:
html = requests.get(url)
requests.get()によって、urlやステータスコード、レスポンスヘッダ、テキスト、エンコーディングなどのWebページの様々なResponseオブジェクトを取得します。
requests.get()によって取得できる属性は以下です。
Webページの中身を取得
11行目:
soup = BeautifulSoup(html.content, "html.parser")
先ほど取得したWebページはhtml変数に入っています。
BeautifulSoupライブラリの()内を
html.content
とすることでWebページのHTMLを指定しています。
また、
"html.parser"
というパーサーを指定します。
これによって取得したHTMLの内容をパースすることができるようになります。
パースとは
パースとは、簡単に言えばhtmlの構造や意味を解析してpythonで扱えるようにすること。
そのパースをしてくれるものをパーサーと言います。
ソースコードをもう一度確認する
next_available_row関数
13行目:
r = next_available_row(worksheet)
next_available_row関数は中盤のほうで定義されている関数ですが、スプレッドシートの最初の空白行の行番号を返してくれる関数です。引数はシート、戻り値はGoogleスプレッドシートの行番号です。
例えば、1行目に見出しが記入されていたら、2行目から値を記入していきたいなどの場合に使えます。
現在の日時を取得する
15行目:
datetimestr = datetime.now().strftime("%Y/%m/%d %H:%M:%S")
ここでは、現在の日時を取得して、変数datetimestrに代入するという操作を行っています。
datetime.now()
で現在の日時を取得できます。
取得した日時はdatetime型というものになっているので
datetime.now().strftime("%Y/%m/%d %H:%M:%S")
とすることで”年/月/日 時:分:秒”という形で文字型に変換します。
これをdatetimestr変数に代入します。
A列のセルに日付を書き込む
16行目:
worksheet.update_acell('A' + str(r), datetimestr)
シート名.update_acell(“セル”, “B”)
でセルの値にBを書き込みます。
str()関数は()内の数字を文字列に変換します。
str(r)としているのは、rを文字列に変換して、A1のような形でセルを表現するために文字列と数字を結合するためです。
今回はArセルに日付の値datetimestrを書き込んでいます。
例えば、
str(r) = ‘1’
の場合、
A1セルにdatetimestr変数に代入された日付の値を書き込みます。
B列のセルの値にURLを書き込む
17行目:
worksheet.update_acell('B' + str(r), url)
この行では、B列のセルにurl変数に代入されたURLを書き込みます。
C列のセルにWebページのタイトルを書き込む
18行目:
worksheet.update_acell('C' + str(r), soup.title.get_text())
ここでは、C列のセルにsoup.title.get_text()で得られる値を書き込んでいます。
soup.title.get_text()
の部分はWebページのタイトルです。
soup.title
で、タグが付いたWebページのタイトルを取得できます。
ただし取得したデータにはタグが付いていますので、その後ろに
.get_text()
を付けることで不要なタグを取り除くことができます。
‘C’を意味するASCIIコードを代入
20行目:start_ascii = 67
start_ascii変数に67を代入します。
これはASCIIコードで大文字の’C’を意味します。
ASCII(アスキー)コードとは
コンピュータは二進数しか扱えません。
ですので、文字データも厳密には二進数として表現されています。
コンピュータ内では、二進数を文字に置き換えて処理しているのです。
このように文字を二進数で表現する数字の事を「文字コード」と言います。
ASCIIコードは文字コードの一種になります。
処理を繰り返す命令
21行目:
for i in range(1, 7):
for文でiに1?6までの数字を代入して、繰り返す処理を実行します。
range(開始, 終了)
は第一引数に開始番号を指定し、第二引数に終了番号を指定すると、その範囲のリストを返します。
注意が必要なのが第二引数の「終了」です。
これは第一引数の「開始」と違い、終了させたい番号に+1した数字を指定する必要があります。
ですからソースコードのように「1?6まで」の範囲を指定したい場合は
range(1, 7)
と終了番号を「6+1=7」とします。
見出しの要素を取得
22行目:
elems = soup.find_all('h' + str(i))
HTMLのソースの中から、何か要素を探すには、soup.find_all()を使います。
ここでは、h○という形の要素を探して取得しています。
具体的には見出しタグを探しています。
soup.find_all()
でh要素のリストを取得し、elems変数に代入します。
for文のiに代入される数字によってh1?h6の要素が取得できます。
見出しを抽出
23行目:
text_list = []
text_listに空のリストを代入します。
24行目:
for elem in elems:
ここから、for文での繰り返し処理です。
先ほど取得したh要素のリスト(elems変数)からh要素をひとつずつ取り出してelem変数に代入して、for文 以下に続く処理を繰り返していきます。
25行目:
text_list.append(elem.get_text().strip())
取り出したh要素にはタグが付いていますので、前に出てきた
get_text()
でタグを取り除いてからtext_listリストに追加します。
また文字列の両端に不要な空白や改行コードが付いている場合もありますので、さらにその後ろに
.strip()
を付けることで文字列の両端の不要な空白と改行コードを取り除くことができます。
リスト.append(要素)
で、リストに要素を追加することができます。
例えば、[1, 2].append(3)となっている場合、[1, 2]は[1, 2, 3]
となります。
[1, 2, 3].append(5)となっている場合[1, 2, 3]は[1, 2, 3, 5]となります。
今回だと、
text_list.append(elem.get_text().strip())
となっているので、text_listのリストに要素elem.get_text().strip()
を追加することになります。
','.join(text_list)
join(リスト)でリスト内の文字列を連結することができます。
例えば、
test1=[a, c, x] というリストがあった場合、
”.join(test1) = ‘acx’
というように、リスト内の文字列を繋げることができます。
‘,’.join()
とすることで、文字列の間にコンマを入れて連結する形になります。
‘,’.join(test1) = ‘a,c,x’
の’,’を’/’にすると
text = ‘python/ruby/php’
という風に連結できます。
今回は、
','.join(text_list)
となっており、text_listは見出しのテキストが入っているので、
見出しのテキストをコンマでつないだ文字列ができます。
27行目:
worksheet.update_acell(chr(start_ascii + i) + str(r), text)
text変数に代入された文字列でセルの値を更新します。
ASCIIコードを文字列に変換
chr()では、ASCIIコードを文字列に変換します。
例えば
start_ascii = 67
とすると、
chr(start_ascii)
は、Cになります。
関数の定義1つ目、next_available_row関数
29~31行目:
def next_available_row(worksheet): str_list = list(filter(None, worksheet.col_values(1))) # fastest return str(len(str_list) + 1)
next_available_row関数を定義しています。
Googleスプレッドシートの上から数えて一番始めの空の行番号を指定するための関数です。
30行目:
str_list = list(filter(None, worksheet.col_values(1))) # fastest
・worksheet.col_values(1)
Googleスプレッドシートの列番号1の値を取得します。
これらの値はリストとなります。
・list(filter(None, worksheet.col_values(1)))
セルに値が入力されていない場合は除去され、list()でリストにします。
例えば、
worksheet.col_values(1) = ['python', '', 'php']
のように、リスト内に空文字がある場合、
list(filter(None, worksheet.col_values(1))) = ['python', 'php']
と、空文字は除去されます。
31行目:
return str(len(str_list) + 1)
・str(len(str_list) + 1)
len()で、リストにある要素の数を取得します。
そして、それを+1した数字が戻り値に指定されます。
関数の定義2つ目、get_gspread_book関数
33~40行目:
def get_gspread_book(secret_key, book_name): scope = ['https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/drive'] credentials = ServiceAccountCredentials.from_json_keyfile_name(secret_key, scope) gc = gspread.authorize(credentials) book = gc.open(book_name) return book
get_gspread_book関数を定義しています。
Googleスプレッドシートを開くための関数になります。
APIを指定
34~35行目:
scope = ['https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/drive']
scope変数に2つのAPIを記述しないとアクセストークンを3600秒毎に
発行し続けなければならないので指定します。
アクセストークン
google APIにアクセスするには、アクセストークンというものが必要です。
しかしアクセストークンは3600秒で有効期限が切れてしまいます。
有効期限が切れたら、毎回アカウント認証をする操作が必要になります。
リフレッシュトークンは、新しいアクセストークンを自動で取得してくれます。
37行目:
credentials = ServiceAccountCredentials.from_json_keyfile_name(secret_key, scope)
認証情報を設定します。
secret_keyにはダウンロードしたjsonファイルを指定します。
38行目:
gc = gspread.authorize(credentials)
認証情報を使用して、GoogleAPIにログインします。
39行目:
book = gc.open(book_name)
ファイル名が代入されたbook_nameを指定して、Googleスプレッドシートを開きます。
開いたGoogleスプレッドシートを戻り値に指定します。
メイン処理
43行目:
if __name__ == '__main__':
script.pyを実行すると、__name__には’__main__’という値が代入されます。
if文がTrueとなるので、43行目以下の処理が実行されます。
もし違うスクリプトでscript.pyをimportして、
script.pyに記述された関数を使用したい場合、
import script
のように書きますが、他のスクリプトからimportして読み込んだ場合、
__name__には、ファイル名である’script’という値が代入されますので、
if文がFalseとなり、43行目以下の処理は実行されません。
script.pyを直接実行した時だけ、43行目以下の処理が実行されるので注意しましょう。
抽出したいWebページのURLを指定
44行目:
url = 'https://hashikake.com/scraping-python'
urlという変数にスクレイピングするWebページのURLを指定しています。
45行目:
print('url: ' + url + ' のTitle、hタグを抽出します。')
url: https://hashikake.com/scraping-python のTitle、hタグを抽出します。
という文章が、printによって出力されます。
46行目:
secret_key = 'My Project 〇〇〇〇.json'
secret_key変数にはダウンロードしたjsonファイルを指定します。
注意:
secret_key = 'My Project 〇〇〇〇.json'
の
'My Project 〇〇〇〇.json'
の部分は一人ひとり違ってきますのでこのソースコードをダウンロードしてもそのままでは動きません。このソースコードを動かしたい方はまず最初に下記の準備が必要になります。
グーグルスプレッドシートの事前準備
Googleのアカウントを用意してから以下のサイトを参考にして
・Google Cloud Platformで新規プロジェクトを作成する
・Google Drive APIを有効にする
・Google Sheets APIを有効にする
・認証情報を設定してJSONファイル(秘密鍵)をダウンロードする
を行って下さい。
参考サイト:【もう迷わない】Pythonでスプレッドシートに読み書きする初期設定まとめ
※ダウンロードしたJSONファイルは再発行はできませんので間違って削除したり紛失したりしないよう注意して下さい。
無事ダウンロードが済みましたらそのJSONファイルをソースコードと同じフォルダの中に入れます。
それからソースコードの
46行目:
'My Project 〇〇〇〇.json'
の部分をご自身がダウンロードしたJSONファイルのファイル名に置き換えて下さい。
47行目:
book_name = 'HTMLスクレイピングテスト'
book_name変数には、Googleスプレッドシートのファイル名を指定します。
スプレッドシートの用意がまだの方はGoogleアカウントでGoogle ドライブにログインし、左上の「新規」ボタンをクリックしてから「Googleスプレッドシート」をクリックしてスプレッドシートを用意して下さい。
開いたスプレッドシートの左上を見るとスプレッドシート名が「無題のスプレッドシート」となっていますのでクリックして「HTMLスクレイピングテスト」に名前を変更すると良いです。
注意:
このプログラムを動かす前に、用意したスプレッドシートへの設定が必要になります。
以下のサイトを参考にして
・先ほどダウンロードしたJSONファイルをテキストエディタで開いて
“client_email”: “○○”
の○○のメールアドレスの部分をコピーします。
・スプレッドシートの右上の「共有」ボタンをクリックして○○の部分をペーストしてから「送信」ボタンをクリックするを行って下さい。
参考サイト:【もう迷わない】Pythonでスプレッドシートに読み書きする初期設定まとめ
48行目:
sheet_name = 'シート1'
sheet_name変数の‘シート1’の部分には、Googleスプレッドシートのシート名を指定します。
エラーが出た場合の処理は2パターン
49~50行目:
try: sheet = get_gspread_book(secret_key, book_name).worksheet(sheet_name)
ここで、別ページでも説明したtry-except文がまた出てきました。
今回はエラーのパターンを2種類用意して、どちらが起こった場合でもプログラムが途中で停止しないようにしています。
SpreadsheetNotFoundエラーが発生した場合
51~53行目:
except SpreadsheetNotFound: print('Spreadsheet: ' + book_name + 'が見つかりませんでした') sys.exit()
「Spreadsheet: HTMLスクレイピングテストが見つかりませんでした」
とprint()によって出力されます。
存在しないスプレッドシートか、アクセスできないスプレッドシートを開こうとするとエラーが発生します。
53行目:
sys.exit()
でプログラムを終了させます。
WorksheetNotFoundエラーが発生した場合
54~56行目:
except WorksheetNotFound: print('Worksheet: ' + sheet_name + 'が見つかりませんでした') sys.exit()
「Worksheet: シート1が見つかりませんでした」
とprintによって出力されます。
存在しないシートか、アクセスできないシートを開こうとするとエラーが発生します。
56行目:
sys.exit()
でプログラムを終了させます。
エラーが発生しなければ、exceptの中で記述されたコードは無視されます。
ワークシートを取得
50行目:
sheet = get_gspread_book(secret_key, book_name).worksheet(sheet_name)
get_gspread_book関数の戻り値で開いたスプレッドシートが指定されています。
さらに
worksheet('シート名')
と指定することでワークシートが取得できます。
webページから、情報を抽出する
57行目:
scrape(url, sheet)
scrape関数を実行し、Webページから必要な情報をスクレイピングします。
処理の完了
58行目:
print('処理が完了しました。')
スクレイピングが終了したら、「処理が完了しました。」とprintで出力します。
すぐに使いたい方向けのマニュアル
1.パソコンにPythonをインストールしていない方はまずこちらでインストールの方法を確認しましょう。
2.マイドキュメントなどに適当な名前のフォルダを作り、その中に新規テキストファイル(.txt)を作成し、プログラムのソースコードを張り付けて、拡張子を.txtから.pyに変換してscript.pyという名前で保存します。
3.書き込みに使うグーグルスプレッドシートをこちらを見て準備しましょう。
また、ソースコードの
url = ‘https://hashikake.com/scraping-python’
の部分にスクレイピングしたいURLを入力しておいてください。
4.Windowsならコマンドプロンプト、Macならターミナルを開きファイルを置いてあるパス(URL)へ移動します。
移動の方法はコマンドプロンプトでもターミナルでも
cd ファイルが置いてあるパス
のコマンドで移動できます。
5.コマンドプロンプト、またはターミナルで
pip install gspread
のコマンドを入力して、Enterを押します。
同様に
pip install oauth2client
pip install requests
も同じようにして下さい。
それぞれライブラリのインストールが始まります。
5.コマンドプロンプト、またはターミナルで
カレントディレクトリにいることを確認して
Python script.py
と入力してEnterを押します。
これでスプレッドシートに自動で記入されることが確認できたら完了です。
プログラムを実行していただいたり、改良して@uury112をつけてメンション付きのツイートをしていただければ(https://twitter.com/uuyr112)でリツイートさせていただきます。
コメント