{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "03b14f3a",
   "metadata": {},
   "source": [
    "# Web Scraping\n",
    "\n",
    "Most webpages are created for humans, but that doesn't mean we can't write computers to \"scrape\" information out of them.  Today, we're going to learn selenium, a powerful tool that allows us to automate typing, clicks, and other actions in a real web browser.  It will help us pull data from sites with a number of challenging designs, several of which are illustrated by simple examples here: https://tyler.caraza-harter.com/cs320/tricky/scrape.html\n",
    "\n",
    "First, let's take a look web scraping via two simpler tools, `requests` and `BeautifulSoup`.\n",
    "\n",
    "## requests and BeautifulSoup\n",
    "\n",
    "If you don't already have these packages, install them: `pip3 install requests beautifulsoup4`.  `requests` lets us to execute GET (download) and other HTTP requests.  Often, the file requested might be an HTML file.  In this case, BeautifulSoup lets us extract information from HTML tags.\n",
    "\n",
    "We'll try to scrape the tabels from this page: https://tyler.caraza-harter.com/cs320/tricky/page1.html.  Visit it, right click on the page, then click \"View Page Source\".\n",
    "\n",
    "You'll see something like this:"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3e078b28",
   "metadata": {},
   "source": [
    "```html\n",
    "<html>\n",
    "  <head>\n",
    "    <script src=\"https://code.jquery.com/jquery-3.4.1.js\"></script>\n",
    "    <script>\n",
    "      ... LOTS OF JAVASCRIPT CODE HERE...\n",
    "    </script>\n",
    "  </head>\n",
    "  <body onload=\"main()\">\n",
    "    <h1>Welcome</h1>\n",
    "    <h3>Here's a table</h3>\n",
    "    <table border=1 id='alpha'>\n",
    "      <tr><td>A</td><td>B</td><td>C</td></tr>\n",
    "      <tr><td>1</td><td>2</td><td>3</td></tr>\n",
    "      <tr><td>4</td><td>5</td><td>6</td></tr>\n",
    "    </table>\n",
    "\n",
    "    <h3>And another one...</h3>\n",
    "  </body>\n",
    "</html>\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fa3f0b8a",
   "metadata": {},
   "source": [
    "Inside the `<script>` tags there is code in the JavaScript programming language.  One the page is loaded in the browser, this code starts executing, and may make some changes to the tags/elements.\n",
    "\n",
    "In the above HTML, we see one table (`<table>`); however, the JavaScript code will automatically generate a second table.  With the `requests` module, we can only grab the version of the page **before** the JavaScript runs.  So in this example, we'll just extract data from that first table (later we'll use Selenium to get data from the second table too)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "0edd48d6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "requests.models.Response"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import requests\n",
    "r = requests.get(\"https://tyler.caraza-harter.com/cs320/tricky/page1.html\")\n",
    "r.raise_for_status()\n",
    "type(r)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "995a0d6c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "str"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "html = r.text\n",
    "type(html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "d99b0b1e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'<html>\\n  <head>\\n    <script src=\"https://code.jquery.com/jquery-3.4.1.js\"></script>\\n    <script>\\n      function addTable() {\\n        var html = \"<table border=1 id=\\'coords\\'>\\\\n\";\\n        html += \"<tr><'"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "html[:200]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7cba8fc1",
   "metadata": {},
   "source": [
    "Above, we see we can use `.get` to request a web page; a `Response` object is returned.  The `.raise_for_status()` call makes sure we crash if it is an error page (such as a \"404 missing\" error).\n",
    "\n",
    "Once we're sure the page is good, we can access the `.text` attribute of the `Response` object.  As show above, this is a regular string.\n",
    "\n",
    "We'll use BeautifulSoup to convert this text to a `BeautifulSoup` object, which is a searchable tree of elements."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "95905149",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "bs4.BeautifulSoup"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from bs4 import BeautifulSoup\n",
    "doc = BeautifulSoup(html, \"html.parser\")\n",
    "type(doc)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "099c192d",
   "metadata": {},
   "source": [
    "Looks like there are three tr tags (table rows) on the page:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "79bbf6fc",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "trs = doc.findAll(\"tr\")\n",
    "len(trs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "c64cb3fd",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[<tr><td>A</td><td>B</td><td>C</td></tr>,\n",
       " <tr><td>1</td><td>2</td><td>3</td></tr>,\n",
       " <tr><td>4</td><td>5</td><td>6</td></tr>]"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "trs"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "568d3e6d",
   "metadata": {},
   "source": [
    "They are represented as `Tag` objects; `Tag` elements looks like HTML when converted to a string.  Alternatively, the `.text` attribute shows us the raw content, without all the surrounding HTML."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "4e32e33b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'<tr><td>A</td><td>B</td><td>C</td></tr>'"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "str(trs[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "f41d2ba9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'ABC'"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "trs[0].text"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d93aea9f",
   "metadata": {},
   "source": [
    "The `findAll` method can be used on the whole page, or to search within a single element/Tag."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "0f1f7409",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "9"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(doc.findAll(\"td\")) # 9 cells (td=table data) in whole page"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "f3e39d91",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(trs[0].findAll(\"td\")) # 3 cells (td=table data) in first row"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "60a3de0a",
   "metadata": {},
   "source": [
    "Let's right a method that does three things:\n",
    "1. fetch a page using `requests.get`\n",
    "2. parse that page with BeautifulSoup\n",
    "3. search through the tree for rows/cells, placing them in a list of lists"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "90004f29",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[['A', 'B', 'C'], ['1', '2', '3'], ['4', '5', '6']]"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def grab_table(url):\n",
    "    r = requests.get(url)\n",
    "    r.raise_for_status()\n",
    "    doc = BeautifulSoup(r.text)\n",
    "    rows = []\n",
    "    for tr in doc.findAll(\"tr\"):\n",
    "        row = []\n",
    "        for td in tr.findAll(\"td\"):\n",
    "            row.append(td.text)\n",
    "        rows.append(row)\n",
    "    return rows\n",
    "\n",
    "rows = grab_table(\"https://tyler.caraza-harter.com/cs320/tricky/page1.html\")\n",
    "rows"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "541f61d9",
   "metadata": {},
   "source": [
    "The above is a short step away from getting a useful DataFrame:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "d10be814",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>A</th>\n",
       "      <th>B</th>\n",
       "      <th>C</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1</td>\n",
       "      <td>2</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>4</td>\n",
       "      <td>5</td>\n",
       "      <td>6</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   A  B  C\n",
       "0  1  2  3\n",
       "1  4  5  6"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "\n",
    "header = rows[0]\n",
    "data = rows[1:]\n",
    "pd.DataFrame(data, columns=header)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3d41dec1",
   "metadata": {},
   "source": [
    "# Selenium\n",
    "\n",
    "Selenium is able to automate clicks and type text in an actual web browser.  This will let us do things like take a screenshot of a page and actually execute the JavaScript in the `<script>` tags (to get the data in the second table too).\n",
    "\n",
    "Selenium has some features of both `requests` and `BeautifulSoup`: it can both grab content, and provide a searchable tree.\n",
    "\n",
    "Let's create a web browser (of type `WebDriver`):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "9fd68d9f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "selenium.webdriver.chrome.webdriver.WebDriver"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from selenium import webdriver\n",
    "from selenium.webdriver.chrome.options import Options\n",
    "from selenium.common.exceptions import NoSuchElementException\n",
    "\n",
    "options = Options()\n",
    "options.headless = True\n",
    "b = webdriver.Chrome(options=options)\n",
    "type(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "18681bd3",
   "metadata": {},
   "source": [
    "The `headless = True` means the browser is hidden, in the background (this is necessary to run on a virtual machine without graphics).  But we can still manipulate this browser and see what it is doing by taking screenshots:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "9e6850b2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b.get(\"https://tyler.caraza-harter.com/cs320/tricky/page1.html\") # go to a page\n",
    "b.save_screenshot(\"shot1.png\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "3f4cfd9c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAyAAAAJYCAYAAACadoJwAAAAAXNSR0IArs4c6QAAIABJREFUeJzt3XucVXW9+P/3ZmBGBhgQENHEQYG8gZcKrwiIctCyDDU9aokYZaWGeTupHRJLS48+ssRbD01hSlJLUFCoo+IFRbNMRbHMTEARBDGuOoCs3x/92F9mZg8ze2b4MMeez8djHrrX5bM+e+9/9ou91tq5LMuyAAAASKDNtp4AAADw70OAAAAAyQgQAAAgGQECAAAkI0AAAIBkBAgAAJCMAAEAAJIRIAAAQDICBAAASEaAAAAAyQgQAAAgGQECAAAkI0AAAIBkBMj/b+rUqZHL5er8zZw5c1tPDQAAPjYaDJAsy6J79+51PpjvvffeW9xv4sSJBT/Qn3TSSVvc76KLLiq438svv1zcMwMAAFqdBgMkl8vFoEGD6ix/9dVXY+nSpfXu9+STTxa1fJMnnniizrLtt98+9tlnnwZmCgAAtHaNOgVr8ODBBZdvKSbqW7d48eJ4/fXXC65bs2ZNPP/883WWDxo0KHK5XCNmCgAAtGZbJUDefffdeO211+odr7795syZExs2bKiz/PDDD2/ELAEAgNauUQFywAEHRKdOneosL3S61JaWN3U/AQIAAB8PjQqQkpKSOOSQQ+osf/HFF2PlypV1ltf+hqOiomKL6zcpFCDl5eXx6U9/ut65vfrqqzFu3LgYNmxY9OrVKzp06BDl5eVRWVkZxx57bNx4442xevXqevdvCYsWLYprr702Ro4cGX379o3tt98+SktLY6eddooDDjggTj311Jg4cWIsXry4wbFeeOGFuPTSS2Pw4MGxyy67RHl5eZSXl8cuu+wShx9+eFxyySXxwgsvNDjOr3/96y3e1etvf/tbnH322dGnT59o37597LrrrjFy5Mh49NFH64z18ssvx1lnnRX9+vWL9u3bR7du3WLw4MFx4403xrp16xr9OrWG9woAgG0sa6Qf/vCHWUTU+XvooYfqbHvAAQfU2OaSSy6ps9+iRYtq7FNdXZ21b9++znbDhg0rOJ/FixdnI0eOzHK5XMF5bf63ww47ZFVVVVt8flOmTCm474wZM+rdZ8WKFdlXv/rVrF27dg3OISKyffbZp96xFixYkB199NGNGicismOOOSZ766236h1v8uTJ9T6fqqqqrLy8vN6xL7zwwmzjxo1ZlmXZNddck7Vt27bebQcOHJgtW7Zsi69tS79XAAD839Xo3wFp7HUgK1eujJdeeqnGstGjR8cnPvGJLe733HPPxQcffFBn/EKnX7300kux3377xZQpUyLLsgbnvnTp0vjKV74S48ePb3Dbxvr73/8e++23X9x+++2xfv36Zo313HPPxQEHHFDUb47MmDEj9t9//4IX7W/JtGnTYtSoUbF27dp6t7n22mvj5z//eVx77bVx8cUXF7wuZ/O5jxkzpt71reG9AgCg9Wh0gBx44IFRVlZWZ3nt06aeeuqp+Oijj/KPd9xxx+jXr1+dkKi9X2Ov/3j33Xfj2GOPjSVLljR26nmXX3553H333UXvV9vy5ctjxIgR8eabbzZ7rEWLFsUXvvCFeO+994red9myZfH5z3++qNfipptuio0bNza43QUXXBD/9V//1agxp06dWvC0sNbwXgEA0Lo0OkDKysriwAMPrLP8ueeeiw8//DD/uPY3G5sCovY3KLW3KxQgbdu2jYMPPrjGsssvvzwWLlxYZ9vevXvHfffdFytWrIiVK1dGVVVVdO7cuc523/rWt5p9ncEVV1wRf//73wuuGz16dDz99NOxcuXKWLNmTbzwwgvxve99r851MJuMGzeu4LUhu+++e9x///2xcuXKWLVqVdx///2x22671dlu0aJFRX9bsMcee8QTTzwRa9eujT/96U/Rr1+/OtusWbMmNm7cGB06dIg77rgjVq1aFW+++WZ8/vOfLzjmlClT6ixrDe8VAACtTDHna1122WUFz9t/7LHH8tsMGjSoxrqf/vSnWZZl2csvv1xjeZs2bbL3338/y7Is++ijj7KKioo64x500EE1jv/+++8XvN6ivLw8e/311+vM97777is435/85Cd1tm3sNSArVqzISktLC25722231fvaLVmyJBs7dmyNZcuXLy94fUWnTp2y+fPn1xnjH//4R9ahQ4c627dr1y5bsWJFjW3ruwakrKwse+ONN2psW1VVVe81GXfccUeNbZctW5aVlJTU2e4LX/hCje225nsFAMD/XY3+BiSi/utANn17UV1dHc8991zBffbee+/o3r17fvnGjRvjqaeeioh/3fmp0N20ap9+9cgjjxS83uJb3/pW9OnTp87ykSNHxp577lln+bRp0wo+j8Z4+OGHC9756eijj46vfvWr9e7Xo0ePuP766+uMVej6ilGjRsWuu+5aZ3nv3r3jK1/5Sp3l69evj1mzZjVm+jFy5Mg636QMGDCg4Lbdu3evc7xu3boVfK2XLl1a43FreK8AAGh9igqQQw89NEpKSuos3xQgzz77bFRXV+eXd+7cOfbdd9+IiMjlcjFo0KCC+zX2+o/aF7dv8h//8R/1zrl///51ls2ZM6dRF0QX8uKLLxZcfvLJJxc91ssvv1xw+ZAhQ+rdp74InDt3bqOOWfs9iIgaYbi5gw8+uOD7Xeh0qdo3EGgN7xUAAK1P22I27tixYxxwwAHxxz/+scbyTb9gXvu6jkMPPTTatPl/jTN48OCYOnVq/vGm7QsFSKFgqf2v7Jts6UNtIR988EG8//770bVr16L229Ic+vbt22Jj7bzzzvXuU9+6+saqrfbdyCIiSktLC27bq1evgssLfWtTOxJaw3sFAEDrU9Q3IBGF/wV+zZo18fzzz9cJkNrb1n78xz/+MdauXRuzZ8+uM+Y+++yzVT90Ll++fKuNvTU199uA7bbbrs6yXC5XcNvy8vKCyxtzF62W9H/1vQIAoK4WCZCIiFmzZsXTTz9dY1ntU6j233//GneDWr9+fUycOLHgv5YX+v2PHXbYodjp1mtLv22xJfXN4fXXX2+xsRYtWlTvPu+8805RY20rreG9AgCg9Sk6QAYNGlTwX8xvvvnmWLVqVf7xdtttFwMHDqyxTUlJSRx66KE1ll199dUFj1MoQOq7WPq5556LLMuK+it0wXNj7LfffgWXN+U3Kwpd8xBR/zUxW1pX32uzrbSG9woAgNan6ADp1q1b7L333nWWz58/v8bjgw46qOC1BbW/Qam93yaFAuSoo46Ktm3rXrZyxRVXNOq0oJdeeilGjx7drDsrHXXUUQWf18yZM+POO++sd79//vOfcdFFF9VYduSRRxZ8PhMnToy33nqrzvIFCxZEVVVVneXt2rWLI444ojHTT6Y1vFcAALQ+RQdIRP2nYW2uUEA0dt/evXvHLrvsUmd5ly5dCt7qdtq0aXHIIYdEVVVVvPHGG7F27dpYu3ZtLFy4MB566KEYN25cDBgwIPbbb7+48847a9ypq1gVFRXxjW98o+C6M888M772ta/FM888E6tXr44PPvgg5s2bFz/+8Y+jX79+MWPGjBrbd+3aNUaNGlVnnJUrV8YRRxwR06dPj9WrV8eaNWti+vTpMWzYsFizZk2d7ceMGVPvDx1uK63hvQIAoPUp6i5YmwwePDhuvvnmLW5TX4AMHDgw2rdvX+e2rbXHr8/48eNj+vTp8fbbb9dY/oc//CFOP/30Lc6ppYwbNy6mTZsW//jHP2osz7IsbrvttrjtttsK7rfjjjvWWXbFFVfE9OnTY8mSJTWWv/766/X+6vjmdt555xg3blwRs0+nNbxXAAC0LlvlG5BC13psUlpaGgcddNAW968vXiL+9SH+oYceih49ejQ80a2kW7du8bvf/a7gjwUWa+edd45p06Y16Y5f3bp1i2nTpkXPnj2bPY+toTW8VwAAtC5NCpCdd945dt9993rXH3DAAdGxY8d61zcUMFsKkIiIfffdN+bOnRsnnnhijd8ZachnPvOZmDRpUhx33HGN3qc+/fr1ixdffDHOOOOMgtc6FGPgwIHxwgsvxIgRIxq9z4gRI+KFF16IT33qU8069tbWGt4rAABajyZ/ch48eHC88cYbBdc1FBBbCpAePXrEHnvs0eDxe/ToEffee2+88cYbMXny5Hjqqadi3rx5sXz58li7dm106tQpevbsGQMGDIiDDz44jjvuuOjTp0+D4xajS5cucccdd8QPfvCDuOuuu+Kpp56KuXPnxvLly2PNmjXRrVu36NmzZ+y1114xYsSIOProo+sdq1evXjFz5sx44YUX4u67747Zs2fH3//+93j//fcjImL77beP3XffPQYNGhT/+Z//Gfvvv3+LPpetqTW8VwAAtA65rLm/bAcAANBITToFCwAAoCkECAAAkIwAAQAAkhEgAABAMgIEAABIRoAAAADJCBAAACAZAQIAACQjQAAAgGQECAAAkIwAAQAAkhEgAABAMgIEAABIRoAAAADJCBAAACAZAQIAACQjQAAAgGQECAAAkIwAAQAAkhEgAABAMgIEAABIRoAAAADJCBAAACAZAQIAACQjQAAAgGQECAAAkIwAAQAAkhEgAABAMgIEAABIRoAAAADJCBAAACCZRgXIY489FrlcLv83derUOttMmDChxjZ/+ctfWnyyLeGFF17Iz3HDhg3bejrbzC233JJ/Hbp3777V9wMAgAjfgLR6ixcvrhF2zzzzzLaeEgAANJkAAQAAkhEgAABAMskCZOPGjTFp0qQYPnx47LDDDtGuXbvo3r17HHPMMTF9+vQ629e+1qC6ujouueSS6NWrV5SUlOSvQyl23Pps2LAhrrvuujjooIOiS5cu0a5du6isrIzhw4fHtddeG++8806jxpk5c2aNU6ZyuVyUlZVFr1694sQTT4zHHnus0XMaOnRo7LTTTjWWHXLIIflxv/zlL7fYMTds2BCXX355VFZWxnbbbRf9+/ePm2++udFz3aSl3g8AAD6mskaYNWtWFhH5vylTptTZ5oYbbqixzauvvppft3bt2uyoo46qsb7233e+850a49188835dV27ds2OO+64OnNoyrj1+drXvrbFcUaMGNGocWbMmLHFcXK5XHb77bc3aqwhQ4ZscazTTjutycfc/PXt1q1b9qUvfangvueff/4W99tcS74fAAB8PDUpQBrzt3mAfPvb384v32mnnbJZs2Zla9asyR5++OGsc+fO+XX33ntvfp/NP+hGRLbnnntmTz75ZPbhhx82a9z6lJeXZxGRlZSUZE888URWXV2dLVq0KHv88cez8847Lxs1alQxr2vehg0bsrfeeiu7+OKLawRVdXV1o/Z/5513arwOc+bMaZFj1n59Bw0alP3tb3/Lli5dmp199tk11j377LMF96sdIC35fgAA8PG01QOkuro669ixY375bbfdVmPsCy64IL9u2LBh+eW1PyA/88wzNfZr6rj16d69exYRWZs2bbJf/OIX2WuvvZatW7euMS9Po6xdu3aLz6c+TQmQxhyz9us7d+7c/Lrq6uqsR48e+XXnnXdewf02D5CWfj8AAPh4atI1IFOmTInsX/GS/7vhhhsKbjt//vxYvXp1/vGYMWNqXKtw3XXX5de99NJLBccoLS2NgQMHtvi4mxs9enRE/OsahjPPPDM++clPRnl5efTv3z/Gjh0bb775ZoNjRESsW7cufvKTn8SQIUOiR48eUVpaGrlcLsrLy2tst3jx4kaNl+KYZWVlsc8+++Qfl5aW1nj817/+tcE5tPT7AQDAx1PbbT2BzW3+AXZznTp1ijZtmn69fH3jbu7HP/5x7LnnnnHPPffEn//853j33Xdjw4YN8corr8Qrr7wSv/3tb+Oll16Krl27bnGc448/Ph588MEGj7d+/fpGz78h2+KYzdGY9wMAgI+nrX4XrMrKyujYsWP+cVVVVZ1vTzb9ffDBB9ts3DZt2sSZZ54ZM2fOjCVLlsSqVaviiSeeiB49ekRExNtvvx2PP/74FsdYuHBhjRAYN25cLF++PLIsi2XLljX6uW0ul8vVeJxlWYsfs7q6OubNm5d/vG7dunjllVfyjz/5yU82OMbWep8BAPh42eoBUlpamj+9KSLiwgsvjAceeCBWrFgRq1atinnz5sXkyZPjhBNOiJ/97GfbbNyjjz46xo8fH88++2wsWbIkysrKanygjmj4G4R27drVeNypU6do3759vPnmm/H1r3+90c9tcxUVFTW+/Zk9e3Zs2LChxY/5rW99K954441YtmxZnH/++fHuu+/m151yyikN7r+13mcAAD5mGnOhSHNvw7tmzZrsyCOPbPDC9R/96Ef5fbZ0t6XmjFufPn36bHGMysrKbMWKFQ2OM2LEiIL7177NbzF3gjr88MMLjllVVdXkY9a+zfGJJ55YcIyxY8fWmMuW3peWfD8AAPh4SvJDhOXl5fH73/8+qqqqYsSIEdGjR49o27ZtdOvWLfbdd98YNWpUTJ06NcaOHbvNxn3kkUfif/7nf2Lo0KHRq1evaNu2bXTo0CH69+8fF1xwQTz77LNRUVHR4Dh33313XHDBBdG7d+8oKyuLPn36xNVXXx0TJkwo6rltrqqqKkaOHBndunWrc0pWSxwzl8vFXXfdFePGjYtdd901SktLY6+99ooJEybE9ddf3+h5bq33GQCAj49cltW6qAAAAGArSfINCAAAQIQAAQAAEhIgAABAMgIEAABIRoAAAADJCBAAACAZAQIAACQjQAAAgGQECAAAkIwAAQAAkhEgAABAMgIEAABIRoAAAADJCBAAACAZAQIAACQjQAAAgGQECAAAkIwAAQAAkhEgAABAMgIEAABIRoAAAADJCBAAACCZtg1tMH78+BTzSG7evHlx9913b+tpAADAv5UGAyQi4vvf//7WnkdyAwYM2NZTAACAfztOwQIAAJJp1DcgmzT1W4PKysqYPn16qxoDAABIr6gAiYiYO3du0QepfR1JaxkDAABIyylYAABAMgIEAABIRoAAAADJtEiAjBkzJnK5XJx//vlF7TdhwoTI5XL5v5KSkthll13ilFNOiddff72osZ599tk4+eST4xOf+ESUlZXFrrvuGsOHD4/JkyfH+vXrixoLAADYOpodIB988EHce++9sd1228WvfvWr2LBhQ9FjvPrqq5FlWVRXV8eMGTPitddeiyOPPDJWrVrVqP0nTJgQhx56aPTo0SMefvjhWLlyZcyePTuGDh0aZ555Zjz44INFzwkAAGh5zQ6QKVOmxMqVK+PKK6+Md999N2bOnNnksdq2bRsDBgyI73//+7FgwYKYM2dOg/vMmTMnxo4dG5dddlnccMMNsddee+W/Abnsssvisccei4qKiibPCQAAaDnNDpCJEydGv3794rzzzouePXvGpEmTWmJeERGxcePGBre55pproqKiIi699NKC6w866KAYNmxYi80JAABoumYFyKJFi+Lhhx+Ok08+Odq0aRNf+tKX4oEHHoj333+/SeN99NFH8corr8QPf/jD6NevXwwdOrTBfR599NEYNGhQbLfddk06JgAAkE6zAqSqqio2btwYJ598ckREnHzyyVFdXR133313UePstddekcvlom3bttG/f/9YtmxZ/OY3v2kwKlasWBErV66MXXbZpcnPAQAASKdZATJp0qTYe++9o3///hERceihh0avXr2KPg1r00XoGzdujPnz58fhhx8eQ4cOjVdeeaVR++dyuaLnDgAApNfkAHnuuedi3rx5cdJJJ+WX5XK5OOmkk2LOnDnx2muvFT1mLpeLXXfdNW699dZYv359XHnllVvcvnPnzlFRURELFy4s+lgAAEB6TQ6QiRMnRkTE5ZdfXuO3PK677rqIiGZdjL7ddtvFzjvvHK+++mqD2w4bNixmz54dH374YZOPBwAApNGkAFm3bl38+te/jpEjR0aWZXX+jj766Kiqqoosy5o0qQ8//DAWLVoUO+64Y4PbXnzxxbFy5cq4+uqrC67/wx/+EI8++miT5gEAALSsJgXI9OnT47333ovTTjut4PrTTjstFixYEI899lhR42ZZFgsWLIizzjor1qxZE+eee26D+xxyyCFx/fXXxxVXXBFjx46Nv/zlL7Fu3bpYuHBhXHXVVTFkyJBYuXJlUfMAAAC2jiYFyMSJE6OioiI+97nPFVz/xS9+McrLy/OnaTVk012w2rRpEwceeGC88847MWvWrHrHr+3cc8+Np556Kt55550YNmxYdOzYMQ499NCYNWtW3H777Y0eBwAA2LraNmWn+++/f4vrO3bsGGvWrGlwnHPOOSfOOeecpkyhjoMPPjjuueeeFhkLAADYOpr9S+gAAACNJUAAAIBkBAgAAJCMAAEAAJIp6iL0ysrKGD9+fLMO2FrGAAAA0isqQKZPn97sA7aWMQAAgPScggUAACRT1DcgAwYMaNJBKisr899atJYxAACA9Ir+IcK5c+cWfZDa12u0ljEAAIC0nIIFAAAkI0AAAIBkBAgAAJBMkwNk48aN8cgjj8To0aOjoqIicrlcvPnmm0WNsWDBgrj00ktjwIAB0aFDh+jbt298+9vfjvfee6/RY6xduzZuvvnmOPjgg6NTp06x0047xec///l45plnin1KAADAVtbkAHn22WfjqquuisMPPzwuvPDCJo1x+umnx9SpU+Paa6+Nd999NyZPnhyPPvpoHHroobF27dpGjXHPPffEP/7xj7jxxhtj8eLFMXv27CgrK4vBgwfHc88916R5AQAAW0fRd8Ha5JBDDolHHnkkIiKuv/76Jo0xfPjwOO+886JDhw4RETFw4MC45ZZb4vDDD4/f/OY3cfrppzc4xhlnnFHjcZ8+feKOO+6ILl26xC9/+csYOHBgk+YGAAC0vCYHSEu47LLL6izbfffdIyJi/vz5TR63pKQkcrlclJeXN3kMAACg5bW6i9BnzpwZEf8vRIqRZVksWLAgzjrrrNhhhx3iG9/4RktPDwAAaIZt+g1IbcuWLYv//u//jl69esXxxx9f1L6DBg2Kp556KiIievbsGb/97W+jsrJya0wTAABoolbzDcj69evj5JNPjqVLl8akSZOiffv2Re0/e/bs2LBhQ/ztb3+LYcOGxVFHHRWPP/74VpotAADQFK0iQLIsi1GjRsWsWbPizjvvjKFDhzZpnJKSkujbt29MnDgxevbsGd///vdbeKYAAEBztIoAOf/882Py5Mlxww03xKmnntrs8dq2bRt77LFH0b9LAgAAbF3bPEB+9KMfxfXXXx8//OEP4+yzz26RMaurq+Pll1+OT37yky0yHgAA0DK2aYDccccdcemll8YFF1xQ8Ja8jXHmmWfGXXfdFQsWLIgPPvggXnrppfy1JE7BAgCA1qXJAbJhw4bI5XKRy+XiO9/5TkRE7LbbbpHL5eLYY49t1BjXXXdd/r+bxtr0d8455zRqjEsvvTSeeOKJOOKII6Jr165x/PHHR6dOneLPf/5zHHbYYU17cgAAwFbR5Nvwtm3bNrIsa9bBX3755WbtHxHRt2/fuOWWW5o9DgAAsPVt82tAAACAfx8CBAAASEaAAAAAyQgQAAAgmaIuQq+srIzx48c364CtZQwAACC9ogJk+vTpzT5gaxkDAABIzylYAABAMkV9AzJgwIAmHaSysjL/rUVrGQMAAEiv6B8inDt3btEHqX29RmsZAwAASMspWAAAQDICBAAASEaAAAAAybRYgIwcOTJyuVycccYZjd7n4YcfjlwuV+eve/fuRR//oYceiiFDhkSnTp2iV69ecfHFF8eqVauKHgcAANh6WiRA7rnnnnj88cejtLS0SfvPnTs3sizL/y1btqyo/W+99dY45ZRTYsyYMfH222/Hiy++GD179owpU6Y0aT4AAMDWUfRdsGp777334txzz42rrroqLrzwwpaYU1HefPPNOO+88+K2226L0047Lb/8/PPPTz4XAABgy5r9Dch5550XlZWV8fWvf70l5lO0X/ziF1FWVhYnn3zyNjk+AADQeM0KkBkzZsRdd90VN910U7Rp0/ShjjjiiGjXrl3stNNOMXr06Hj77bcbve/s2bOjf//+cc0110Tv3r2jrKws9txzz7jpppuaPB8AAGDraHI1rFq1Ks4666z4xje+EZ/5zGeaNEZZWVl873vfi9mzZ8fy5ctj0qRJMXv27Dj44INj6dKljRpj0aJF8cwzz8Sdd94Z9957byxZsiS++c1vxtlnnx3XXnttk+YFAABsHU0OkIsvvjiqq6vjyiuvbPLBDz/88PjBD34Qe+yxR3Tq1CmGDx8e9913X7z99ttx/fXXN2qMjRs3xkcffRQ33HBDDBw4MLp06RJjx46NY489Nn70ox/Fxo0bmzw/AACgZTUpQP7617/GrbfeGtdee2106dKlRSc0YMCA6NWrVzz77LON2r5bt24REXHYYYfVWH7YYYfF8uXLY/78+S06PwAAoOmaFCDvv/9+ZFkWp59+eo3f71izZk1MnDgxcrlczJw5s6XnWtA+++xTcHmWZUmODwAANF6TAuTggw+u8bsdm/46dOgQo0aNiizL4uijj27ShF5++eVYuHBhHHjggY3afuTIkRER8fTTT9dYPmfOnNhhhx2isrKySfMAAABaXov9EnpTjBkzJn75y1/G/PnzY/Xq1fHII4/ECSecEDvvvHOcd955jRrjs5/9bBxxxBFx7rnnxp/+9KdYsWJF3HDDDTF9+vQYP358s+7OBQAAtKxt+un8u9/9bjz55JNxxBFHRNeuXeOMM86IwYMHxx/+8Ifo0aNHo8bI5XIxderUGD58eHzuc5+LHj16xM9//vO4884745vf/OZWfgYAAEAxmv1L6JtbvXp1Udv37ds3br311mYft6KiIiZMmBATJkxo9lgAAMDW4/wkAAAgGQECAAAkI0AAAIBkBAgAAJBMURehV1ZWxvjx45t1wNYyBgAAkF5RATJ9+vRmH7C1jAEAAKTnFCwAACCZBr8BmTdvXgwYMCDcyf6nAAAQrUlEQVTFXAAAgI+5XJZl2baeBAAA8O/BKVgAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJFN0gFRXV8f2228fuVwu/3fSSSdtjbnV6ze/+U2N4/87ueWWW/LPu3v37tt6OgAAUJSiA+SBBx6If/7znw0uo3iLFy+uEVbPPPPMtp4SAAC0qKIDZNKkSXWWVVdXxz333NMiEwIAAD6+igqQpUuXxsyZM/OP+/Xrl///qqqqlpsVAADwsVRUgEyePDk2bNgQERGdO3eOn/3sZ/l1s2fPjjfeeKPOPrWvWdi4cWNcc801sfvuu0eHDh1iwIABcdNNN0WWZXX2XbJkSXz1q1+NHXfcMcrLy+Owww6LWbNmFfsc82bOnFnjFKdcLhdlZWXRq1evOPHEE+Oxxx5r0fl/9NFHcdttt8WwYcOie/fu0a5du+jatWsMHjw4brrppli/fn1+26FDh8ZOO+1UY/9DDjkkf+wvf/nLBZ9TMfPZuHFjTJo0KYYPHx477LBDtGvXLrp37x7HHHNMTJ8+vcHnXl1dHZdcckn06tUrSkpKYurUqQ2+5sW8Bs19vYt9fgAAbANZET796U9nEZFFRHb66adnGzZsyHbcccf8sssvv7zOPjfffHN+fbdu3bIvf/nL+ceb/91www019lu6dGm222671dmupKQkGzNmTI1ljTVjxoyCx970l8vlsttvv71F5r969eps8ODBWzzegQcemK1YsSLLsiwbMmTIFrc97bTTmjWftWvXZkcdddQWj/Gd73yn3ufetWvX7Ljjjqux/ZQpU7b4ehf7GqR+fgAApNfoT+/z5s2r8WFu+vTpWZZl2Te/+c38sj59+tTZb/MPlBGRDRw4MPvLX/6SvfPOO9nQoUPzy/v27Vtjv6997Wv5dZ06dcqmT5+erVy5MpsyZUpWXl7epACpbcOGDdlbb72VXXzxxTU+aFdXVzd7/meffXZ+XceOHbOpU6dmK1euzH73u99lXbt2za8744wz8vu88847NY41Z86cFns9v/3tb+fX7bTTTtmsWbOyNWvWZA8//HDWuXPn/Lp777233mPtueee2ZNPPpl9+OGHjXp9m/IapHx+AACk1+hP79/97nfzH+K6dOmS/5D+6KOP1vjA+NRTT9XYr/YHyueffz6/btKkSfnlJSUl2fr167Ms+1cYVFRU5NddeOGFNcY855xzWiRANlm7dm2N8Z555plmzb+6ujrr2LFjft1FF11U43hXXnllfl1paWm2atWqLMuaFiBNmc9tt91WY8wLLrggv27YsGH1Hmvz16UhTX0NUj4/AADSa9Q1IBs3boxf/epX+cdf/OIXo7S0NCIihgwZEjvuuGN+XaG7ZG1SVlYW+++/f/5x586d8///0UcfxYcffhgR/7od7cqVK/PrPvWpT9UY54ADDmjMtOtYt25d/OQnP4khQ4ZEjx49orS0NHK5XJSXl9fYbvHixc2a//z582P16tX5dZ/5zGdqjLP543Xr1sXrr7/epOfT1PmMGTOmxnUw1113XX7dSy+9VPBYpaWlMXDgwEbPrSVeg5TPDwCANBoVILNmzYqFCxfmH9955535D3clJSWxZMmS/Lp77rknqqurC47TsWPHGj8c2KZN2h9iP/744+P888+PJ554IpYuXVrnAuhN6lve2PlntS6Qrv1jibXXN9XWeD03/yC/uU6dOhU1fku8BimfHwAAaTTqE10xt9h9//33m33HoZ49e0ZFRUX+8fPPP19j/Z///Oeix1y4cGE8+OCD+cfjxo2L5cuXR5ZlsWzZsqZPtoDevXtHhw4d8o//+Mc/1li/+fMpLS2Nvn37RsTWC5XKysro2LFj/nFVVVVk/zr9rs7fBx980CLHbOpr0BRNfX7//Oc/a3xTsvktppu6DgCALWswQNauXRu//e1v849vvPHGgh/sPve5z+W32dJpWI1RUlISJ510Uv7xrbfeGg8++GCsXr067r///vjFL35R9Jjt2rWr8bhTp07Rvn37ePPNN+PrX/96s+ZbW2lpaZxxxhn5xzfffHNMmzYtVq9eHQ8//HCNU4JOOeWU/IfnioqKGv/KP3v27Pxtj5s7n9GjR+cfX3jhhfHAAw/EihUrYtWqVTFv3ryYPHlynHDCCTVurdzcYzblNWjqsVI/PwAAmqbBALnvvvtqnLby2c9+tuB2my+fMWNGs79VuOqqq6J3794REbFq1ao49thjo1OnTnHCCSfEqaeeWvR4PXv2jBEjRuQfX3TRRdG+ffvYbbfdolu3bs2aayFXX311DB48OCL+Nf8vfOEL0alTpxg+fHi89957ERFx4IEHxk9/+tP8Pu3bt4/DDjss//jiiy+Odu3aRS6Xi1/+8pfNms+Pf/zjOPLIIyPiX7+vctxxx0WXLl2ioqIi9tlnnzj11FPjvvvui7Vr1zbrOJtrymvQVNvi+QEAULwGA2Tz06/23nvvfBTUdswxx+T/f/369TF58uRmTWyHHXaIp59+OkaPHh3du3eP7bbbLg455JD43//93xohUYy77747Lrjggujdu3eUlZVFnz594uqrr44JEyY0a66FdOjQIR599NH4+c9/HkOHDo3tt98+SkpKokuXLjFo0KCYMGFCzJ49u8aF1RH/er1HjhwZ3bp1q3NKVnOUl5fH73//+6iqqooRI0ZEjx49om3bttGtW7fYd999Y9SoUTF16tQYO3Zsix2zqa9BU2yL5wcAQPFyWUtdaAAAANCAtLehAgAA/q0JEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMkIEAAAIBkBAgAAJCNAAACAZAQIAACQjAABAACSESAAAEAyAgQAAEhGgAAAAMn8f/UJoLKcA9xPAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.core.display import Image\n",
    "Image(\"shot1.png\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "261f7331",
   "metadata": {},
   "source": [
    "Looks like that second table wasn't loaded yet.  But if we wait a few seconds, it will be."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "619801f5",
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "time.sleep(3) # in seconds"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "c1aea4b6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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6a677tK6des8rql79+5q0qSJU1unTp0c4/7hD38wbc6ysjI999xzstvtuuyyy9SuXTvNnDnT41rPM+v7AAAAwCXK8MDatWsNSY7X0qVLXY6ZNm2a0zHffPONY19xcbHRs2dPp/0VX08++aTTeDNnznTsi4qKMvr37+9Sgy/jVubBBx+86Di9e/f2aJwVK1ZcdBybzWa8+eabHo3VrVu3i441aNAgn+e88PONjo427r77brd9R48efdF+FzLz+wAAAMClyacA4snrwgDyxBNPONqbNGlirF271igqKjJWrVpl1K9f37Hv7bffdvS58IeuJKNNmzbGp59+apw5c6Za41YmNDTUkGQEBAQY69evN0pKSoz9+/cbn3zyiZGammoMGTLEm8/VoayszPjpp5+McePGOQWqkpISj/ofOHDA6XPYuHGjKXNW/Hy7du1q/PDDD8aRI0eMkSNHOu3Lyclx269iADHz+wAAAMClye8BpKSkxKhXr56jffbs2U5jjxkzxrEvJSXF0V7xB/KmTZuc+vk6bmViYmIMSUadOnWMOXPmGN9//71x9uxZTz4ejxQXF1/0/VTGlwDiyZwVP9/c3FzHvpKSEiM2NtaxLzU11W2/CwOI2d8HAAAALk0+rQFZunSpjF/Ci+M1bdo0t8fu2bNHp06dcmyPGDHCaa3Cq6++6ti3detWt2MEBwcrMTHR9HEvNGzYMEm/rGEYPny4rrrqKoWGhqpdu3YaNWqU8vLyqhxDks6ePat//OMf6tatm2JjYxUcHCybzabQ0FCn4w4ePOjReFbMGRISorZt2zq2g4ODnba/++67Kmsw+/sAAADApSmwpgu40IU/YC8UHh6uOnV8Xy9f2bgXevnll9WmTRstWbJEX331lQ4fPqyysjJt375d27dv17vvvqutW7cqKirqouPccccd+uCDD6qcr7S01OP6q1ITc1aHJ98HAAAALk1+vwuW3W5XvXr1HNvp6ekuZ0/Ov06fPl1j49apU0fDhw/XypUrdejQIZ08eVLr169XbGysJGnfvn365JNPLjrG3r17nYLAhAkTdPz4cRmGoaNHj3r83i5ks9mctg3DMH3OkpIS7dixw7F99uxZbd++3bF91VVXVTmGv75nAAAAXFr8HkCCg4MdlzdJ0tixY7Vs2TIVFBTo5MmT2rFjhzIyMnTnnXfqX//6V42N26dP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AAAAWIYAAgAAAMAyBBAAAAAAliGAAAAAALAMAQQAAACAZQggAAAAACxDAAEAAABgGQIIAAAAAMsQQAAAAABYhgACAAAAwDIEEAAAAACWIYAAAAAAsAwBBAAAAIBlCCAAAAAALEMAAQAAAGAZAggAAAAAyxBAAAAAAFjG6wBSUlKiBg0ayGazOV733HOPP2qr1DsDcLoBAAAgAElEQVTvvOM0//+S119/3fG+Y2JiarocAAAAwCteB5Bly5bp559/rrIN3jt48KBTsNq0aVNNlwQAAACYyusAsmDBApe2kpISLVmyxJSCAAAAAFy6vAogR44c0cqVKx3brVq1cvw/PT3dvKoAAAAAXJK8CiAZGRkqKyuTJNWvX1//+te/HPuys7P1448/uvSpuGahvLxckydP1pVXXqmwsDAlJCTotddek2EYLn0PHTqkBx54QI0aNVJoaKi6dOmitWvXevseHVauXOl0iZPNZlNISIji4uJ01113ad26dabWf+7cOc2ePVspKSmKiYlRUFCQoqKilJycrNdee02lpaWOY7t3764mTZo49e/UqZNj7j/84Q9u35M39ZSXl2vBggXq1auXGjZsqKCgIMXExKhv377Kysqq8r2XlJTo6aefVlxcnAICApSZmVnlZ+7NZ1Ddz9vb9wcAAIAaYHjht7/9rSHJkGQMHjzYKCsrMxo1auRoe+6551z6zJw507E/Ojra+MMf/uDYvvA1bdo0p35HjhwxWrRo4XJcQECAMWLECKc2T61YscLt3OdfNpvNePPNN02p/9SpU0ZycvJF5+vQoYNRUFBgGIZhdOvW7aLHDho0qFr1FBcXGz179rzoHE8++WSl7z0qKsro37+/0/FLly696Oft7Wdg9fsDAACA9Tz+9b5jxw6nH3NZWVmGYRjGo48+6mhr2bKlS78Lf1BKMhITE41vv/3WOHDggNG9e3dHe3x8vFO/Bx980LEvPDzcyMrKMgoLC42lS5caoaGhPgWQisrKyoyffvrJGDdunNMP7ZKSkmrXP3LkSMe+evXqGZmZmUZhYaHxn//8x4iKinLsGzp0qKPPgQMHnObauHGjaZ/nE0884djXpEkTY+3atUZRUZGxatUqo379+o59b7/9dqVztWnTxvj000+NM2fOePT5+vIZWPn+AAAAYD2Pf73/+c9/dvyIi4yMdPxIX7NmjdMPxg0b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efPmdHV1pbOzM2ed1doh3H///Ul8+wMAAN6Omn4L1sDAQEaOHHnKucmTJydJ5s+fn66uriRJrVbL7t27s379+syfPz9Hjx7NJZdckvvuuy9Lly5tWU7y38u6HnjggcyaNStTpkxp9tEAAICKNF1A2trahryPo729PVu2bMmWLVsqzanVaunt7R12BgAAUEblS7AAAABepYAAAADFKCAAAEAxCggAAFDMsDah1+v1dHZ2VjWW4jkAAEBZwyog//uVt1UqlQMAAJRlCRYAAFDMsGZApk2bVtU4Uq/XT858lMoBAADKGvaHCPfv31/FOE7b81EqBwAAKMcSLAAAoBgFBAAAKEYBAQAAimm6gAwODqa7uzsrVqxIe3t7arVaent7z3jtj370o8yZMyfjx49Pe3t7pk+fnp07d7Y85yc/+Uk6OjoyevTojBs3LkuWLMmhQ4eafUQAAKDFmi4gPT092bBhQzo6OrJ27drXvW7u3Lm54IILcuDAgRw6dCiLFi3KJz7xiezYsaNlOU899VSuvfbaTJ06Nb29vdm3b18OHz6cq6++Ov/4xz+aekYAAKC1mi4gM2bMSHd3d1auXJn29vbXvO7b3/52Tpw4kS1btmTChAl517velfXr1+eyyy7LAw880LKczs7OTJw4MZs3b855552XCy+8MDt27EhfX1+2bNnS1DMCAACtVfkekLa2ttRqtdPONxqNtLUN+y3Ar+lXv/pVPvzhD59yz4kTJ6Zer2fXrl0tywEAAJpXeQG59dZbM378+Nx+++3561//mhdffDEbN25MX19f1q1b17KcRqPxmkXnmWeeaVkOAADQvNZNQbyGyZMn5/vf/34WL16cbdu2JUlGjx6dbdu25aqrrmpZzgc+8IH09PTkxIkTGTFiRJKkv78/fX19GRgYyPHjx3P22We3LA8AABi+ymdA9u7dm2uuuSYLFy5Mf39/jhw5krvvvjs33nhjtm/f3rKcz33uc+nt7c2dd96Zw4cP509/+lOWL19+8t/POssbhwEA4K1W+f/Kv/SlL+U973lPtmzZkvPPPz/jxo3LmjVrMn/+/Nd9q9VwzZs3L7t27covfvGLTJw4MVdccUXe//73Z9myZRk3blxGjRrVsiwAAKA5lS/B+v3vf5+pU6eeNgNx+eWX55FHHsnf//73jB07tiVZCxcuzMKFC085N2PGjMyaNasl9wcAAN6cygvIpEmT8uyzz2ZwcPCUEvLMM8+kvb39dV+t+2Y9/fTT6enpyQ9+8IPKMgAAgKGrfAnWqlWr8txzz2XVqlX5y1/+kqNHj+Yb3/hGHnnkkdx5550t25vR09OTdevW5bnnnsu///3vPP7441m4cGE++clPZt68eS3JAAAA3pymZ0AGBgYycuTIU85Nnjw5STJ//vx0dXUlSW644YY8+uij2bhxY6ZOnZpXXnklU6ZMyb333psVK1a0LOeDH/xg9u7dm+uuuy59fX25+OKL85nPfCa33nprs48IAAC0WNMFpK2tLY1GY0jXzp07N3Pnzq00p62tLatXr87q1aubygEAAKrn3bQAAEAxCggAAFCMAgIAABSjgAAAAMUMaxN6vV5PZ2dnVWMpngMAAJQ1rALy6itvq1YqBwAAKMsSLAAAoJg3nAH57W9/m2nTppUYCwAA8B+u1hjq1wQBAADeJEuwAACAYhQQAACgGAUEAAAoRgEBAACKUUAAAIBiFBAAAKAYBQQAAChGAQEAAIpRQAAAgGIUEAAAoBgFBAAAKEYBAQAAilFAAACAYhQQAACgGAUEAAAoRgEBAACKUUAAAIBiFBAAAKAYBQQAAChGAQEAAIpRQAAAgGIUEAAAoBgFBAAAKEYBAQAAilFAAACAYhQQAACgGAUEAAAoRgEBAACKUUAAAIBiFBAAAKAYBQQAAChGAQEAAIpRQAAAgGIUEAAAoBgFBAAAKEYBAQAAilFAAACAYhQQAACgGAUEAAAoRgEBAACKUUAAAIBiFBAAAKAYBQQAAChGAQEAAIpRQAAAgGIUEAAAoBgFBAAAKEYBAQAAilFAAACAYhQQAACgGAUEAAAoRgEBAACKUUAAAIBiFBAAAKAYBQQAAChGAQEAAIpRQAAAgGIUEAAAoBgFBAAAKEYBAQAAilFAAACAYhQQAACgGAUEAAAoRgEBAACKUUAAAIBiFBAAAKAYBQQAAChGAQEAAIpRQAAAgGIUEAAAoBgFBAAAKEYBAQAAilFAAACAYhQQAACgGAUEAAAo5r8A30qLTGVd5QwAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b.save_screenshot(\"shot2.png\")\n",
    "Image(\"shot2.png\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eb57d51b",
   "metadata": {},
   "source": [
    "Here's what happened in the browser:\n",
    "1. Chrome converted HTML tags to elements in the DOM (Document Object Model)\n",
    "2. JavaScript added some elements to the DOM (for the second table)\n",
    "3. the new version with both tables got shown\n",
    "\n",
    "Selenium's `.page_source` element lets us convert the new version back to HTML (notice there are two `<table>`'s instead of the original one -- `requests` could only see the first one, but Selenium also sees the one generated by the JavaScript code)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "f72bb34f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<html><head>\n",
      "    <script src=\"https://code.jquery.com/jquery-3.4.1.js\"></script>\n",
      "    <script>\n",
      "      function addTable() {\n",
      "        var html = \"<table border=1 id='coords'>\\n\";\n",
      "        html += \"<tr><td>x</td><td>y</td></tr>\\n\";\n",
      "        for (i = 0; i < 10; i++) {\n",
      "          html += \"<tr><td>\" + (i*2) + \"</td><td>\" + (i*2+1) + \"</td></tr>\\n\";\n",
      "        }\n",
      "        html += \"</table>\";\n",
      "\n",
      "        var t = document.createElement(\"div\");\n",
      "        t.innerHTML = html;\n",
      "        document.body.appendChild(t);\n",
      "      }\n",
      "      \n",
      "      function main() {\n",
      "        setTimeout(addTable, 1000)\n",
      "      }\n",
      "      </script>\n",
      "  </head>\n",
      "  <body onload=\"main()\">\n",
      "    <h1>Welcome</h1>\n",
      "    <h3>Here's a table</h3>\n",
      "    <table border=\"1\" id=\"alpha\">\n",
      "      <tbody><tr><td>A</td><td>B</td><td>C</td></tr>\n",
      "      <tr><td>1</td><td>2</td><td>3</td></tr>\n",
      "      <tr><td>4</td><td>5</td><td>6</td></tr>\n",
      "    </tbody></table>\n",
      "\n",
      "    <h3>And another one...</h3>\n",
      "  \n",
      "\n",
      "<div><table border=\"1\" id=\"coords\">\n",
      "<tbody><tr><td>x</td><td>y</td></tr>\n",
      "<tr><td>0</td><td>1</td></tr>\n",
      "<tr><td>2</td><td>3</td></tr>\n",
      "<tr><td>4</td><td>5</td></tr>\n",
      "<tr><td>6</td><td>7</td></tr>\n",
      "<tr><td>8</td><td>9</td></tr>\n",
      "<tr><td>10</td><td>11</td></tr>\n",
      "<tr><td>12</td><td>13</td></tr>\n",
      "<tr><td>14</td><td>15</td></tr>\n",
      "<tr><td>16</td><td>17</td></tr>\n",
      "<tr><td>18</td><td>19</td></tr>\n",
      "</tbody></table></div></body></html>\n"
     ]
    }
   ],
   "source": [
    "print(b.page_source)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a299f1fb",
   "metadata": {},
   "source": [
    "One option would be to used this updated HTML string with BeautifulSoup to search for tables and data:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "a7baf446",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "There are 2 table(s)\n"
     ]
    }
   ],
   "source": [
    "doc = BeautifulSoup(b.page_source)\n",
    "tables = doc.findAll(\"table\")\n",
    "print(f\"There are {len(tables)} table(s)\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a0e4b75",
   "metadata": {},
   "source": [
    "Alternatively, Selenium has a (somewhat clunkier) interface for directly searching for elements:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "f9d2b214",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "There are 2 table(s)\n"
     ]
    }
   ],
   "source": [
    "tables = b.find_elements_by_tag_name(\"table\")\n",
    "print(f\"There are {len(tables)} table(s)\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6e28ed79",
   "metadata": {},
   "source": [
    "Instead of BeautifulSoup `Tag` objects, we get Selenium `WebElement` objects.  Fortunately, both have a `.text` attribute to see the raw data (without surrounding HTML tags):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "91241793",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "selenium.webdriver.remote.webelement.WebElement"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "type(tables[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "d881a8d6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A B C\n",
      "1 2 3\n",
      "4 5 6\n"
     ]
    }
   ],
   "source": [
    "print(tables[0].text)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f203ab87",
   "metadata": {},
   "source": [
    "## Conclusion\n",
    "\n",
    "A web browser like Chrome understands both HTML and JavaScript (and is able to run JavaScript that may update the elements corresponding to HTML tags).  For simple pages, the `requests` module is great way to fetch HTML and other resources, without any JavaScript engine.  `requests` does not parse HTML, so it is often used in conjunction with BeautifulSoup (which can parse an HTML document to a searchable tree structure).\n",
    "\n",
    "Selenium is much slower than `requests`, but it is able to control a real web browser (capable of executing JavaScript), so it allows data scientists to scrape many pages that would not be scrapable otherwise.  Selenium also provides a searchable tree of elements, like BeautifulSoup, but the methods tend to be less convenient, so one may choose to still use BeautifulSoup with Selenium (though it's less necessary than when working with `requests`)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "002c3ca4",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
