LoginSignup
0
0

More than 1 year has passed since last update.

Python BeautifulSoup: キャンペーン加盟店をスクレイプした備忘録

Last updated at Posted at 2023-05-02

勉強中です。備忘録として記載しています。

Webスクレイピングに役立つPythonライブラリ

  • RequestsとBeautiful Soup
  • Scrapy
  • Selenium

HTTP概要

WebブラウザとWebサーバーは、HTTP(Hyper-Text Transfer Protocol)という通信プロトコル(ルール)に則って情報の受け渡しを行っている。
クライアント(Webブラウザ)は、HTTPのGETメソッドでサーバー(Webサーバー)に、「このURLのページを下さい」とリクエストを送り、それに対して、サーバーはページをHTMLファイルを返す(リスポンス)。
image.png

スクレイプ開始

スクレイピングでは,次のことを行う.

  1. WebサーバーにGETリクエストを送り、ResponseのHTMLを受け取る
  2. HTMLを解析し,必要な情報を抽出し保存する

今回,PythonでrequestsとBeautifulSoupモジュールを使いこの作業を行う.
スクレイピングするサイトは,名古屋市プレミアム付商品券加盟店一覧:https://nagoya-shouhinken.com/shop/
プレミアム付商品券は自治体実施のお得なキャンペーンだが,どのお店で使えるかが,このサイトで検索しない限りわからない,しかも加盟店は6000店舗を超えており,一覧を手に入れるには,10件/頁 x 600ページを延々とクリックしていく必要がある.これをプログラミングでポチッと終わらせることが今回の目標だ.

WebページのHTMLを見てみると,iframeが使われていることが分かった,iframは,別のサイトにリンクして,リンク先の情報を表示させる.
リンク先のページを確認する.
image.png
リンク先 https://sub.nagoya-shouhinken.com/prd/c_app/shoplists?page=614

店舗情報が下画像のボックス上に並んでいる.
image.png

では,早速コードを書いていく.
まずは,HTMLファイルをGet要求し,Responseを変数に入れる.

code.py
#必要なライブラリをインポート
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を持つデータを抽出する.

code.py
#「店名」,「エリア」,「カテゴリ」を抽出
#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.

code.py
for area in areas:
  print(area.text)

今回は「取扱券種」は抽出対象外とした.
「住所」と「TEL」だが,タグが入れ子構造になっており,「住所」だけを指定して抽出する方法が不明だったので,より上位のタグとclassで,「TEL」と一緒に情報を抽出し,抽出したデータから,「住所」と「TEL」を抜き出すことにする.

code.py
#「住所」,「TEL」を抽出
addresses = soup.find_all("dl", class_"p-area-shoplist__address")

では次に,1ページ目以外の,他のページをどのようにスクレイピングするのか考える.
2ページ目や3ページ目のリンクにカーソルをあてると,URLの最後にページ番号(page=(ページ番号))がついていることが分かる.
image.png
リンク末尾にページ番号をつけ,ページ数分ループすることで,全ての情報が取れそうだ.

最終的なコードはこちら

code.py
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秒ランダムに待つ
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0