Pythonクローリング&スクレイピング[増補改訂版] ―データ収集・解析のための実践開発ガイドー その16
第5章 クローリング・スクレイピングの実践とデータの活用
取得したデータ活用を思いついていませんが、テキストを進めていきたいと思います。
ジオコーディング
YOLP(地図):Yahoo!ジオコーダAPI - Yahoo!デベロッパーネットワーク
住所から位置情報を取得するために Yahoo! のジオコードを使います。API を登録して利用することができます。
curl -s 'https://map.yahooapis.jp/geocode/V1/geoCoder?appid=********-&output=json&query=東京都台東区上野公園7番7号' | jq .
美術館の位置情報
前に美術館の住所のデータを扱ったので、住所に基づいて Yahoo! ジオコードを利用して緯度経度を取得します。
import os import dbm import json import logging from typing import Iterator, Tuple, Union import requests from SPARQLWrapper import SPARQLWrapper import sys from pymongo import MongoClient client = MongoClient('localhost', 27017) YAHOO_GEOCODE_API_URL = 'https://map.yahooapis.jp/geocode/V1/geoCoder' YAHOO_APPLICATION_ID = os.environ['YAHOO_APPLICATION_ID'] # キャッシュを保存するファイル (MongoDB) db = client.scraping geocode_collection = db.geocode_collection def main(): features = [] # 美術館のリスト for museum in get_museums(): label = museum.get('label', museum['s']) address = museum['address'] if 'lon_degree' in museum: lon, lat = sexagesimal_to_decimal(museum) else: lon, lat = geocode(address) print(label, address, lon, lat) if lon is None: continue features.append({ 'type': 'Feature', 'geometory': {'type': 'Point', 'coordinates': [lon, lat]}, 'properties': {'label': label, 'address': address} }) feature_collection = { 'type': 'FeatureCollection', 'feature': features, } with open('museums.geojson', 'w') as f: json.dump(feature_collection, f) def get_museums() -> Iterator[dict]: logging.info('Executing SPARQL query...') # SPARQLのインスタンス sparql = SPARQLWrapper('http://ja.dbpedia.org/sparql') sparql.setQuery(r""" SELECT * WHERE { ?s rdf:type dbpedia-owl:Museum ; prop-ja:所在地 ?address . OPTIONAL { ?s rdfs:label ?label . } OPTIONAL { ?s prop-ja:経度度 ?lon_degree ; prop-ja:経度分 ?lon_minute ; prop-ja:経度秒 ?lon_second ; prop-ja:緯度度 ?lat_degree ; prop-ja:緯度分 ?lat_minute ; prop-ja:緯度秒 ?lat_second . } FILTER REGEX(?address, "^\\p{Han}{2,3}[都道府県]") } ORDER BY ?s """) sparql.setReturnFormat('json') response = sparql.query().convert() logging.info(f"Got {len(response['results']['bindings'])} results") for result in response['results']['bindings']: yield {name: binding['value'] for name, binding in result.items()} def sexagesimal_to_decimal(museum: dict) -> Tuple[float, float]: """ 60進数の緯度・経度を10進数に変換する """ lon = float(museum['lon_degree']) + float(museum['lon_minute']) / 60 + float(museum['lon_second']) / 3600 lat = float(museum['lat_degree']) + float(museum['lat_minute']) / 60 + float(museum['lat_second']) / 3600 return (lon, lat) def geocode(address: str) -> Union[Tuple[float, float], Tuple[None, None]]: """ 引数で指定した住所をYahoo!ジオコーダで緯度と経度のペアを返す """ print(address) if not geocode_collection.find_one({'address': address}): logging.info(f'Geocoding {address}...') req = requests.get(YAHOO_GEOCODE_API_URL, params={ 'appid': YAHOO_APPLICATION_ID, 'output': 'json', 'query': address, }) response = json.loads(req.content.decode('utf-8')) if 'Feature' not in response: geocode_collection.insert_one({'address': address, 'lon': 'None', 'lat': 'None'}) return (None, None) coordinates = response['Feature'][0]['Geometry']['Coordinates'].split(',') geocode_collection.insert_one({'address': address, 'lon': coordinates[0], 'lat': coordinates[1]}) s = geocode_collection.find_one({'address': address}) if s['lon'] == 'None' or s['lat'] == 'None': return (None, None) return (float(s['lon']), float(s['lat'])) if __name__ == '__main__': logging.basicConfig(level=logging.INFO) main()
テキストでは、dbm を使ってデータを保存していたんですが、僕の環境では使うことができなかったので、MongoDB を使いました。
本
Pythonクローリング&スクレイピング[増補改訂版] -データ収集・解析のための実践開発ガイド
- 作者: 加藤耕太
- 出版社/メーカー: 技術評論社
- 発売日: 2019/08/10
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る