GBFSのデータを使って、新しくできたシェアモビリティのステーション情報をXに自動ポストするよ。





:::note warn
注意
ほぼ実装できているのですが、少し上手く行かないところがあるので、
ひとまずできているところまで、記載したいと思います。
:::

:::note info
この記事は [シェアモビリティの標準的なデータフォーマット GBFS Advent Calendar 2023](https://qiita.com/advent-calendar/2023/gbfs) 14日目の記事です。
:::

# 課題

シェアモビリティのステーションは、日々増加しておりキャッチアップするのが大変。
気が付かないうちに、ステーションが新しくできていたといったことがある。

# やりたいこと

シェアモビリティデータの定時取得と新設ステーションを特定。そしてXに自動ポストする。

こちらのXのアカウントでツイートする予定です。

https://twitter.com/cycle_station_i

:::note info
インフォメーション

XはBotの一掃を掲げていますが、きちんと申告すれば大丈夫なようで、このアカウントも「自動アカウント」である申告を行いました。
:::
![08D7DFB1-AEDC-4FFA-88FE-2C8C4DADDF12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274029/4d203bf8-a969-f74b-6227-8144435464fd.png)

![252D8E20-48D5-400D-A4EC-B85CEA3354E9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274029/540f2300-a8ae-9c2d-5b28-29e9ddf8dfba.png)

# 環境
AWS S3, Lambda

# 言語
Python 3.9

# 使用するデータ

データについてはこちら↓

https://qiita.com/kumatira/items/f9229c21d9f0db3b5ae3

GBFSを公開した際の背景や想いなどはこちら↓

https://note.com/openstreet/n/n2f4b51cd52b3

## 各事業者のGBFSのURLはこちら
 - [HELLO CYCLING の GBFS](https://ckan.odpt.org/dataset/c_bikeshare_gbfs-openstreet)
 - [ドコモ・バイクシェア の GBFS](https://ckan.odpt.org/dataset/c_bikeshare_gbfs-d-nationwide-bikeshare)

# Stepを整理
 - シェアモビリティデータの定時取得
 - 新設ステーションの特定
 - Xに自動ポスト

それではやっていきましょう。

## シェアモビリティデータの定時取得

まずは、一日一回、ステーションのデータを取得し、蓄積していきます。

条件
 - 毎朝6時をトリガーにLambdaのプログラムを実行
 - 取得したデータをS3のフォルダに格納
```py:getgbfs.py
import json
import http.client
from urllib.parse import urlparse
import boto3
import datetime

def lambda_handler(event, context):

    # URLからデータを取得
    url = "https://api-public.odpt.org/api/v4/gbfs/hellocycling/station_information.json"
    parsed_url = urlparse(url)
    conn = http.client.HTTPSConnection(parsed_url.netloc)
    conn.request("GET", parsed_url.path)
    response = conn.getresponse()
    data = response.read()
    conn.close()

    # JSONデータの読み込み
    data_json = json.loads(data)

    # 'data' キーの中身を展開
    data_items = data_json['data']['stations']

    # CSV形式の文字列に変換
    csv_str = "station_id, name, lat, lon\n"
    for item in data_items:
        csv_str += f"{item['station_id']}, {item['name']}, {item['lat']}, {item['lon']}\n"

    # S3にアップロード
    bucket_name = 'gbfsdata'
    t_delta = datetime.timedelta(hours=9)
    JST = datetime.timezone(t_delta, 'JST')
    now = datetime.datetime.now(JST)
    file_name = f"hello-cycling/station-information/{now.strftime('%Y%m%d_%H%M')}.csv"

    s3 = boto3.resource('s3')
    s3.Bucket(bucket_name).put_object(Key=file_name, Body=csv_str, ContentType='text/csv')

    return {"status": "Success"}

```

## 新設ステーションの特定

前日のデータと、当日のデータを突き合わせて、
station の id に差分があるところがステーションの増加 or 減少があったところと考えます。
今回は、新設のステーションをツイートしたいので、「前日までなかったが、当日のデータにはあるステーション」を抽出します。

```py:new_station.py

```

## Xに自動ポスト

特定したステーションの情報をXに投稿します。

:::note warn
注意
Lambda上での自動投稿に少し躓いているので、ローカルでの処理について記載します。
:::

```py:auto_tweet.py

```

### エラー対処

>Response
{
  "errorMessage": "Unable to import module 'lambda_function': cannot import name 'DEFAULT_CIPHERS' from 'urllib3.util.ssl_' (/opt/python/urllib3/util/ssl_.py)",
  "errorType": "Runtime.ImportModuleError",
  "requestId": "xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxx",
  "stackTrace": []
}

原因は「urllib3」が、つい2週間前(2023年6月前半)にLatestが、
1系から2系になったことによるものらしい。
https://qiita.com/maechi/items/6d5107bc526784a026b3



# 参考にしたブログ

https://twinkangaroos.com/how-to-use-aws-lambda-for-periodic-scraping-3.html


https://repost.aws/ja/knowledge-center/lambda-import-module-error-python


https://soypocket.com/it/aws-lambda-python-error-no-module-named/


https://note.com/omiotuke240/n/n1173339bffc9

https://dev.classmethod.jp/articles/fix-lambda-error-no-module-named-lambda_function/


https://scr.marketing-wizard.biz/dev/tweepy-twitter-apiv2

https://poota.net/archives/414

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/packaging-layers.html

https://www.distant-view.co.jp/column/6513/