{"id":1317,"date":"2021-04-09T15:21:50","date_gmt":"2021-04-09T19:21:50","guid":{"rendered":"https:\/\/blog.lufamily.ca\/kang\/?p=1317"},"modified":"2021-04-09T15:21:50","modified_gmt":"2021-04-09T19:21:50","slug":"checking-for-vaccine-schedule-availability","status":"publish","type":"post","link":"https:\/\/blog.lufamily.ca\/kang\/2021\/04\/09\/checking-for-vaccine-schedule-availability\/","title":{"rendered":"Checking for Vaccine Schedule Availability"},"content":{"rendered":"\n<p>It looks like York Region is beginning to ramp up our vaccine schedules. We are now awaiting our postal code to be eligible so that my wife and I can make an appointment. At the time of writing this post, unfortunately, our postal code is still not eligible.<\/p>\n\n\n\n<p>We know some of our neighbours are checking the website, <a rel=\"noreferrer noopener\" href=\"https:\/\/york.ca\/covid19vaccine\" target=\"_blank\">https:\/\/york.ca\/covid19vaccine<\/a> on a regular basis. Obviously, this is very tedious and frustrating. I decided to embark on a small project to detect our postal code from the web site. My goal is to write a script that can be executed from my NAS server every 30 minutes to see if it can find our postal code on the website. My first attempt was to use Python and <a rel=\"noreferrer noopener\" href=\"https:\/\/www.selenium.dev\/documentation\/en\/\" target=\"_blank\">Selenium<\/a>. The API was a bit clunky and I found it to be somewhat unreliable and fraught with timing issues. I gave up on this approach.<\/p>\n\n\n\n<p>I thought I give it another shot, but this time using <a rel=\"noreferrer noopener\" href=\"https:\/\/www.npmjs.com\/package\/puppeteer\" target=\"_blank\">Puppeteer<\/a>. This was much more simpler to use, and I found it to be more friendly especially if you&#8217;ve worked with Browser based Javascript to begin with.<\/p>\n\n\n\n<p>I wrote this simple <code>node<\/code> script called <code>scrape.js<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code smallFont\"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\n#!\/usr\/bin\/env node\n\nconst puppeteer = require(&#039;puppeteer&#039;);\n\nconst targetPostalCode = process.argv&#x5B;2] || &#039;A2B&#039;;\n\nconsole.log (&#039;scraping for &#039; + targetPostalCode + &#039;...\\n&#039;);\n\n(async () =&gt; {\n  const browser = await puppeteer.launch();\n  const page = await browser.newPage();\n  await page.goto(&#039;http:\/\/york.ca\/covid19vaccine&#039;);\n\n  const anchorSelector = &#039;div#Y_accor div.new h3.Y_accordion span.trigger a&#039;;\n  await page.waitForSelector(anchorSelector);\n\n  console.log (&#039;received...\\n&#039;);\n\n  const result = await page.evaluate((anchorSelector) =&gt; {\n    let res = &#x5B;];\n    document.querySelectorAll(anchorSelector).forEach(function(elem){\n      if (elem.textContent.match(\/.*50 Years of Age and Older.*\/i) != null) {\n        elem.parentElement.parentElement.parentElement.querySelectorAll(&quot;p&quot;).forEach(function(elem){\n          if (elem.textContent.match(\/.*postal codes.*\/i) != null) { \n            const postalCodes = elem.parentElement.querySelector(&quot;strong&quot;).textContent;\n            postalCodes.split(&quot;, &quot;).forEach(function(pc) {\n              res.push(pc.trim());\n            });\n          }\n        });\n      }\n    });\n    return res;\n  }, anchorSelector);\n\n  console.log(result);\n\n  let found = false;\n  let regex = new RegExp(targetPostalCode, &quot;i&quot;);\n  result.forEach(function(postalCode) {\n    if (postalCode.match(regex) != null) {\n        \/\/ Postal Code Found!\n        console.log(&quot;We found: &quot; + targetPostalCode);\n        found = true;\n    }\n  });\n\n  console.log(&#039;closing...&#039;);\n\n  await browser.close();\n})();\n<\/pre><\/div>\n\n\n<p>I placed this script in the directory <code>\/home\/xxxxx\/gitwork\/covidMonitor<\/code>. Note that I targeted &#8220;<strong>50 years of Age and Older<\/strong>&#8220;, because this is the age group that I am personally interested in. The <code>A2B <\/code>is also not my real postal code. It is used instead of my own private postal code.<\/p>\n\n\n\n<p>Before I run the program, I had to install <code>puppeteer<\/code> in my working directory. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">cd \/home\/xxxxx\/gitwork\/covidMonitor\nsudo npm i puppeteer<\/pre>\n\n\n\n<p>Running the above <code>scrape.js<\/code> produces the following:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code smallFont\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nscraping for A2B...\n\nreceived...\n\n&#x5B; &#039;L0J&#039;,\n  &#039;L4B&#039;,\n  &#039;L4E&#039;,\n  &#039;L4H&#039;,\n  &#039;L4J&#039;,\n  &#039;L4K&#039;,\n  &#039;L4L&#039;,\n  &#039;L6A&#039;,\n  &#039;L3S&#039;,\n  &#039;L3T&#039;,\n  &#039;L6B&#039;,\n  &#039;L6C&#039;,\n  &#039;L6E&#039; ]\nclosing. \n<\/pre><\/div>\n\n\n<p>Of course <code>A2B<\/code> is not in the list. If it was, another line like:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code smallFont\"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nWe found: A2B\n<\/pre><\/div>\n\n\n<p>will be in the output.<\/p>\n\n\n\n<p>I supplemented the above with a shell script program which I can later use to configure cron to be executed every 30 minutes. The shell script&#8217;s job is to monitor the website using <code>scrape.js<\/code> and if the postal code is found, then send a notification email.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code smallFont\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\n#!\/usr\/bin\/env zsh\n\ncd \/home\/xxxxx\/gitwork\/covidMonitor\n\nif &#x5B; $(.\/scrape.js | tee \/home\/xxxxx\/log\/covidPostalCodes.log | grep &quot;found&quot; | wc -l) -ge 1 ]\nthen\n\nsendmail xxxxx@gmail.com &lt;&lt;@\nSubject: Covid Vaccine Can Be Scheduled\n\nGoto the following site to schedule your vaccine:\n\nhttps:\/\/york.ca\/covid19vaccine\n\n@\n\nfi\n<\/pre><\/div>\n\n\n<p>I could have included the email notification logic in the node script as well, but I figure I may want to check manually on an infrequent basis, in which case I simply run the <code>scrape.js<\/code> script on the command line.<\/p>\n\n\n\n<p>Now all there is to be done is relax and wait, a thing that we have been doing a lot lately during the pandemic.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It looks like York Region is beginning to ramp up our vaccine schedules. We are now awaiting our postal code to be eligible so that my wife and I can make an appointment. At the time of writing this post, unfortunately, our postal code is still not eligible. We know some of our neighbours are &hellip; <a href=\"https:\/\/blog.lufamily.ca\/kang\/2021\/04\/09\/checking-for-vaccine-schedule-availability\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Checking for Vaccine Schedule Availability&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1317","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p7V6i8-lf","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/blog.lufamily.ca\/kang\/wp-json\/wp\/v2\/posts\/1317","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.lufamily.ca\/kang\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.lufamily.ca\/kang\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.lufamily.ca\/kang\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.lufamily.ca\/kang\/wp-json\/wp\/v2\/comments?post=1317"}],"version-history":[{"count":10,"href":"https:\/\/blog.lufamily.ca\/kang\/wp-json\/wp\/v2\/posts\/1317\/revisions"}],"predecessor-version":[{"id":1329,"href":"https:\/\/blog.lufamily.ca\/kang\/wp-json\/wp\/v2\/posts\/1317\/revisions\/1329"}],"wp:attachment":[{"href":"https:\/\/blog.lufamily.ca\/kang\/wp-json\/wp\/v2\/media?parent=1317"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.lufamily.ca\/kang\/wp-json\/wp\/v2\/categories?post=1317"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.lufamily.ca\/kang\/wp-json\/wp\/v2\/tags?post=1317"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}