Exporting your Tabelog 行ったお店 history
This is going to be a niche one, but maybe somebody will Google for this someday.
This morning, I figured out a relatively low-effort way to export my visited restaurants (行ったお店) in Tabelog and then decorate them with latitude and longitude as well as translations of each restaurant's name and summary.
There are basically three steps:
- Gather each page of your visited restaurants using JavaScript in the console
- Export them to a JSON file
- In a Ruby script, update the JSON for each restaurant, adding:
- Latitude and longitude
- English translations of its name and summary
Gathering the restaurants in JavaScript
I tried futzing with using a browser automation tool for this, but I kept running
into issues with how Tabelog's OAuth works, so just pasted this command twenty times
in the development console, once for each page (aggregating all my visited places
into a localStorage
property):
let summaries = JSON.parse(localStorage.getItem('tabelogSummaries') || '[]')
let mostRecentDate = null
summaries = summaries.concat(Array.from(document.querySelectorAll('.rvw-item--simple')).map(node => {
const date = node.querySelector('.p-preview-visit__visited-date')?.innerText.replace('訪問', '').replaceAll('/','-')
if (date) mostRecentDate = date
return {
title: node.querySelector('.simple-rvw__rst-name-target').innerText,
subtitle: node.querySelector('.simple-rvw__area-catg').innerText,
mapLink: node.querySelector('.simple-rvw__rst-name-target').href,
mapLinkType: 'tabelog',
score: node.querySelector('.p-preview-visit--score .c-rating-v2__val')?.innerText,
date: mostRecentDate,
lat: null,
lng: null
}
}))
localStorage.setItem('tabelogSummaries', JSON.stringify(summaries))
console.log(JSON.stringify(summaries))
After running this on the final page of my visited restaurants list, I copied
the last log output and saved it as tabelog_src.json
Enhancing the JSON with Ruby
Next, I ran this Ruby script to create tabelog_dest.json
:
require "uri"
require "cgi"
require "nokogiri"
require "net/http"
require "json"
items = JSON.load_file("tabelog_src.json", symbolize_names: true)
# item shape:
# {
# "placeTitle": "やきとりスタンド 京急川崎店",
# "placeSubtitle": "京急川崎、川崎/居酒屋、焼き鳥、ラーメン",
# "mapLink": "https://tabelog.com/kanagawa/A1405/A140501/14063800/",
# "mapLinkType": "tabelog",
# "score": "3.4",
# "date": "2023-05-22",
# "lat": null,
# "lng": null
# }
items.map.with_index do |item, i|
puts "Processing item #{i + 1}: #{item[:placeTitle]}..."
# Load the detail page and extract the map image URL so we can nab its lat/lng
url = URI.parse(item[:mapLink])
response = Net::HTTP.get(url)
document = Nokogiri::HTML(response)
map_url = URI.parse(document.css(".rstinfo-table__map-image").first["data-original"])
item[:lat], item[:lng] = CGI.parse(map_url.query)["center"].first.split(",")
# brew install translate-shell to get the `trans` command
item[:placeTitleAlt] = `trans -b -s ja #{item[:placeTitle].inspect}`.chomp
item[:placeSubtitleAlt] = `trans -b -s ja #{item[:placeSubtitle].inspect}`.chomp
end
# Output item shape:
# {
# "placeTitle": "やきとりスタンド 京急川崎店",
# "placeSubtitle": "京急川崎、川崎/居酒屋、焼き鳥、ラーメン",
# "mapLink": "https://tabelog.com/kanagawa/A1405/A140501/14063800/",
# "mapLinkType": "tabelog",
# "score": "3.4",
# "date": "2023-05-22",
# "lat": "35.532667702754814",
# "lng": "139.69926311341322",
# "placeTitleAlt": "Yakitori stand Keikyu Kawasaki store",
# "placeSubtitleAlt": "Keikyu Kawasaki, Kawasaki/Izakaya, Yakitori, Ramen"
# },
File.write("tabelog_dest.json", JSON.pretty_generate(items))
This is what the script does:
- Read the JSON file
- Loop through each item to visit its detail page
- Extract the restaurant's coordinates from a Google Maps embed URL
- Shell out to translate-shell to translate all the names and summaries
- Dump the updated JSON
Stay tuned
Of course, my purpose in doing all this is to seed my new 📍 Spots section of this here web site with some of my favorite restaurants in Japan. I always find little scraping projects like this to be a fun puzzle to solve, so I thought I'd share this one's "solution" with you all, especially if anyone else is looking to make a backup of their own reviews. 💜