はじめに
-
こんにちは ! KDDI アジャイル開発センターの小板橋です。
今回は、scrapyを利用した面白いスクレイピングツールを拝見したため、僕はそれをbeautifulsoup4で再現してみました。 -
内容としては、beautifulsoup4を利用し、NAVITIMEをスクレイピングし、指定した都道府県のコンビニ(セブンイレブン、ローソン、ファミリーマート)の住所を取得し、GCPのgeocoding apiを利用し緯度経度に変換後CSV出力するといったものです。
beautifulsoup4とは
beautifulsoup4とは、HTMLやXMLから欲しいデータを抽出するためのPythonライブラリです。
インストール方法
pipでインストールできます。
pip install beautifulsoup4
BeautifulSoupでHTMLの中からHTML要素を取得するには、下記の2タイプのメソッドを使用します。
- find系 find_all()、find()
- select系 select()、select_one()
今回は、find系のfind_all()を使用しました。
ちなみに、上記のfind系とselect系の違いなのですが、
種類 | すべての要素をリストで返却 | ひとつだけ要素を返却 | 引数 |
---|---|---|---|
find系 | find_all() | find() | 要素名,属性指定 |
select系 | select() | select_one() | CSSセレクタ |
geocoding apiとは
住所を地理座標(緯度/経度)に変換できるAPIです。
インストール方法
pipでインストールできます。
pip install googlemaps
実装
注意点: For文の最大値を下記のコードでは東京都のセブンイレブンを検索時の最大ページ数にしている
→ 引数で得たコンビニを検索時のページ最大数を取得する修正をしようとして、力つきました。笑
#!/usr/bin/env python
from urllib import request, error
from bs4 import BeautifulSoup
import csv
import googlemaps
import time
import sys
from argparse import ArgumentParser, FileType
storepath = '0201001001'
citypath = '13'
def gettext():
response = request.urlopen(url)
try:
with request.urlopen(url) as res:
res.read()
except error.HTTPError as err:
print(err.code, "wwwww")
soup = BeautifulSoup(response, 'html.parser')
response.close()
csvRow = []
googleapikey = '個人のGoogelMapのAPIkeyを設定'
gmaps = googlemaps.Client(key=googleapikey)
for i in soup.find_all(class_="ellipsis"):
i.extract()
for j in soup.find_all(class_="spot-detail-value-text"):
texts = j.get_text()
csvRow.append(texts.strip())
with open("store_lat_lng.csv", "a", encoding='utf-8') as file:
for csvRows in csvRow:
result = gmaps.geocode([csvRows])
if len(result) != 0 :
lat = result[0]["geometry"]["location"]["lat"]
lng = result[0]["geometry"]["location"]["lng"]
writer = csv.writer(file)
writer.writerow([csvRows, lat, lng])
time.sleep(0.5)
print("終了")
sys.exit()
p = ArgumentParser(description='指定した都市におけるコンビニの緯度経度をCSVとして吐き出す')
p.add_argument('--store', choices=['セブンイレブン', 'ローソン', 'ファミリマート'], default='セブンイレブン', help='default=セブンイレブン')
p.add_argument('--city', choices=['tokyo', 'Kanagawa', 'Osaka'], default='tokyo', help='default=tokyo')
args = p.parse_args()
if args.store == 'セブンイレブン' :
storepath = '0201001001'
if args.store == 'ローソン' :
storepath = '0201001009'
if args.store == 'ファミリマート' :
storepath = '0201001006'
if args.city == 'tokyo' :
citypath = '13'
if args.city == 'Kanagawa' :
citypath = '14'
if args.city == 'Osaka' :
citypath = '27'
url = 'https://www.navitime.co.jp/category/{0}/{1}'.format(storepath, citypath)
gettext()
for i in range(2, 60):
url = 'https://www.navitime.co.jp/category/{0}/{1}/?page={2}'.format(storepath, citypath, i)
gettext()
動作
--helpで引数を確認
~/Desktop
❯ ./遊び用Pythonツール/google_map_scraping.py --help
usage: google_map_scraping.py [-h] [--store {セブンイレブン,ローソン,ファミリマート}]
[--city {tokyo,Kanagawa,Osaka}]
指定した都市におけるコンビニの緯度経度をCSVとして吐き出す
optional arguments:
-h, --help show this help message and exit
--store {セブンイレブン,ローソン,ファミリマート}
default=セブンイレブン
--city {tokyo,Kanagawa,Osaka}
default=tokyo
~/Desktop
❯
Defaultの値で実行
~/Desktop
❯ ./遊び用Pythonツール/google_map_scraping.py
終了
CSVを確認
東京都三鷹市新川6-3-14,35.68321359999999,139.5685815
東京都千代田区永田町2丁目2番1号,35.6745788,139.743009
東京都港区六本木3-2-1,35.6645869,139.7377776
東京都八王子市高尾町1806-1,35.6333012,139.2562665
東京都世田谷区玉川3-11-7,35.6136912,139.6256771
東京都世田谷区太子堂2-12-1,35.6450583,139.6735356
東京都大田区東海3丁目2番1号,35.5789543,139.7591679
東京都目黒区下目黒5-18-21,35.6306158,139.7021458
東京都町田市鶴間8丁目15番21号,35.5103597,139.4769608
東京都千代田区九段南3-1-1,35.692245,139.7434825
東京都福生市熊川1411-6,35.7253801,139.3431771
東京都中央区新川2-27-2,35.6742508,139.7843206
東京都中央区日本橋箱崎町22-1,35.6815297,139.7862889
東京都新宿区中落合3-1-3,35.7223184,139.6919351
東京都新宿区新宿2-6-4,35.6900244,139.7071167
東京都新宿区西新宿6-5-1,35.6931766,139.6931655
東京都八王子市石川町2441-5,35.6739094,139.363978
東京都八王子市戸吹町1469-1,35.70595,139.2971229
・
・
・
Google Mapで表示してみた
1.Google Mapで[マイプレイス]を選択します。
2.[地図を作成] → [インポート]を選択し、先ほどのPythonツールで出力したCSVを読み込ませる。
その後、列の緯度/経度をしていると一括で、表示される
多いですね。。w
おわり
注意点としては、geocoding apiの使用料ですかね、1000リクエストで$5なので、お金のない僕としてはきついですw