编码我进入魔术王国
#python #自动化 #googlecloud #twilio

最初发布在我的personal site

在2022年4月,我们首次将家人带到迪士尼世界。我们很兴奋,孩子们很兴奋,一切都在抬头。我预订了住宿,机票和一辆租赁车辆,计划了6个月的所有内容。除了迪士尼世界门票以外的一切。我的想法是,在不太可能发生销售的情况下,我可以节省一些来之不易的现金。

我觉得我已经弄清楚了一切。

我是最聪明的人,因为我想到了一切。

我不知道的是新的``公园预订系统''。

预订系统

如果我做了更多的研究,我会发现从2020年开始,作为对大流行的回应,迪士尼为他们的公园建立了预订系统。这意味着他们现在每天都会限制每个公园中的人数。购买门票时,您还必须在要去的公园里保留自己的位置。这使他们可以保留公园的数字,并且可能还会使管理人员等其他事情变得更加容易。

所以,当我去买我们的门票时,我感到惊讶和失望地发现,唯一的公园在我们预定的两天内没有完全预订,这是Epcot。

EPCOT - Photo by Robert Horvick on Unsplash

不要误会我的意思,epcot真是太酷了!那里有很多很棒的东西,但是我知道我们的4个小孩(和我们两个父母)将无法看到魔术王国的城堡和其他凉爽的部分感到失望。在与我的耐心和宽容的伴侣谈论它之后,我们决定顺其自然,并在Epcot做2天。

但我不满意。我需要纠正我的错误。我开始怀疑我是否可以利用自己的技能将我们带入魔术王国。

思考

迪士尼有一个page on their site that shows the reservation availability,我用来发现只有Epcot可用。当我打电话与代表购买门票交谈时,他们提到有时人们会取消,您可以抓住该预订。我问这频率发生多久,他们告诉我这很少见,但是如果您观看该预订可用性页面,您可能会很幸运。

The reservation availability system

从我们迪士尼世界访问开始前的两个星期开始,我几乎每天都会检查此页面。这成为一项无所不在的任务。我真的很想在别人抓住它之前拿起取消的预订。那是我决定自动化流程的时候。

有些侦察的时间

查看日历,我意识到,当我单击下个月时,它可能正在从他们的服务器中获取数据以显示可用的内容。检查检查器工具中的网络选项卡已确认。

响应是一个带有所有日期的JSON对象,对于每个日期,公园都有可用的预订。查看用于获取此数据的URL,我注意到它有非常简单的论点。

https://disneyworld.disney.go.com/availability-calendar/api/calendar?segment=tickets&startDate=2022-05-01&endDate=2022-05-31

  • segment-可以是ticketresortpassholder。我们希望ticket获取票务数据。
  • startDate-您想要的数据范围的开始日期。
  • endDate-您想要的数据范围的结束日期。

简单!

因此,如果我们想查看5月第三周(15至21日)可能可用的东西,我们可以使用此URL:

https://disneyworld.disney.go.com/availability-calendar/api/calendar?segment=tickets&startDate=2022-05-15&endDate=2022-05-21

我们得到以下数据:

[
  {
    "date": "2022-05-15",
    "availability": "full",
    "parks": [
      "80007944",
      "80007823",
      "80007998",
      "80007838"
    ]
  },
  {
    "date": "2022-05-16",
    "availability": "partial",
    "parks": [
      "80007823"
    ]
  },
  {
    "date": "2022-05-17",
    "availability": "partial",
    "parks": [
      "80007823",
      "80007838"
    ]
  },
  {
    "date": "2022-05-18",
    "availability": "partial",
    "parks": [
      "80007823"
    ]
  },
  {
    "date": "2022-05-19",
    "availability": "partial",
    "parks": [
      "80007823"
    ]
  },
  {
    "date": "2022-05-20",
    "availability": "partial",
    "parks": [
      "80007823",
      "80007838"
    ]
  },
  {
    "date": "2022-05-21",
    "availability": "full",
    "parks": [
      "80007944",
      "80007823",
      "80007998",
      "80007838"
    ]
  }
]

可用性变量很明显。它只是告诉我们那天是否有可用性。它有三个州 - 没有部分,又有。公园阵列向我们展示了哪些公园可用,但是我们为每个公园提供了某种身份证。这花了一些工作来弄清楚,但是在网站和JSON数据之间查看,我能够确定哪个ID代表了哪个公园。

80007823 = Animal Kingdom
80007838 = EPCOT
80007944 = Magic Kingdom
80007998 = Hollywood Studios

收集了所有这些信息,是时候开始使用它了。

让我们进行编码

首先,我决定使用一些工具来实现此自动化。我正在为所有服务使用免费层,所以他们没有花我一分钱ð

  • python-通常是我选择的语言(武器),尤其是自动化。
  • Requests-如果您曾经使用过Python,则可能已经使用了此库。它允许您使用HTTP发送和接收请求和响应。
  • Google Cloud Functions-用于按计划运行我们的代码。
  • Twilio Messaging-如果魔术王国可用,请向自己发送短信警报!

让我们从如何接收数据开始。在这里,我们正在使用请求。这是我们的代码,并提供评论。

import requests

# Set our variables for the request we want to make
base_url = 'https://disneyworld.disney.go.com/availability-calendar/api/calendar'
start_date = '2022-05-15'
end_date = '2022-05-21'

# Add a header so that the request looks legit
headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:98.0) Gecko/20100101 Firefox/98.0',
}

# Set our URL parameters to get the data we want
params = {
    'segment': 'tickets',
    'startDate': start_date,
    'endDate': end_date,
}

# Using the above data, make our request, and get our response
response = requests.get(
    base_url,
    headers=headers,
    params=params,
)

# Convert the data from a JSON string to a python dictionary
data = response.json()

那是相当痛苦的。现在我们有了我们需要的数据,让我们使用它。

# Map the IDs with the parks
parks = {
    '80007823': 'Animal Kingdom',
    '80007838': 'EPCOT',
    '80007944': 'Magic Kingdom',
    '80007998': 'Hollywood Studios',
}

# The park we're looking for
park_wanted = '80007944'

# An array of available dates
dates = []

# data is from the response in the code block above
for item in data:
    # Check if there's availability
    if item['availability'] != 'none':
        # Check if the park we want is available
        if park_wanted in item['parks']:
            # Add the date to our available dates array
            dates.append(item['date'])

我不会去设置Twilio,因为他们在登上客户并解释如何入门的情况下做得很好。我们的代码非常简单。我们只是使用我们的帐户信息创建一个Twilio客户端,制作短信并发送。

# Import the Twilio client
from twilio.rest import Client

account_sid = 'A*******'             # Twilio account SID
auth_token = 'b*******'              # Twilio auth token
twilio_phone_number = '+1**********' # Phone number Twilio account sends from 
phone_number = '+1**********'        # Our phone number

# Check if we found any available dates
if dates:
    # Create our Twilio client
    twilio_client = Client(account_sid, auth_token)

    # Create and send our message
    twilio_client.messages.create(
        body=f"Reservations are now available for { parks[park_wanted] } on { [date for date in dates] }. Reserve now: https://disneyworld.disney.go.com/park-reservations/create-party",
        from_=twilio_phone_number,
        to=phone_number
    )

现在我们需要将所有内容组合起来,并使其可通过Google Cloud功能可用。我们需要将重要部分包装在功能中,以便Google Cloud功能调用,然后我们还需要在该功能结束时返回某些内容。这是我们完成的代码。

import requests
from twilio.rest import Client

parks = {
    '80007823': 'Animal Kingdom',
    '80007838': 'EPCOT',
    '80007944': 'Magic Kingdom',
    '80007998': 'Hollywood Studios',
}

park_wanted = '80007944'

account_sid = 'A*******'
auth_token = 'b*******'
twilio_phone_number = '+1**********'
phone_number = '+1**********'

base_url = 'https://disneyworld.disney.go.com/availability-calendar/api/calendar'
start_date = '2022-05-15'
end_date = '2022-05-21'

headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:98.0) Gecko/20100101 Firefox/98.0',
}

params = {
    'segment': 'tickets',
    'startDate': start_date,
    'endDate': end_date,
}

def run(request):
    response = requests.get(
        base_url,
        headers=headers,
        params=params,
    )
    data = response.json()

    dates = []

    for item in data:
        if item['availability'] != 'none' and park_wanted in item['parks']:
            dates.append(item['date'])

    if dates:
        twilio_client = Client(account_sid, auth_token)
        twilio_client.messages.create(
            body=f"Reservations are now available for { parks[park_wanted] } on { [date for date in dates] }. Reserve now: https://disneyworld.disney.go.com/park-reservations/create-party",
            from_=twilio_phone_number,
            to=phone_number
        )

    return 'complete'

最后要做的就是将其放在Google Cloud功能上。互联网上有很多有关如何使用Google Cloud功能进行的文章,因此我不会在这里参与其中。

现在我们等待。

等待

我们上了飞机,我仍然没有得到文字。

两天后,我们定居在度假村,仍然没有文字。

第二天,我们到达Epcot,在迪士尼世界的第一天,仍然没有文字。

然后发生了

我认为我不会忘记这一刻。我们刚刚看过Epcot Fireworks的表演,就像我们在世界之巅一样。我和我的伴侣并排行走,他们都与我们近乎睡眠的孩子一起推动双婴儿推车。我们讨论了那天我们错过的所有事情,我们将在第二天检查一下...

然后,我意识到我在过去几分钟内在手机上收到了几次通知。我把手机从口袋里拉出,向伴侣大喊:“魔术王国是开放的!”。我们找到了一张桌子,停在婴儿车,疯狂地试图取消我们的第二天Epcot保留地,然后终于为魔术王国保留了第二天。

我们做到了。

Magic Kingdom Castle - Photo by Capricorn song on Unsplash

回顾

从旅行的肾上腺素匆忙中降下来后,我想到是否可以将其用于其他人使用。我注意到我进行了一些思想实验的问题:

  1. 我认为不会有足够的客户作为服务。
  2. 如果有多个客户试图在特定日期确保特定的公园,它将彼此对抗。这似乎不公平。

我最近还了解到,有时您可以构建仅适合您的东西。它不需要每个人。我认为这可以使它变得特别。