勉強中です。備忘録として記載しています。
Webスクレイピングに役立つPythonライブラリ
- RequestsとBeautiful Soup
- Scrapy
- Selenium
HTTP概要
WebブラウザとWebサーバーは、HTTP(Hyper-Text Transfer Protocol)という通信プロトコル(ルール)に則って情報の受け渡しを行っている。
クライアント(Webブラウザ)は、HTTPのGETメソッドでサーバー(Webサーバー)に、「このURLのページを下さい」とリクエストを送り、それに対して、サーバーはページをHTMLファイルを返す(リスポンス)。
スクレイプ開始
スクレイピングでは,次のことを行う.
- WebサーバーにGETリクエストを送り、ResponseのHTMLを受け取る
- HTMLを解析し,必要な情報を抽出し保存する
今回,PythonでrequestsとBeautifulSoupモジュールを使いこの作業を行う.
スクレイピングするサイトは,名古屋市プレミアム付商品券加盟店一覧:https://nagoya-shouhinken.com/shop/
プレミアム付商品券は自治体実施のお得なキャンペーンだが,どのお店で使えるかが,このサイトで検索しない限りわからない,しかも加盟店は6000店舗を超えており,一覧を手に入れるには,10件/頁 x 600ページを延々とクリックしていく必要がある.これをプログラミングでポチッと終わらせることが今回の目標だ.
WebページのHTMLを見てみると,iframeが使われていることが分かった,iframは,別のサイトにリンクして,リンク先の情報を表示させる.
リンク先のページを確認する.
リンク先 https://sub.nagoya-shouhinken.com/prd/c_app/shoplists?page=614
では,早速コードを書いていく.
まずは,HTMLファイルをGet要求し,Responseを変数に入れる.
#必要なライブラリをインポート
from bs4 import BeautifulSoup
import requests
#Get要求し,Responseを「page」変数に入れる
page = requests.get(url)
#「page」のコンテンツをBeautifulSoupモジュールで解析し,「soup」変数に文字列として入れる
soup = BeautifulSoup(page.content, 'html.parser')
次に、欲しい情報の抽出を行う。
「店名」等欲しい情報のタグを確認.HTMLタグとclassを引数にして,ページから該当するタグとclassを持つデータを抽出する.
#「店名」,「エリア」,「カテゴリ」を抽出
#classを渡すときの,引数名は「class_」.アンダースコアを忘れないようにする
names = soup.find_all("h2", class_="p-area-shoplist__headline")
areas = soup.find_all("dd", class_="-area")
categories = soup.find_all("dd", class_="-category")
結果をprintし,欲しかった情報が抽出されていることを確認する.
「areas」変数の中身をprint.
for area in areas:
print(area.text)
今回は「取扱券種」は抽出対象外とした.
「住所」と「TEL」だが,タグが入れ子構造になっており,「住所」だけを指定して抽出する方法が不明だったので,より上位のタグとclassで,「TEL」と一緒に情報を抽出し,抽出したデータから,「住所」と「TEL」を抜き出すことにする.
#「住所」,「TEL」を抽出
addresses = soup.find_all("dl", class_"p-area-shoplist__address")
では次に,1ページ目以外の,他のページをどのようにスクレイピングするのか考える.
2ページ目や3ページ目のリンクにカーソルをあてると,URLの最後にページ番号(page=(ページ番号))がついていることが分かる.
リンク末尾にページ番号をつけ,ページ数分ループすることで,全ての情報が取れそうだ.
最終的なコードはこちら
from bs4 import BeautifulSoup
import requests, random, time
for p in range(1,614):
url = 'https://sub.nagoya-shouhinken.com/prd/c_app/shoplists?page=' + str(p)
page = requests.get(url)
soup = BeautifulSoup(page.content, 'html.parser') #page変数はHTMLなので,内容が文字列として取り出す
names = soup.find_all("h2", class_="p-area-shoplist__headline")
areas = soup.find_all("dd", class_="-area")
categories = soup.find_all("dd", class_="-category")
addresses = soup.find_all("dl", "p-area-shoplist__address")#住所とTELを含む情報をまとめて持つ
#この後CSVファイルにしてエクスポートするために,結果をリストに入れていく
result = []
d = {}
for i in range(10):
name = names[i].text.split('\n')[1].strip() #余分な余白を削除してある
area = areas[i].text
category = categories[i].text
address = addresses[i].text.split("\n")[3] #住所のみを取り出してある
tel = addresses[i].text.split("\n")[-3] #TELのみを取り出してある
d = {"name": name, "area": area, "category": category, "address": address, "tel": tel}
result.append(d)
time.sleep(random.randint(5,8)) #次のスクレイぷに進むまで5〜8秒ランダムに待つ