เก็บข้อมูลจาก Bangkok Transit และเขียนฟังก์ชันง่ายๆ

TITIPATA bio photo

By TITIPATA

ชอบฟังเพลงอินดี้และอัลเทอร์เนทีฟ เวลาว่างชอบเขียนโปรแกรมและเล่นเกม

Email Twitter Google+ Github

Reading time ~25 minutes

TITIPATA bio photo

By TITIPATA

ชอบฟังเพลงอินดี้และอัลเทอร์เนทีฟ เวลาว่างชอบเขียนโปรแกรมและเล่นเกม

Email Twitter Google+ Github

จริงๆแล้วเราเป็นคนที่ใช้บริการขนส่งมวลชนมาตลอดเลยนะ ปกติแล้วก็ไม่ได้ขับรถอะไร เวลาเดินทางในกรุงเทพฯ จะไปหาที่จอดรถแต่ละที บางทีเดินหรือวิ่งเอาเร็วกว่าซะด้วยซ้ำ

พอพูดถึงเวลาจะเดินทางในกรุงเทพฯ สมัยนี้ทุกคนก็คงเลือกใช้ Google Maps กันหมดแล้ว แต่จริงๆแล้วรู้รึเปล่าว่าเราก็มีเว็บไซต์ขนส่งมวลชนเหมือนกัน ลองเข้าไปดูกันได้ที่ transitbangkok.com

ถ้าถามเราว่าทำไมเราต้องมีข้อมูลพวกนี้ด้วย แค่ใช้ Google ก็พอมั้ง ในส่วนตัวของเราคิดว่าการที่กรุงเทพฯมีข้อมูลพวกนี้อยู่กับตัวเอง ถือว่าเป็นเรื่องที่ดีมาก ลองคิดดูว่าถ้ากรุงเทพฯสามารถเก็บข้อมูลต่างๆที่เกี่ยวกับขนส่งมวลชนได้ด้วยตัวเอง ซึ่งไม่ใช่แค่เก็บว่าป้ายรถเมล์อยู่ที่ไหน หรือเดินทางจากที่นึงไปอีกที่นึงต้องไปยังไงบ้าง แต่มีขึ้นมูลอื่นๆที่เกี่ยวข้องกับการเดินทางด้วย เช่น คนเดินทางจากที่ไหนไปที่ไหนช่วงไหนบ้าง

ลองนึกดูว่าถ้ากรุงเทพฯ สามารถเก็บข้อมูลพวกนี้ได้ เค้าสามารถเอาข้อมูลมาวิเคราะห์​แล้วก็ออกแบบระบบขนส่งมวลชนที่ดีขึ้นได้ในอนาคต ถ้าเรามัวแต่พึ่ง Google Maps ก็เหมือนเราให้คนอื่นมองจากข้างนอก แต่เราไม่สามารถเข้าใจจังหวัดของเราเลย

เวิ่นไปซะเยอะ ซึ่งไม่น่าจะช่วยอะไรได้ เราลองมาดูภาพรวมก่อนว่าเราทำอะไรกับเว็บนี้ได้บ้าง

transitbangkok.com เป็นเว็บดีไซน์ใช้งานไม่ยากมาก เว็บนี้เก็บข้อมูลของป้ายรถเมล์และเส้นทางเดินรถสายต่างๆในกรุงเทพฯ นอกจากนั้นเราสามารถเสิร์ชหาเส้นการเดินทาง จากป้ายนึงไปอีกป้ายนึงได้ด้วย เช่น จากจุฬาฯไปสีลม เป็นต้น

ในโพสต์นี้ เราจะมาลองเก็บข้อมูลจากเว็บไซต์กัน โดยใช้ไลบรารี่ที่ชื่อว่า BeautifulSoup นอกจากนั้น เราจะเขียน python function เพื่อให้เรา ใส่ข้อมูลจุดตั้งต้นและปลายทางของการเดินทาง แล้วให้วิธีการเดินทางออกมาว่าต้องเดินทางไปยังไง

ใครที่อยากจะเข้าไปดูโค้ดเต็มๆก็เข้าไปดูได้ที่ github.com/titipata/bangkok_transit ขอบคุณ @bluenex และ @bachkukkik ที่ช่วยเช็คโค้ดด้วย นั่งเขียนกันตอนดึกมากๆนอกเวลางาน บางทีก็เบลอเขียนตัวแปรผิดๆถูกๆ

เก็บข้อมูล

เราเริ่มกันที่หน้า transitbangkok.com/bangkok_bus_routes.php ซึ่งเป็นหน้าที่เก็บข้อมูลของป้ายรถเมล์ต่างๆในกรุงเทพฯ หน้าที่ของเราคือเก็บลิงค์ของแต่ละป้ายรถเมล์มา จากนั้นใช้ลิงค์เข้าไปแต่ละเพจเพื่อเก็บว่ารถเมล์สายไหนผ่านบ้าง

หน้าตาขอโค้ดที่ใช้เก็บลิงค์เป็นประมาณนี้

import requests
from bs4 import BeautifulSoup

body = requests.get('http://www.transitbangkok.com/bangkok_bus_routes.php')
soup = BeautifulSoup(body.text, "lxml")
stations = []
for link in soup.find_all('a'):
    if '/stations/' in link.get('href'):
        stations.append(link.get('href'))
stations = list(set(stations))

ส่วนโค้ดที่ใช้เข้าไปเก็บข้อมูลแต่ละหน้า ลองดูได้ที่นี่

ใครที่ไม่อยากโหลดเอง เราได้เก็บข้อมูลของป้ายรถเมล์และสายรถเมล์ที่วิ่งผ่านไว้ใน CSV file แล้วที่นี่เลย

เสิร์ชป้ายใกล้เคียง

บางทีเวลาเสิร์ชชื่อป้ายรถเมล์​หรือจุดที่เราจะไป ถ้าใน Google เค้ามี auto-correction หรือแก้คำผิดให้ แต่สำหรับ Python นั้น มีไลบรารี่ที่ติดมาด้วยชื่อว่า difflib โดยใน difflib นี้มีฟังก์ช่ันติดมาด้วยที่ช่วยให้เราหาคำที่เขียนใกล้เคียงได้ชื่อว่า get_close_matches

อันนี้ไว้ใช้เวลา input ของเราเขียนเกือบถูกแล้ว แต่อาจจะมีเขียนผิดไปตัวนึง เราก็ยังแก้คำให้ไป ใกล้เคียงที่สุดกับสถานีที่เรามี

จากนั้นเราแค่เอาสถานีทั้งหมดมาต่อกัน (list1 + list2) แล้วก็ใช้ get_close_matches หาได้เลย

from difflib import get_close_matches

stations_english = [station['station_name'] for station in stations]
stations_thai = [station['station_thai_name'] for station in stations]
station_closest = get_close_matches(query , stations_thai + stations_english, n=1, cutoff=0.6)

ถ้าโหลด transit.py มา ข้างในนั้นจะมีฟังก์ชันชื่อ transit.query_station('บางรัก', stations) โดยฟังก์ชันนี้จะรีเทิร์นป้ายที่มีชื่อใกล้เคียงที่สุดกับที่เราใส่เข้าไป

วีธีการไปจากจุดเริ่มต้นถึงจุดสุดท้าย

transitbangkok.com มี query format หรือว่า พูดง่ายๆคือเราสามารถส่งป้ายสถานีไปบนเว็บไซต์แล้วมันจะให้วิธีการเดินทางกลับมา โดย query มีหน้าตาประมาณนี้ (station_start, station_end คือป้ายรถเมล์ภาษาอังกฤษตาม)

query_link = 'http://www.transitbangkok.com/showBestRoute.php?from=%s&to=%s&originSelected=false&destinationSelected=false&lang=en' \
            % (station_start['query'], station_end['query'])

%s ใน Python เป็นวิธีแทนสตริงเข้าไป เช่น "hello %s" % "world" = "hello world" เป็นต้น

ท้ายสุดแล้ว เราแค่ส่ง query ไปให้ที่เว็บไซต์แล้วเก็บข้อมูลมาเป็นอันจบ

route_request = requests.get(query_link)
soup_route = BeautifulSoup(route_request.content, 'lxml')
descriptions = soup_route.find('div', attrs={'id': 'routeDescription'})

route_descrtions = []
for description in descriptions.find_all('img'):
    action = description.next_sibling
    to_station = action.next_sibling
    n = action.find_next_siblings('a')
    if 'travel' in action.lower():
        lines = [to_station.find_next('b').text] +  [a.contents[0] for a in n]
    else:
        lines = []
    desp = {'action': action,
            'to': to_station.text,
            'lines': lines}
    route_descrtions.append(desp)

จริงๆแล้ว format ของเว็บไซต์นี้มันทำให้เราดึงข้อมูลออกมาลำบากกว่านี้เยอะ ลองไปดูโค้ดเต็มๆกันได้ เราแค่โชว์โค้ดส่วนที่ดูตรงไปตรงมา แต่จริงๆแล้วมันซับซ้อนกว่านี้เล็กน้อย

ถ้าเราจัดรูปแบบถูกต้อง หน้าตาของ output ที่ได้จะเป็นประมาณนี้

[{'action': 'Walk by foot to ',
  'lines': [],
  'to': 'Sanam Luang'},
 {'action': 'Travel to ',
  'lines': ['2', '15', '44', '47', '201', '203', '512'],
  'to': 'Khok Wua'},
 {'action': 'Walk by foot to ',
  'lines': [],
  'to': 'Democracy Monument'},
 {'action': 'Travel to ',
  'lines': ['59', '157', '159', '503', '509'],
  'to': 'Sanam Pao'}]

สำหรับคนที่ใช้ transit.py ก็เขียนแค่ข้างล่างได้เลย

transit.get_commute_instruction('ท่าพระจันทร์', 'สนามเป้า', stations)

อารัมภบท

ในบล้อกนี้เราได้พูดถึงเว็บไซต์ transit ของกรุงเทพฯ และเข้าไปดูว่ามี data อะไรที่เราดึงออกมาใช้ได้บ้าง

นอกจากนั้นเราก็เขียนฟังก์ชันในภาษา Python เพื่อหาวิธีการเดินทางมาดูได้โดยตรงจากเว็บไซต์

แต่พอเก็บข้อมูลมาทั้งหมดแล้ว ทำให้ตระหนักได้ว่า เห้ย! ทำไมกรุงเทพฯที่เป็นเมืองใหญ่ขนาดนี้ ซึ่งต้องมีระบบการคมนาคมที่ต้องใช้ครอบคลุมทั้งพื่นที่ แต่ข้อมูลที่ระบบการคมนาคมในกรุงเทพฯมีนั้นช่างน้อยนิด

น้อยนิดในที่นี้คือเรามีข้อมูลของรถเมล์เพียง 200 และป้ายรถเมล์เพียง 300 ป้าย

ถึงเวลาแล้วที่ระบบการคมนาคมควรเปลี่ยนแปลง (เว็บไซต์)?