GoogleCloudのPlacesAPIを利用して会社名から電話番号を自動取得

# GoogleCloudのPlacesAPIについて

PlacesAPIについて簡単に説明すると、GoogleMapsPlatform APIの一部です。場所を検索したり、経路や道のりを自動取得するのに役立ちます。
[公式ドキュメント -Google Maps Platform -Places API](https://developers.google.com/maps/documentation/places/web-service?hl=ja)
GoogleMapsPlatformのAPIは数多ありますが、今回は会社名から電話番号を取得するので __PlacesAPI__ を利用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3500912/03856ca2-e6a3-48a5-132b-fc8674e334ee.png)
また、PlacesAPIには __PlacesAPI__ と __PlacesAPI(New)__ がありますが、後者の方が機能面に充実しており、より安全で信頼性の高いとされているので今回はこれを利用します。
[PlacesAPIとPlacesAPI(new)の違い](https://developers.google.com/maps/documentation/places/web-service/choose-api?hl=ja)

# GoogleCloudのコンソールからAPIキーを作成
もちろんAPIを利用するにはアカウントが必要です。Googleも神様ではないので、一定の通信量を超えると料金が発生する __従量課金制__ です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3500912/4f754873-6e10-7326-66f4-c9987c450aba.png)

Googleアカウントを作成し、GoogleCloudのコンソール画面に移動してAPIライブラリから __PlacesAPI(New)__ を有効化してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3500912/e6a63ab4-e7ac-ec95-a1c9-30a0b4fd9753.png)

その後、ランダムな文字列であるAPIキーが表示されるので、それを保存しておいてください。
また、利用にはクレジットカードでの支払い方法を登録する必要があります。

## 実行するAPIリファレンス
PlacesAPIのなかのどのAPIをリファレンスするかについては、[Place Details](https://developers.google.com/maps/documentation/places/web-service/place-details?hl=ja)が該当します。入力されたTextを検索し、でてきた情報（今回はその施設の電話番号）を抽出する際に利用するものです。
また、情報を取得する過程についてはTextで直接結果がでるのではなく、place_idというものを取得してその内容を参照します。
[place_idについての詳細情報  -Googleマップで、特定の場所を一意に識別するID](https://developers.google.com/maps/documentation/places/web-service/place-id?hl=ja)
### 利用するライブラリ
また、今回はJavascriptではなくPythonで実行するので以下のライブラリをインストールしてください。
https://pypi.org/project/googlemaps/

```ターミナル
$pip install googlemaps
```

# Pythonコード内で実際に利用する
実務で利用する場面を想定しているので、今回は以下のような仮装の案件を用意しました。

__・ジモティーで検索し、でてきた案件の住所から電話番号を抽出する__

今回はあくまで実験であり、学習のために行うものです。このページに存在するソースコードの第三者の利用についての責任については私と関連しません。

## Webページから会社名一覧を取得する
まずはジモティーの案件一覧から住所をスクレイピングするコードを作成します。
今回は __requests__ を利用します。
もちろん __BeautifulSoup4__ も利用します。
https://pypi.org/project/beautifulsoup4/
```
$pip pip install beautifulsoup4
```
```
$pip install requests
```
https://jmty.jp/mie/rec-care

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3500912/add0c06a-059b-d869-d238-a4509784374b.png)



上記はジモティーに掲載されているの三重県の医療のアルバイト・バイト・パートの求人募集情報一覧です。まずは、このページにリクエストを送りHTMLをパースします。
bs4の具体的な使い方と仕組みについては[こちら](https://www.python.ambitious-engineer.com/archives/981)を御覧ください。

### メインページのHTMLをパースする
```python
import requests
from bs4 import BeautifulSoup
url = "https://jmty.jp/mie/rec-care"
response = requests.get(url=url)
soup = BeautifulSoup(response.content, "html.parser")
```

これで、メインページのHTMLをパースできました。
つぎに、ここからそれぞれの案件のURLを取得し、それぞれにリクエストを送るコードを書きます。

### URLの場所を特定
F12キーを押して、メインページを開発者ツールでみてみます。
それぞれの案件がそれぞれ __li class ="p-articles-list-item"__ タグに格納サれていることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3500912/6065776b-8109-91e6-2a5f-d4378240ef92.png)


基本的に一つのタグの中にURLが含まれている場合、 __aタグのhref__ に存在しています。今回は以下の箇所になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3500912/de77aa8a-ea23-b42e-d588-423bab4bcf1c.png)


---
### それぞれの案件をパース
これらの情報がわかったので、案件それぞれのURLにアクセスしパースするコードをfor文で書きます

```python
import requests
from bs4 import BeautifulSoup
url = "https://jmty.jp/mie/rec-care"
response = requests.get(url=url)
soup = BeautifulSoup(response.content, "html.parser")

for job in soup.find_all("li", class_="p-articles-list-item"):
    job_url = job.a["href"]
    job_response = requests.get(job_url)
    job_soup = BeautifulSoup(job_response.content, "html.parser")
```

### 会社住所を抽出
ページ先のデフォルトの情報のテーブルに、「社名/店名」という要素が存在します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3500912/27cb6555-4454-c46f-9171-b5a35a801e96.png)
---
テーブルのHTMLは以下のようになっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3500912/ff789d29-6dbe-78e1-01d6-665de4935de5.png)
tdタグの __class="p-article-column-key"の次にあるtdタグ__ のtextを取得すればいいので、bs4のnextメソッドを利用します。今回は、findメソッドで判定します。

```python
import requests
from bs4 import BeautifulSoup
url = "https://jmty.jp/mie/rec-care"
response = requests.get(url=url)
soup = BeautifulSoup(response.content, "html.parser")

for job in soup.find_all("li", class_="p-articles-list-item"):
    job_url = job.a["href"]
    job_response = requests.get(job_url)
    job_soup = BeautifulSoup(job_response.content, "html.parser")
    main_table = job_soup.find('table', class_="unstriped p-article-column")

    company_name = next((row.find('td', class_="p-article-column-value").get_text(strip=True) for row in main_table.find_all('tr') if '社名/店名' in row.text), None)
    company_name = company_name if company_name else ""
    print(company_name)
```
>get_text メソッドは、要素内のテキストを取得します。strip=True は、テキストの前後の空白を取り除くためのオプションです。
next メソッドは、条件に一致する次の要素を取得します。この例では、main_table 内の各行で '社名/店名' が含まれている行を検索し、それに対応する企業名を取得しています。
また、例外処理をするために(これは特殊な記法ですが)三項演算子を使用しており、company_name が None の場合は空の文字列に設定します。これは、企業名が見つからない場合に備えた例外処理の一部です。

company_name変数を出力すると、コンソールは以下のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3500912/9a8fd39d-19ff-880f-9c97-eeb0501650be.png)

__会社名がきちんと取得できているのが確認できたので、さっそく本題である電話番号検索に移ります!__

## 取得できた会社名一覧から電話番号を検索する
ここからが本題です、長らくお待たせしました。
Pythonのgooglemapsライブラリを利用して、取得した会社名のplace_idをplacesAPIを利用して取得します。
### PlacesAPIを叩いたresultを取得するコード
```python
import googlemaps
api_key = "your api key input here ><"
...割愛します...
    gmaps = googlemaps.Client(api_key)
    results = gmaps.places(company_name)
    print(results)
```
### result(コンソール)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3500912/67d3c667-eb14-80fb-849c-06d620e7048f.png)
resultからplace_idを取得できたので、じっさいにそのplace_idを利用してその場所の情報を検索するコードを書きます。
### place_idを叩くコード
```python
...割愛します...
    if len(results['results']) > 0:
        place_id = results['results'][0]['place_id']
        place_details = gmaps.place(place_id)
        print(place_detalils)
    else:
        phone_number = '電話番号が見つかりません'
```
>resultsの存在の有無について、存在しない場合は空の辞書が返ってくる仕様になっていることから、文字列が0より多いかどうかで判定しています。最後にdetailを出力します。

### place_idのdetail(コンソール)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3500912/22d297d0-70f7-2878-ca26-2cef350a23ba.png)
detailが多すぎるので、 __ctrl+F__ で「phone」という単語でフィルタリングします。
その結果'formatted_phone_number'に電話番号が記載されていることが分かったので、以下のコードで抽出します。いよいよ完成です！

### detailから電話番号を抽出
```python
...割愛します...
    if len(results['results']) > 0:
        place_id = results['results'][0]['place_id']
        place_details = gmaps.place(place_id)
        phone_number = place_details['result'].get('formatted_phone_number')
        phone_number = phone_number.strip()
    else:
        phone_number = '電話番号が見つかりません'
        
    print(phone_number)
```
>まず初めに、辞書ないからgetメソッドをつかって'formatted_phone_number'を抽出します。例外処理として、存在しない場合には'電話番号が見つかりません'に置き換えます。strip()も利用しています。

### 抽出した電話番号(上記のコードのコンソール)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3500912/99076dc1-121f-c23d-355e-6188cd4fe550.png)

これでこんかいの本題は終了しましたので、全体のコードを見せます！

# 全体のコード
```python
import requests
from bs4 import BeautifulSoup
import googlemaps
api_key = "your api key input here ><"
url = "https://jmty.jp/mie/rec-care"
response = requests.get(url=url)
soup = BeautifulSoup(response.content, "html.parser")

for job in soup.find_all("li", class_="p-articles-list-item"):
    job_url = job.a["href"]
    job_response = requests.get(job_url)
    job_soup = BeautifulSoup(job_response.content, "html.parser")
    main_table = job_soup.find('table', class_="unstriped p-article-column")

    company_name = next((row.find('td', class_="p-article-column-value").get_text(strip=True) for row in main_table.find_all('tr') if '社名/店名' in row.text), None)
    company_name = company_name if company_name else ""
    gmaps = googlemaps.Client(api_key)
    results = gmaps.places(company_name)
    if len(results['results']) > 0:
        place_id = results['results'][0]['place_id']
        place_details = gmaps.place(place_id)
        phone_number = place_details['result'].get('formatted_phone_number')
        phone_number = phone_number.strip()
    else:
        phone_number = '電話番号が見つかりません'

    print(phone_number)
```

# 終わりに
今回は簡単なAPIリファレンスでしたが、住所や店舗名から電話番号を取得するメソッドについては割りと需要があると思うので、参考になれば幸いです。
閲覧ありがとうございました。