roberthsu2003 / __2024_05_05_sunday__

AI 人工智慧開發入門_python
29 stars 2 forks source link

請下載台北市youbike及時資料(json),解析資料! #17

Open roberthsu2003 opened 1 month ago

roberthsu2003 commented 1 month ago

請幫我查出目前可借車輛數為3輛以內的站點

請幫我查出目前可還車輛數為3輛以內的站點

請將維護的站點移除

youbike = 'https://tcgbusfs.blob.core.windows.net/dotapp/youbike/v2/youbike_immediate.json'
截圖 2024-06-09 下午4 34 06
jonathan-sean commented 1 month ago

Python code:

# 下載台北市youbike及時資料(json),解析資料
#  - URL: https://tcgbusfs.blob.core.windows.net/dotapp/youbike/v2/youbike_immediate.json
#  - 查出目前可借車輛數為3輛以內的站點
#  - 查出目前可還車輛數為3輛以內的站點
#  - 將維護的站點移除

import traceback
import json
import requests
from requests import Response
from pprint import pprint
from pydantic import (
    BaseModel,
    RootModel,
    Field,
    ValidationError,
    field_validator
)
import pyinputplus as pyip
from random import choices

# Inherited from PyDantic BaseModel
class UBike(BaseModel):
    act:bool
    mday:str
    sarea:str
    sna:str
    ar:str
    latitude:float
    longitude:float
    available_rent_bikes:int
    available_return_bikes:int
    total:int

# Inherited from PyDantic RootModel
class UBikeRoot(RootModel):
    root:list[UBike]

# Return True if each pattern matched
def _search_bike_any(item:dict, patterns:list[dict]) -> bool:
    for (k, v) in patterns.items():
        if item[k] > 0 and item[k] <= v:
            return True
    return False

# Return True if all patterns matched
def _search_bike_all(item:dict, patterns:list[dict]) -> bool:
    for (k, v) in patterns.items():
        if item[k] <= 0 or item[k] > v:
            return False
    return True

def _search_bike(dlist:list[dict], key:str, val_min:float=1, val_max:float=1, sort:bool=False, sort_key:str='mday', reverse=True):
    _dlst:list[dict] = list(filter(lambda item:item[key] >= val_min and item[key] <= val_max, dlist))
    if sort:
        _dlst = sorted(_dlst, key=lambda item: item[sort_key], reverse=reverse)
    return _dlst

def _display_sites_random(dlist:list[dict], sort:bool=True, sort_key:str='mday', reverse=True):
    max:int = len(dlist)
    if max == 0:
        return None
    try:
        n:int = pyip.inputInt(f"請輸入要隨機顯示的站點(1~{max}): ", min=1, max=max)
        dlst_random:list[dict] = choices(dlist, k=n)
        if sort:
            dlst_random = sorted(dlst_random, key=lambda item: item[sort_key], reverse=reverse)
        i:int = 0
        for d in list(dlst_random):
            i += 1
            print(f"第 {i} 筆")
            for (k, v) in d.items():
                print(f"\t{k}: {v}")
    except Exception as e:
        raise e

def main():
    title:str = "臺北市 U-Bike 即時資訊"
    try:
        ubike_url:str = "https://tcgbusfs.blob.core.windows.net/dotapp/youbike/v2/youbike_immediate.json"
        resp:Response = requests.get(ubike_url)
        if not resp.ok:
            print(f"ERROR: 下載{title}失敗")
            return

        # This JSON include integer and float, but python json module cannot parse these data
        # How to correct these ?
        # Load generic text and call model_validate() to get data in required fields
        jaon_raw:UBikeRoot= UBikeRoot.model_validate(json.loads(resp.text))
        # convert UBikeRoot to dictionary list by model_dump()
        ubike_full:list[dict] = jaon_raw.model_dump()
        print(f"{title}:")
        print(f"全部有 {len(ubike_full)} 個 U-Bike 站點")

        # filter data
        #  1.Search for active sites
        act:bool = True
        ubike_act:list[dict] = list(filter(lambda item:item['act'] == act, ubike_full))

        patterns:dict[str: int] = { "available_rent_bikes": 3, "available_return_bikes": 3 }
        display_mode:int = 1    # default display or condition
        if display_mode == 1:
            #  2. Search for bikes to rent
            key:str = "available_rent_bikes"
            ubike_lst:list[dict] = _search_bike(ubike_act, key, val_max=patterns[key])
            print(str.format("\n營運中且可借車輛數在 {} 輛(含)以內的有站點 {} 個", patterns[key], len(ubike_lst)))
            _display_sites_random(ubike_lst)

            #  3. Search for bikes to return
            key = "available_return_bikes"
            ubike_lst:list[dict] = _search_bike(ubike_act, key, val_max=patterns[key])
            print(str.format("\n營運中且可還車輛數在 {} 輛(含)以內的站點有 {} 個", patterns[key], len(ubike_lst)))
            _display_sites_random(ubike_lst)
        else:
            #  2. Search available rental and return bikes using or criteria
            # For my practice
            # Try to use a dictionary to store search criteria
            # For functions with more parameters, use the special lambda function approach
            ubike_lst:list[dict] = list(filter(lambda item:_search_bike_any(item, patterns), ubike_act))
            print("\n搜尋")
            print(str.format("\t- {}", '營運中' if act else '休息中'))
            print(str.format("\t- 可借車輛數: {} 輛(含)以內", patterns['available_rent_bikes']))
            print(str.format("\t- 可還車輛數: {} 輛(含)以內", patterns['available_return_bikes']))
            cnt:int = len(ubike_lst)
            print(f"\t共有 {cnt} 個符合條件的站點")
            _display_sites_random(ubike_lst)
    except Exception as e:
        print(f"EXCEPTION: {e}")
        traceback.print_exc()

if '__main__' == __name__:
    main()

Result:

臺北市 U-Bike 即時資訊:
全部有 1420 個 U-Bike 站點

營運中且可借車輛數在 3 輛(含)以內的有站點 276 個
請輸入要隨機顯示的站點(1~276): 3
第 1 筆
    act: True
    mday: 2024-06-13 15:01:22
    sarea: 中山區
    sna: YouBike2.0_長春路137巷口
    ar: 民生東路二段134號前
    latitude: 25.05791
    longitude: 121.53114
    available_rent_bikes: 3
    available_return_bikes: 20
    total: 23
第 2 筆
    act: True
    mday: 2024-06-13 14:58:12
    sarea: 士林區
    sna: YouBike2.0_社子市場
    ar: 延平北路六段67號旁
    latitude: 25.0881
    longitude: 121.50873
    available_rent_bikes: 1
    available_return_bikes: 10
    total: 15
第 3 筆
    act: True
    mday: 2024-06-13 14:46:20
    sarea: 南港區
    sna: YouBike2.0_力行橋(南港)
    ar: 研究院路一段101巷16弄2號南側
    latitude: 25.05172
    longitude: 121.61686
    available_rent_bikes: 3
    available_return_bikes: 15
    total: 18

營運中且可還車輛數在 3 輛(含)以內的站點有 108 個
請輸入要隨機顯示的站點(1~108): 3
第 1 筆
    act: True
    mday: 2024-06-13 15:01:23
    sarea: 中正區
    sna: YouBike2.0_中山徐州路口
    ar: 中山南路/徐州路(東南側)
    latitude: 25.04178
    longitude: 121.51907
    available_rent_bikes: 13
    available_return_bikes: 1
    total: 26
第 2 筆
    act: True
    mday: 2024-06-13 15:01:17
    sarea: 中正區
    sna: YouBike2.0_法務部
    ar: 重慶南路一段130號旁
    latitude: 25.03705
    longitude: 121.51249
    available_rent_bikes: 20
    available_return_bikes: 1
    total: 27
第 3 筆
    act: True
    mday: 2024-06-13 14:53:19
    sarea: 松山區
    sna: YouBike2.0_光復南路46巷
    ar: 光復南路46巷10號東側
    latitude: 25.04606
    longitude: 121.55665
    available_rent_bikes: 13
    available_return_bikes: 3
    total: 16
charlywang11 commented 1 month ago

請下載台北市youbike及時資料(json),解析資料!

請幫我查出目前可借車輛數為3輛以內的站點 請幫我查出目前可還車輛數為3輛以內的站點 請將維護的站點移除

import requests
import pyinputplus as pyip
from pprint import pprint
from requests import Response
from pydantic import BaseModel,RootModel,Field,ValidationError,field_validator
from random import choices

class UB(BaseModel):
    場站中文名稱:str = Field(alias='sna')
    場站區域:str = Field(alias='sarea')
    資料更新時間:str = Field(alias='mday')
    地點:str = Field(alias='ar')
    act:bool
    場站總停車格:int = Field(alias='total')
    場站目前車輛數量:int = Field(alias='available_rent_bikes')
    空位數量:int = Field(alias='available_return_bikes')
    緯度:float = Field(alias='latitude')
    經度:float = Field(alias='longitude')

class Root(RootModel):
    root:list[UB]

def main():
    youbike_url = 'https://tcgbusfs.blob.core.windows.net/dotapp/youbike/v2/youbike_immediate.json'
    res:Response = requests.get(youbike_url)
    all_data = res.json()

    try:
        root:Root = Root.model_validate(all_data)
    except ValidationError as error:
        print(error)

    data_list:list[dict] = root.model_dump()
    filter_list:list[dict] = list(filter(lambda item:False if item['act']==0 else True,data_list))
    filter_list_rent_less3:list[dict] = list(filter(lambda item:True if item['場站目前車輛數量']<3 else False,data_list))
    filter_list_return_less3:list[dict] = list(filter(lambda item:True if item['空位數量']<3 else False,data_list))

    print(f"台北市YouBike有{len(data_list)}站點,目前正常運作站點共{len(filter_list)}個")

    num = pyip.inputInt("請輸入隨機顯示的站點數(1~5): ", min=1, max=5)
    print(num)

    print(f"\n可借車輛數為3輛以內的站點有{len(filter_list_rent_less3)}站")
    num_list:list[dict] = choices(filter_list_rent_less3, k=num)
    for sta in num_list:
            seq = filter_list_rent_less3.index(sta)
            print(f"No.{seq}")
            pprint(sta, indent=2, sort_dicts=False)

    print(f"\n可還車輛數為3輛以內的站點有{len(filter_list_return_less3)}站")
    num_list:list[dict] = choices(filter_list_return_less3, k=num)
    for sta in num_list:
            seq = filter_list_return_less3.index(sta)
            print(f"No.{seq}")
            pprint(sta, indent=2, sort_dicts=False)

if __name__ == '__main__':
     main()

run:

台北市YouBike有1420站點,目前正常運作站點共1411個
請輸入隨機顯示的站點數(1~5): 2

可借車輛數為3輛以內的站點有383站
No.123
{ '場站中文名稱': 'YouBike2.0_景興路102巷口',
  '場站區域': '文山區',
  '資料更新時間': '2024-06-13 08:28:14',
  '地點': '景華街52巷/景興路102巷',
  'act': True,
  '場站總停車格': 14,
  '場站目前車輛數量': 0,
  '空位數量': 14,
  '緯度': 24.99438,
  '經度': 121.54376}
No.326
{ '場站中文名稱': 'YouBike2.0_虎林永吉路口',
  '場站區域': '信義區',
  '資料更新時間': '2024-06-13 09:21:22',
  '地點': '永吉路356號東側',
  'act': True,
  '場站總停車格': 15,
  '場站目前車輛數量': 1,
  '空位數量': 13,
  '緯度': 25.04519,
  '經度': 121.57712}

可還車輛數為3輛以內的站點有156站
No.3
{ '場站中文名稱': 'YouBike2.0_臺大男七舍前',
  '場站區域': '大安區',
  '資料更新時間': '2024-06-13 09:19:19',
  '地點': '長興街/長興街80巷口西側',
  'act': True,
  '場站總停車格': 20,
  '場站目前車輛數量': 18,
  '空位數量': 2,
  '緯度': 25.01537,
  '經度': 121.54698}
No.93
{ '場站中文名稱': 'YouBike2.0_康寧路三段99巷17弄口',
  '場站區域': '內湖區',
  '資料更新時間': '2024-06-13 09:09:20',
  '地點': '康寧路三段99巷19號對側',
  'act': True,
  '場站總停車格': 15,
  '場站目前車輛數量': 13,
  '空位數量': 2,
  '緯度': 25.0721,
  '經度': 121.60991}
jonathan-sean commented 1 month ago

@roberthsu2003

請幫我查出目前可借車輛數為3輛以內的站點

請幫我查出目前可還車輛數為3輛以內的站點

請將維護的站點移除

youbike = 'https://tcgbusfs.blob.core.windows.net/dotapp/youbike/v2/youbike_immediate.json'
截圖 2024-06-09 下午4 34 06

請問查詢腳踏車數量的這二個條件是 and 還是 or?又或是分為二筆查詢結果?

roberthsu2003 commented 1 month ago

@roberthsu2003

請幫我查出目前可借車輛數為3輛以內的站點

請幫我查出目前可還車輛數為3輛以內的站點

請將維護的站點移除

youbike = 'https://tcgbusfs.blob.core.windows.net/dotapp/youbike/v2/youbike_immediate.json'
截圖 2024-06-09 下午4 34 06

請問查詢腳踏車數量的這二個條件是 and 還是 or?又或是分為二筆查詢結果?

沒有限制喔

jonathan-sean commented 1 month ago

@roberthsu2003

請幫我查出目前可借車輛數為3輛以內的站點

請幫我查出目前可還車輛數為3輛以內的站點

請將維護的站點移除

youbike = 'https://tcgbusfs.blob.core.windows.net/dotapp/youbike/v2/youbike_immediate.json'
截圖 2024-06-09 下午4 34 06

請問查詢腳踏車數量的這二個條件是 and 還是 or?又或是分為二筆查詢結果?

沒有限制喔

瞭解