Note: phiên bản Tiếng Việt của bài này ở link dưới.
https://duongnt.com/urchintai-api-vie
Perhaps most people who have tried to rent an apartment in Japan have heard about UR Chintai (UR賃貸住宅) with its many good perks like no key money, no guarantor needed, or deposit generally gets refunded. Recently, I realized that UR Chintai’s website is a dynamic one, and most of the contents in a page are loaded using JavaScript via API calls. What’s surprising to me is even though their API is public, there is scanty information about it on the Internet. The only mentions of it I can find is in this document on their homepage. However, by diving into their JavaScript files, I was able to learn quite a lot about that API.
Today, we will use their API to check the status of a property or a room. Then we will look at urchintai-client
, a small Python package I wrote to make querying the API easier. You can find the source code for urchintai-client
at the link below.
https://github.com/duongntbk/urchintai-client
We will use the following property URL and room URL in all of our examples. They do not have any special meaning, and I picked them randomly. Depending on when you read this article, that property and room may or may not be vacant, but that’s okay.
https://www.ur-net.go.jp/chintai/kanto/kanagawa/40_2600.html # <- This is our property URL
https://www.ur-net.go.jp/chintai/kanto/kanagawa/40_2600_room.html?JKSS=000000410 # <- And this is our room URL
Query information about a property
Diving in the code
The code to handle loading a property’s information is at this link. Keep in mind that if you open it using Chrome then the Japanese font will be messed up. You could still read the code itself without any problem, but I recommend using Firefox and setting the page encoding to Unicode for the best viewing experience.
We are interested in finding out if a particular property has any vacant room. So we need to look at the code to load the list of empty rooms in a property. That part starts from line 589.
return ur.api.ajax('bukken/detail/detail_bukken_room/', ajaxData)
.done(function (data, status, jqXHR) {
// bunch of code
}).fail(function() {
// bunch of code
});
We can guess that we need to query bukken/detail/detail_bukken_room/
endpoint. To find the API’s root path, we will check the ur.api.ajax
method, that method is defined in this file. From it, we can see that the API root is https://chintai.sumai.ur-net.go.jp/chintai/api/
, and because there was no HTTP method provided, POST
will be used. Next, we will find out what data we need to include in our request by looking at the ajaxData
object.
var ajaxData = ur.api.bukken_detail.setPostData();
The setPostData
method is defined at line 1124. We can see that they push a lot of data into ajaxData
, but actually we only need the following six fields: shisya
, danchi
, shikibetu
, orderByField
, orderBySort
and pageIndex
(people with keen eyes might even realize that they mistakenly push pageIndex
into ajaxData
twice). Furthermore, the value of orderByField
, orderBySort
and pageIndex
can all be set to 0
for our purpose, which leaves us with just three fields.
This is those three values are set.
ajaxData.push({name: 'shisya', value: ur.api.bukken_detail.param.shisya});
ajaxData.push({name: 'danchi', value: ur.api.bukken_detail.param.danchi});
ajaxData.push({ name: 'shikibetu', value: ur.api.bukken_detail.param.shikibetu });
ur.api.bukken_detail.param.XXX
, in turn, are initialized at line 260 ~ 264, inside the ur.api.bukken_detail.initSearch
method.
ur.api.bukken_detail.initSearch = function (shisya, danchi, shikibetu, life_designhouse, new_bukken_room) {
//...
// 支社
ur.api.bukken_detail.param.shisya = shisya;
// 団地
ur.api.bukken_detail.param.danchi = danchi;
// 識別
ur.api.bukken_detail.param.shikibetu = shikibetu;
//...
}
ur.api.bukken_detail.initSearch
is not called anywhere inside this JavaScript file. But if you download the page using curl
or a similar program with JavaScript turned off, you can find the following code.
<script type="text/JavaScript">
$(function () {
ur.cookie.setupBookmarkBukken();
ur.cookie.saveHistoryBukken('40_2600');
ur.api.bukken_detail.initSearch('40', '260', '0');
ur.api.bukken_bukken.initSearch('40', '260', '0');
$("a.td_underline_before:empty").parents(".cassettes_contact_box").remove();
$("span.item_tel_number:empty").parents("span.button_tel_purple").remove();
});
</script>
Remember that our property URL is https://www.ur-net.go.jp/chintai/kanto/kanagawa/40_2600.html
and suddenly the three numbers 40
, 260
and 0
become very familiar. We can then conclude that a property URL has this format: https://www.ur-net.go.jp/chintai/<area>/<prefecture>/AA_BBBC.html
.
- AA:
shisya
- BBB:
danchi
- C:
shikibetu
Trying out the API
Putting everything together, we can request the list of empty rooms in a property like this.
Method: POST
Endpoint: https://chintai.sumai.ur-net.go.jp/chintai/api/bukken/detail/detail_bukken_room/
Form data: {
'shisya': '40',
'danchi': '260'
'shikibetu': '0',
'orderByField': '0',
'orderBySort': '0',
'pageIndex': '0',
}
The response as of this writing is below.
[
{
"pageIndex": "0",
"rowMax": "5",
"rowMaxSp": "3",
"rowMaxNext": "10",
"pageMax": "5",
"allCount": "4",
"block": "kanto",
"tdfk": "kanagawa",
"shisya": "40",
"danchi": "260",
"shikibetu": "0",
"floorAll": "15階",
"roomDetailLink": "/chintai/kanto/kanagawa/40_2600_room.html?JKSS=000000404",
"roomDetailLinkSp": "/chintai/sp/kanto/kanagawa/40_2600_room.html?JKSS=000000404",
"system": [
{
"制度_IMG": "btn_kinkyo.png",
"制度名": "近居割",
"制度HTML": "kinkyo"
}
],
"parking": null,
"design": [
{
"デザイン_HTML": "renovation",
"デザイン_IMG": "logo_renovation.png",
"デザイン名": "リノベーション住宅"
},
{
"デザイン_HTML": "premium",
"デザイン_IMG": "logo_premium.png",
"デザイン名": "プレミアムなお部屋"
}
],
"featureParam": [],
"traffic": null,
"place": null,
"kanris": null,
"kouzou": null,
"soukosu": null,
"id": "000000404",
"year": null,
"name": "404号室",
"shikikin": "2か月",
"requirement": "ナシ",
"madori": "https://chintai.sumai.ur-net.go.jp/chintai/img_madori/40/40_260/40_260_0-00-0000_B5_RA_01_00011.gif",
"rent": "101,800円",
"rent_normal": "",
"rent_normal_css": " dn",
"commonfee": "4,100円",
"commonfee_sp": null,
"status": null,
"type": "2DK",
"floorspace": "45㎡",
"floor": "4階",
"urlDetail": null,
"urlDetail_sp": null,
"feature": null
},
{
<OMITTED>
},
{
<OMITTED>
},
{
<OMITTED>
}
]
This response contains a lot of information about each vacant room in this property. We can see there is a field called allCount
, its value is the number of vacant rooms (4 as of the time I ran this query). There is also information about rent, room number, floor space,… Next, we will try to call this endpoint for another property which has no vacant room.
https://www.ur-net.go.jp/chintai/kanto/kanagawa/40_3600.html
The result is this.
null
From this, we can see that checking if a property has vacant rooms is very simple, just query bukken/detail/detail_bukken_room/
and see if the response is null
or not.
Query information about a particular room
Diving in the code
The JavaScript code to handle loading a room’s information is at this link. The part we need to pay attention to starts at line 170.
ur.api.room_detail.getDataRoom = function () {
var ajaxData = [
{name: 'id', value: ur.api.room_detail.param.id},
{name: 'shisya', value: ur.api.room_detail.param.shisya},
{name: 'danchi', value: ur.api.room_detail.param.danchi},
{name: 'shikibetu', value: ur.api.room_detail.param.shikibetu },
{name: 'sp', value: (conf.isMobile()) ? '1' : '' }
];
ur.api.ajax('bukken/detail/detail_room/', ajaxData)
.done(function (data, status, jqXHR) {
// bunch of code
}).fail(function () {
// bunch of code
});
};
We can ignore the sp
parameter for now, because it only sets a flag to aid mobile/PC display. It’s easy to see that ur.api.room_detail.param.XXX
are initialized at line 144 ~ 159, inside the ur.api.room_detail.initSearch
method. We already know that shisya
, danchi
and shikibetu
are retrieved from the URL. And thanks to line 154, we can guess that id
is parameter JKSS
from the query string.
var id = ur.func.getParam('JKSS');
Trying out the API
Remember that our room URL is https://www.ur-net.go.jp/chintai/kanto/kanagawa/40_2600_room.html?JKSS=000000410
, we will query the API as below.
Method: POST
Endpoint: https://chintai.sumai.ur-net.go.jp/chintai/api/bukken/detail/detail_room/
Form data: {
'shisya': '40',
'danchi': '260'
'shikibetu': '0',
'id': '000000410'
}
The response as of this writing is below.
[
{
"roomCatch1": "",
"roomCatch2": "",
"roomRead1": "",
"roomRead2": "",
"roomNm": "410号室",
"rent_sp": "<span class=\"item_price\">135,600円</span><span class=\"item_commonfee\">(4,100円)</span>",
"madoriYuka": "2LDK /63㎡",
"madoriYuka_sp": "2LDK /63㎡",
"floor_sp": "4階 /15階",
"netLink": "https://sumai.ur-net.go.jp/chintai/s/otoiawase/juko.html?in=1040260000000410",
"kariLink": "",
"img": [
<LINK TO ROOM's IMAGES>
],
"movie": null,
"otherRoom": [],
"system": [
{
"制度_IMG": "btn_kinkyo.png",
"制度名": "近居割",
"制度HTML": "kinkyo"
}
],
"design": [
{
"デザイン_HTML": "renovation",
"デザイン_IMG": "logo_renovation.png",
"デザイン名": "リノベーション住宅"
},
{
"デザイン_HTML": "premium",
"デザイン_IMG": "logo_premium.png",
"デザイン名": "プレミアムなお部屋"
}
],
"bookmark_key": "40_2600000000410",
"parking": "<span>機械 空き台数:7台 料金:19,030円~21,120円<br></span><span class=\"item_text_parking-caution\">※ご契約時、駐車場敷金2か月が必要です。</span>",
"facility": "エレベーター、エアコン、ドロップインコンロ、オートドアロック、防犯カメラ、プレイロット、BS、VDSL、アルコーブ、バス・トイレ別、洗面所独立、追い焚き、洗濯機置場(室内)、玄関収納、バルコニー",
"biko": "<li>・2020年12月リノベーション済み(キッチン交換、洗面化粧台交換、床改修)</li>",
"bikoUrLight": "",
"featureParam": [],
"mihoshu": "",
"id": "000000410",
"year": "32",
"name": null,
"shikikin": "2か月",
"requirement": "ナシ",
"madori": null,
"rent": "<p class=\"price\">135,600円<span class=\"item_commonfee\">(4,100円)</span></p>",
"rent_normal": null,
"rent_normal_css": " dn",
"commonfee": null,
"commonfee_sp": null,
"status": null,
"type": null,
"floorspace": null,
"floor": "4階 /15階",
"urlDetail": null,
"urlDetail_sp": null,
"feature": "最寄りの小中学校が徒歩10分以内、敷地内に公園あり、最寄りの公園が徒歩5分以内"
}
]
What if we try to call the same endpoint for a non-vacant room, like this one?
https://www.ur-net.go.jp/chintai/kanto/kanagawa/40_2600_room.html?JKSS=000000411
The result is exactly what you would expect.
null
Thus checking if a room is vacant is also very simple, just query bukken/detail/detail_room/
and see if the response is null
or not.
A note about room ID
From the last section, we know that the ID for room number 410 is 000000410
. Because most UR Chintai property has more than nine floors but no property has more than 99 floors, we can reasonably expect that the last four digits in a room ID is the room number. But what about the leading six digits?
Let’s take a look at this property, it has three buildings, numbering 1
, 2
and 3
. The ID for room 204 in building 2 is 000020204
. It’s unlikely for a property to have more than 99 buildings, so I guess the format of a room ID is AAABBCCCC.
- AAA: I don’t know what this part means. For all rooms I can find, this part is
000
. - BB: building number, if the property has only one building then this part is
00
instead of01
. - CCCC: room number.
Quick look of some other endpoints
Method: POST
Endpoint: https://chintai.sumai.ur-net.go.jp/chintai/api/bukken/detail/detail_bukken_bukken/
Form data: {
'shisya': 'AA',
'danchi': 'BBB'
'shikibetu': 'C'
}
Returns the overview of a property, it has the following information.
- Number of parking slots in a property and the monthly-price of a slot.
- Surrounding area: kindergarten, library, public park,…
- Building facilities: elevator, CATV, auto lock,…
Method: POST
Endpoint: https://chintai.sumai.ur-net.go.jp/chintai/api/bukken/detail/detail_bukken/
Form data: {
'shisya': 'AA',
'danchi': 'BBB'
'shikibetu': 'C'
}
Returns pictures and videos of a property and its surrounding area. Each picture has two versions, a normal one and a small thumbnail.
Method: POST
Endpoint: https://chintai.sumai.ur-net.go.jp/chintai/api/bukken/detail/detail_bukken_design/
Form data: {
'bukkenid': 'AA_BBB' # For our example, the bukkenid is 40_260. Don't know why this one is different from the rest
}
Returns the following information about a property.
- Address.
- The nearest train station.
- Total number of rooms.
- The year when UR Chintai started managing this property.
- Type of building (concrete, wood,…).
Method: POST
Endpoint: https://chintai.sumai.ur-net.go.jp/chintai/api/bukken/detail/detail_bukken_tenpo/
Form data: {
'shisya': 'AA',
'danchi': 'BBB'
'shikibetu': 'C'
}
Returns information about the branch that manages a property. It has the phone number, address, holiday, open time,… of that branch. This information will come in handy when you want to apply for a room in that property.
Method: POST
Endpoint: https://chintai.sumai.ur-net.go.jp/chintai/api/bukken/detail/bukken_main/
Form data: {
'shisya': 'AA',
'danchi': 'BBB'
'shikibetu': 'C'
}
This endpoint seems to be a simplified version of detail_bukken_bukken
. They return mostly the same information but bukken/search/bukken_main
is limited to the subset of vacant room(s).
Introducing urchintai-client
Remembering what endpoint to call with what data can get tiring quickly. Because of that, I wrote a small Python package called urchintai-client to make querying UR Chintai API easier. You can read more about it on GitHub.
https://github.com/duongntbk/urchintai-client
Here, I will only introduce one use case, checking if a property has any vacant room using its URL. Assuming that you’ve already installed urchintai-client
, run the following script in Python terminal.
import asyncio
from urchintai_client.session_manager import SessionManager
from urchintai_client.request_sender import RequestSender
from urchintai_client.ur_client import UrClient
sender = RequestSender(SessionManager.GetSession())
client = UrClient(sender)
url = 'https://www.ur-net.go.jp/chintai/kanto/kanagawa/40_2600.html'
loop = asyncio.get_event_loop()
is_vacant = loop.run_until_complete(client.is_property_vacant(url))
print(f'Property has vacant room(s): {is_vacant}')
loop.run_until_complete(SessionManager.CloseSession()) # Don't forgot to close the session
At the time of this writing, the script above prints the following message to console.
Property has vacant room(s): True
Conclusion
Armed with the knowledge about UR Chintai API, we could easily add more functionalities to urchintai-client
. With the correct combination of calls, it is possible to programmatically retrieve any information you want from their system. Maybe we can use this to create a bot to periodically check the status of a property or a room and send notification when a new room becomes available.
One Thought on “Use API to query information from UR Chintai”