A story that a Ruby beginner made and released a LINE BOT that tells the train time in 2 months

Change log

September 10, 2020 Corrected title September 10, 2020 Comments and corrections September 9, 2020 First published in this article

Introduction

We have developed a LINE bot called "Tell me Ayase". There are still many unfinished parts, but since we have finished developing the main functions, we decided to publish them on GitHub and Qiita. In this article, we will explain the functions and technical aspects.

Click here to add friends Add friend

GitHub repository

https://github.com/Aseiide/ayase_bot

Tell me Ayase, what is you?

demo.gif

--Can be used on the Tokyo Metro Chiyoda Line --You can get the time of the train bound for Ayase by sending [Current station] on the Chiyoda line.

Development history

千代田線.png

The university where my home is attending is also along the Chiyoda Line. Since the Chiyoda Line is on the JR Joban Line, the descent is connected to Matsudo, Kashiwa, Toride, etc., so it is quite crowded in the evening. On the other hand, the trains bound for Ayase and Kita-ayase have short destinations and the probability of being crowded is very low, so I tried to take them here. It was troublesome to search for the time with Yahoo's transfer app and check the time, so I decided to work on the development of LINE Bot.

Technical explanation

Technical composition

ayasebot-sequence.png

API you are using

LINE Messaging API

https://github.com/line/line-bot-sdk-ruby I had made a bot for Echolalia, so I proceeded with the production while referring to the SDK and documents.

Ekispert Web Service (Free Plan)

Select this API that can be used individually and for free. In the free plan, it is not possible to simply get the time, so scraping is performed on the url returned by hitting the API to get the time.

Code commentary

Convert station name to station code

station_code = {
  :Yoyogi Uehara=> "23044",
  :Yoyogi park=> "23045",
  :In front of Meiji Jingu=> "23016",
  :Omotesando=> "22588",
  :Nogizaka=> "22893",
  :Akasaka=> "22485",
  :Houses of Parliament=> "22668",
  :Kasumigaseki=> "22596",
  :Hibiya=> "22951",
  :In front of Nijubashimae=> "22883",
  :Otemachi=> "22564",
  :Shin-ochanomizu=> "22732",
  :Yushima=> "23038",
  :Nezu=> "22888",
  :Sendagi=> "22782",
  :Nishinippori=> "22880",
  :Machiya=> "22978",
  :Kitasenju=> "22630",
  :Ayase=> "22499",
  :Kita Ayase=> "22627"
  }

When hitting the API, the station entered in Japanese by the user is converted to the station code. As a result of various trials, I passed it as a symbol and converted it to a station code of a character string.

Receive the transmitted station name as a variable

@station_name = event.message["text"]

Since it was necessary to store it in a variable in LINE, it is stored in a variable in this way of writing. At the beginning of development, it didn't work at all with `` `station_name = gets.chomp``` etc.

Fix the arrival station to Ayase and throw a request

res1 = Net::HTTP.get(URI.parse("http://api.ekispert.jp/v1/json/search/course/light?key=#{ENV['ACCESS_KEY']}&from=#{station_code[@station_name.to_sym]}&to=22499"))

Convert the station name received by station_name to a symbol I am hitting the API by expanding the symbol into variables.

Store the JSON returned by hitting in hash

hash = JSON.parse(res1)
url = hash["ResultSet"]["ResourceURI"]

When you hit the API

"ResultSet":~~
"ResourceURI":~~

Since it is returned in the form of, it is stored in a variable called url using a hash.

Store the scraped text in a variable

Before correction


doc = Nokogiri::HTML.parse(html, nil, charset)
doc.xpath('/html/body/div[1]/div[4]/div/div[1]/div[2]/div/table/tr[1]/td[3]/p[1]').each do |node|
$time = node.inner_text
end

Revised


time = nil
doc.xpath('/html/body/div[1]/div[4]/div/div[1]/div[2]/div/table/tr[1]/td[3]/p[1]').each do |node|
time = node.inner_text
end

Even if I copy and paste the Xpath obtained by the developer tool of chrome, it does not work ,. After all, removing the tbody tag that was originally included worked fine. Since time is used outside the ~~ block, it is stored as a global variable. (** Verify if instance variables work well **) ~~ Modified the code to narrow the scope of $ time.

Difficulties

What I did alone for the first time from conception to development

Until now, I had been developing according to some tutorial, so it was my first time to proceed with development while researching from scratch. While searching for words that I didn't understand, I proceeded while learning from an engineer I knew what I didn't understand in the implementation part. I feel that I have learned basic parts that are difficult to pick up in books and online, such as how to communicate in text and how to ask questions.

Development based on Pull Request

No matter how much I did the tutorial, I found it very difficult to understand git. Until now, I had only the experience of pushing the developed ones to GitHub, so it was very nice to have the experience of proceeding with development while cutting branches.

Processing to receive what was sent in the LINE message as a variable

I had a hard time storing the station name sent by the user in a variable, which I mentioned in the code explanation. It's very simple to look at the code, but I couldn't find it in the documentation and it took me a long time to find this way of writing. In the end, I found a similar implementation from the article published on Qiita and arrived at it.

About sinatra specifications

In the code

post '/callback' do
end

There is a block called. There were times when it didn't work because I didn't know that it was ** executed every time ** during this block. (I haven't found the source yet) The scraping part had to be done every time. I learned about the implementation here from the Ruby community (Nishi-nippori.rb, Fukuoka.rb), and it works fine.

Impressions

It's less than 100 lines of code, but I'm very happy to be able to actually move what I wanted to make! I feel that I haven't studied enough yet, but I think it was a good learning experience.

Features to be implemented

--Send a list of "stations that can be sent" when registering as a friend --Display of error message when a station other than the Chiyoda Line is sent

reference

In writing this commentary article, I referred to the following article https://qiita.com/shinbunbun_/items/00c4064c8133a34cf7c3 https://qiita.com/inoue2002/items/7e47283ba9affa0fac82

Recommended Posts

A story that a Ruby beginner made and released a LINE BOT that tells the train time in 2 months
The story that docker had a hard time
A story about a super beginner participating in the AtCoder contest for the first time (AtCoder Beginner Contest 140)
Determine that the value is a multiple of 〇 in Ruby
[Learning record] I got the current time in Ruby and output a different greeting for each time.
I made a Ruby container image and moved the Lambda function
The story that Tomcat suffered from a timeout error in Eclipse
How to operate IGV using socket communication, and the story of making a Ruby Gem using that method
The story of forgetting to close a file in Java and failing
Draw a bar graph and a line graph at the same time with MPAndroidChart
A story about an arithmetic overflow that you shouldn't encounter in Ruby
After verifying the Monty Hall problem with Ruby, a story that I could understand well and did not understand well