{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Online Data\n", "\n", "The internet is probably the most common place to seek information. In fact, every homepage you browse and every article you read is data and, as long as there is no pay wall or other security feature, free to you. Most of the data in such form is unordered and cannot easily be analysed quantitatively, like text or video clips (especially text usually does carry a lot of information). Beside this unstructured data, there are files for free to download, e.g. in a .csv format. Yet, all this has to be done by hand: either click some 'download' button to acquire a file or, even worse, copy a text online and paste it into a document.\n", "\n", "In the next sections, we will at first briefly introduce some basic elements of online communication and then present different ways to access data online from our computer without loading and storing it manually (we will write code manually, though).\n", "\n", "## Website basics \n", "\n", "### HTTP \n", "\n", "The **H**yper**T**ext **T**ransfer **P**rotocol is used for online communication in the world wide web (www). The basic operations are *requests* and *response*. In the www, when trying to open a website, you are actually sending a request to a server asking to provide the information stored under that web address. The server will then hopefully respond to your request by sending the respective information to your machine which then will be rendered in your browser. This response information does contain additional meta data, like the time of the request, status/error codes, etc which we will see later. An extension is **https** (**s**ecure).\n", "\n", "### URL\n", "\n", "The **U**niform **R**esource **L**ocator is the address your request is telling the server to look for information. It consists of several elements, ```http://www.uni-passau.de```:\n", "\n", "- the protocol: usually ```http``` or ```https``` in the www, followed by a colon and doube slash ```://```\n", "\n", "- the hostname: ```www.uni-passau.de``` \n", "\n", "- a path/query: appended with ```/``` or ```?``` to the hostname\n", "\n", "To know about these three separate parts enables us to automate navigation in the www using python.\n", "\n", "### HTML\n", "\n", "Information in the www is usually found in the **H**yper**T**ext **M**arkup **L**anguage for web browsers. HTML uses **tags** to structure hierarchical data, telling the browser how to display the single elements. Tags appear in pairs and are enclosed in angle brackets `````` to open a respective section and `````` to close it.\\\n", "Any HTML will be enclosed in the most outer `````` and `````` tags. Inside this, the document is structured by various tags. To name just some: \n", "\n", "- ``````: the main part of a website containing the displayed information\n", "\n", "- ```
```: division, denotes a section\n", "\n", "- ```

```: paragraph, simple text information\n", "\n", "- ``````: displays data in a table, (`````` for single rows)\n", "\n", "- ``````: bold, does not structure the page, but alters the font \n", "\n", "Beside the tag itself attributes may be included inside the brackets. With the right tools, we can exploit tags and attributes to navigate to specific elements on webpages in order to extract the element information. Very common attributes are ```id``` and ```class```. \n", "\n", "A simple html may look like this (inside \"\"\" and indented):" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"\\n\\n \\n
\\n

\\n This is a brief introduction to HTML.\\n

\\n
\\n \\n\\n\"" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"\"\"\n", "\n", " \n", "
\n", "

\n", " This is a brief introduction to HTML.\n", "

\n", "
\n", " \n", "\n", "\"\"\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Since jupyter works with html, we can render the above html directly in a markdown cell: " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " \n", " \n", "
\n", "

\n", " This is a brief introduction to HTML. \n", "

\n", "
\n", " \n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### JSON\n", "\n", "The **J**ava**S**cript **O**bject **N**otation is a type of data format which you will frequently encounter when working with online data. For one, websites that offer a .scv download often also offer a .json file to download. Moreover, the json format is often used by APIs (see next secrtion) to transfer data. Its structure looks is very similar to a python dictionary, using curly and square brackets and key-value pairs as well as enabling nesting. Data is therefore stored in such objects. There are packages which can handle json files, for example pandas to transform it into a dataframe. \n", "\n", "Let's see what a dataframe looks like when transformed into a json format:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "
\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
lengthheight
obj_11955
obj_22264
\n", "

" ], "text/plain": [ " length height\n", "obj_1 19 55\n", "obj_2 22 64" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import pandas as pd\n", "\n", "df = pd.DataFrame([[19, 55], [22, 64]],\n", "index=[\"obj_1\", \"obj_2\"],\n", "columns=[\"length\", \"height\"])\n", "df" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And the respective json format, created with the ```to_json()``` method:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{\"length\":{\"obj_1\":19,\"obj_2\":22},\"height\":{\"obj_1\":55,\"obj_2\":64}}\n" ] } ], "source": [ "print(df.to_json()) " ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
lengthheight
obj_11955
obj_22264
\n", "
" ], "text/plain": [ " length height\n", "obj_1 19 55\n", "obj_2 22 64" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# back to dataframe with read_json()\n", "pd.read_json(df.to_json())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## API\n", "\n", "Instead of (or in addition to) any downloadable files, data providers may offer an **API** (**A**pplication **P**rogramming **I**nterface) to access data. An API constitutes a rather convenient way to getting information as it allows direct machine to machine transaction - meaning you can log in, select and download data directly with and into python. With reliable API access, it is thus not necessary to store the data on your hard drive permanently (you must however do so temporarily). \\\n", "The two most basic operations when working with an API over http:\n", "\n", "- GET: send a request and *get* a response from the server, for example the data you asked for\n", "\n", "- POST: send information to the API, for example to add data to a database remotely\n", "\n", "Many large companies offer APIs for programmers, for example the google maps API is often used on web pages where directions are explained or Twitter offers an API where tweets and meta data are provided. These APIs usually are not free. However, free APIs do exist for many topics of data, [see here](https://github.com/public-apis/public-apis/blob/master/README.md) for example . \\\n", "Normally, the procedure is to register an e-mail account to get an **identification key**. This key is needed to use the API from your computer and enables the provider to track your activity. For example, if only *n* downloads are free per day, too unrestrained a downloading business might even get you kicked or banned. In any case, to work properly with an API, one should read the documentary (or at least parts of it).\n", "\n", "In general, we will use the [```requests```](https://requests.readthedocs.io/en/master/) package for working with APIs.\n", "\n", "For a first and simpler example, though, we can make use of a package called [```wikipediaapi```](https://pypi.org/project/Wikipedia-API/) implementing the [Wikipedia API](https://www.mediawiki.org/wiki/API:Main_page). Whenever working with APIs, it is advised to look for trustworthy implementations, since the work might have been done for you already. We will then go on to produce the same result using the requests package.\n", "\n", "As usual, the first step is to import the packages (if already installed)." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "import wikipediaapi" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "# instantiate object and call page method\n", "wiki_en = wikipediaapi.Wikipedia('en')\n", "page = wiki_en.page('University_of_Passau') " ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "title:\n", " University_of_Passau\n", "\n", "summary:\n", " The University of Passau (Universität Passau in German) is a public research university located in Passau, Lower Bavaria, Germany. Founded in 1973, it is the youngest university in Bavaria and consequently has the most modern campus in the state. Nevertheless, its roots as the Institute for Catholic Studies dates back to the early 17th century.\n", "Today it is home to four faculties and 39 different undergraduate and postgraduate degree programmes.\n" ] } ], "source": [ "print('title:\\n', page.title)\n", "print('\\nsummary:\\n',page.summary)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The API from the ```wikipediaapi``` package returns preprocessed data from the respective article.\n", "\n", "\n", "Since APIs may come without such handy packages, we will now engage the ```requests```package to perform the same tasks.\\\n", "At first, we import the package under the alias ```re```." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "import requests as re" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "wiki_url = 'https://en.wikipedia.org/w/api.php'\n", "\n", "# store parameters as dictionary to pass to function, may include key and username for authentication \n", "# the parameters are found in the documentary!\n", "params = {'action': 'query',\n", " 'format': 'json',\n", " 'titles': 'University_of_Passau',\n", " 'prop': 'extracts',\n", " 'exintro': 1,\n", " 'disablelimitreport':1}\n", "\n", "response = re.get(wiki_url, params=params)\n", "print(type(response))" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "200" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# check, if request was successful\n", "response.status_code # -> 200 " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Having a successful request, we can now take a look at the response object's elements. Since the format was specified as json in our request, we can use the built-in ```.json()``` method.\\\n", "To display a json file in a more readbale manner (indents, linebreaks), we can use the ```json``` package and its ```dumps```method." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "import json" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{\n", " \"batchcomplete\": \"\",\n", " \"warnings\": {\n", " \"main\": {\n", " \"*\": \"Unrecognized parameter: disablelimitreport.\"\n", " },\n", " \"extracts\": {\n", " \"*\": \"HTML may be malformed and/or unbalanced and may omit inline images. Use at your own risk. Known problems are listed at https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TextExtracts#Caveats.\"\n", " }\n", " },\n", " \"query\": {\n", " \"normalized\": [\n", " {\n", " \"from\": \"University_of_Passau\",\n", " \"to\": \"University of Passau\"\n", " }\n", " ],\n", " \"pages\": {\n", " \"409091\": {\n", " \"pageid\": 409091,\n", " \"ns\": 0,\n", " \"title\": \"University of Passau\",\n", " \"extract\": \"

The University of Passau (Universit\\u00e4t Passau in German) is a public research university located in Passau, Lower Bavaria, Germany. Founded in 1973, it is the youngest university in Bavaria and consequently has the most modern campus in the state. Nevertheless, its roots as the Institute for Catholic Studies dates back to the early 17th century.\\n

Today it is home to four faculties and 39 different undergraduate and postgraduate degree programmes.

\"\n", " }\n", " }\n", " }\n", "}\n" ] } ], "source": [ "print(json.dumps(response.json(), indent=4))" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "title: University of Passau\n", "\n", "summary:

The University of Passau (Universität Passau in German) is a public research university located in Passau, Lower Bavaria, Germany. Founded in 1973, it is the youngest university in Bavaria and consequently has the most modern campus in the state. Nevertheless, its roots as the Institute for Catholic Studies dates back to the early 17th century.\n", "

Today it is home to four faculties and 39 different undergraduate and postgraduate degree programmes.

\n" ] } ], "source": [ "# we can now navigate through the nested dictionaries\n", "title = response.json()['query']['pages']['409091']['title']\n", "print('title: ',title)\n", "summary = response.json()['query']['pages']['409091']['extract']\n", "print('\\nsummary:', summary)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Since the Text is still in html, as can be seen from tags, we are not yet finished. To convert html to normal text, one way is by using [**BeautifulSoup**.](https://pypi.org/project/beautifulsoup4/)\\\n", "Let's import it from the ```bs4``` package and transform the html." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The University of Passau (Universität Passau in German) is a public research university located in Passau, Lower Bavaria, Germany. Founded in 1973, it is the youngest university in Bavaria and consequently has the most modern campus in the state. Nevertheless, its roots as the Institute for Catholic Studies dates back to the early 17th century.\n", "Today it is home to four faculties and 39 different undergraduate and postgraduate degree programmes.\n" ] } ], "source": [ "from bs4 import BeautifulSoup\n", "\n", "# first instantiate object, use 'lxml' parser (installation necessary) \n", "my_soup = BeautifulSoup(summary, 'lxml')\n", "\n", "# extract the text, i.e. remove tags\n", "print(my_soup.text)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Website content\n", "BeautifulSoup can not only extract text from html, but, in analogy to the json ```dumps()``` method from before, print html files more readable. We will leverage BeautifulSoup's functions now to extract again the same information, but now from the website directly, i.e. without an API.\n" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "# first, send request - get response from ordinary url\n", "response = re.get('https://en.wikipedia.org/wiki/University_of_Passau')\n", "\n", "# second, extract content from the response (html)\n", "html = response.content\n", "\n", "# third, instantiate BS onject\n", "soup = BeautifulSoup(html)\n", "\n", "# if necessary look at a formatted version of the html\n", "# print(soup.prettify()) # -> very long output" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "The University of Passau (Universität Passau in German) is a public research university located in Passau, Lower Bavaria, Germany. Founded in 1973, it is the youngest university in Bavaria and consequently has the most modern campus in the state. Nevertheless, its roots as the Institute for Catholic Studies dates back to the early 17th century.\n", "Today it is home to four faculties and 39 different undergraduate and postgraduate degree programmes.\n" ] } ], "source": [ "# finally print the text attribute from the created object\n", "print(soup.text[588:1037]) # only part of document for shorter output " ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'The University of Passau (Universität Passau in German) is a public research university located in Passau, Lower Bavaria, Germany. Founded in 1973, it is the youngest university in Bavaria and consequently has the most modern campus in the state. Nevertheless, its roots as the Institute for Catholic Studies dates back to the early 17th century.\\n'" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "soup.find('p').getText()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can see, that we loaded the whole website as raw text. One can immediately see that it is not obvious how to extract the wanted summary only. We will later see some ways to extract text and leverage repeated structure across a website for its different pages to extract text sections like this." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Back to APIs\n", "\n", "Now, the API we will mostly use in this course is from [financialmodelingprep.com](https://financialmodelingprep.com/developer/docs/), providing financial and company data. In contrast to the Wikipedia API, a registration by e-mail is required. Please register to get your API key.\n", "\n", "To access the data, the key must be submitted in the request. We can use the params statement as before, handing it the respective statements.\n", "\n", "(Note that the API key is already saved in \"api_key\")" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "tags": [ "remove-cell" ] }, "outputs": [], "source": [ "api_key = 'my_key'\n", "api_key = '44c50c7a71efa92e8dac68f5902ea0ec'" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "# define components of the request\n", "base_url = 'https://financialmodelingprep.com/api/v3/'\n", "filing = 'profile'\n", "stock = 'GOOG'\n", "params = {'apikey': api_key}\n", "\n", "# send request and store reponse\n", "response = re.get(base_url+filing+'/'+stock, params=params)" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[{'symbol': 'GOOG',\n", " 'price': 101.38,\n", " 'beta': 1.099484,\n", " 'volAvg': 23226134,\n", " 'mktCap': 1316794269696,\n", " 'lastDiv': 0.0,\n", " 'range': '95.27-152.1',\n", " 'changes': -0.01000214,\n", " 'companyName': 'Alphabet Inc.',\n", " 'currency': 'USD',\n", " 'cik': '0001652044',\n", " 'isin': 'US02079K1079',\n", " 'cusip': '02079K107',\n", " 'exchange': 'NASDAQ Global Select',\n", " 'exchangeShortName': 'NASDAQ',\n", " 'industry': 'Internet Content & Information',\n", " 'website': 'https://www.abc.xyz',\n", " 'description': 'Alphabet Inc. provides various products and platforms in the United States, Europe, the Middle East, Africa, the Asia-Pacific, Canada, and Latin America. It operates through Google Services, Google Cloud, and Other Bets segments. The Google Services segment offers products and services, including ads, Android, Chrome, hardware, Gmail, Google Drive, Google Maps, Google Photos, Google Play, Search, and YouTube. It is also involved in the sale of apps and in-app purchases and digital content in the Google Play store; and Fitbit wearable devices, Google Nest home products, Pixel phones, and other devices, as well as in the provision of YouTube non-advertising services. The Google Cloud segment offers infrastructure, platform, and other services; Google Workspace that include cloud-based collaboration tools for enterprises, such as Gmail, Docs, Drive, Calendar, and Meet; and other services for enterprise customers. The Other Bets segment sells health technology and internet services. The company was founded in 1998 and is headquartered in Mountain View, California.',\n", " 'ceo': 'Mr. Sundar Pichai',\n", " 'sector': 'Communication Services',\n", " 'country': 'US',\n", " 'fullTimeEmployees': '174014',\n", " 'phone': '650-253-0000',\n", " 'address': '1600 Amphitheatre Parkway',\n", " 'city': 'Mountain View',\n", " 'state': 'CA',\n", " 'zip': '94043',\n", " 'dcfDiff': 30.96,\n", " 'dcf': 132.35,\n", " 'image': 'https://financialmodelingprep.com/image-stock/GOOG.png',\n", " 'ipoDate': '2004-08-19',\n", " 'defaultImage': False,\n", " 'isEtf': False,\n", " 'isActivelyTrading': True,\n", " 'isAdr': False,\n", " 'isFund': False}]" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Without further processing, the json is already quite well structured to read\n", "response.json()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also load symbols from all companies listed in the Dow Jones Index and then load historical stock price data from those companies using the afore acquired symbols." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "200\n" ] } ], "source": [ "filing = 'dowjones_constituent'\n", "response = re.get(base_url+filing, params=params)\n", "print(response.status_code)" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " symbol name sector \\\n", "0 CRM Salesforce.Com Inc Technology \n", "1 WBA Walgreens Boots Alliance Inc Healthcare \n", "2 V Visa Inc Financial Services \n", "\n", " subSector headQuarter dateFirstAdded cik \\\n", "0 Technology San Francisco, CALIFORNIA 2020-08-31 0001108524 \n", "1 Healthcare Deerfield, ILLINOIS 2018-06-26 0001618921 \n", "2 Financial Services San Francisco, CALIFORNIA 2013-09-23 0001403161 \n", "\n", " founded \n", "0 2004-06-23 \n", "1 2014-12-31 \n", "2 2008-03-19 \n" ] } ], "source": [ "dji_df = pd.DataFrame.from_dict(response.json())\n", "print(dji_df.head(3))" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['CRM', 'WBA', 'V', 'NKE', 'UNH', 'TRV', 'VZ', 'INTC', 'WMT', 'JNJ', 'DIS', 'MCD', 'JPM', 'CAT', 'BA', 'AMGN', 'DOW', 'AAPL', 'GS', 'CSCO', 'MSFT', 'HD', 'PG', 'MRK', 'IBM', 'HON', 'KO', 'CVX', 'AXP', 'MMM']\n" ] } ], "source": [ "# extract symbol column and convert to list\n", "dji_symbols = dji_df.symbol.tolist()\n", "print(dji_symbols)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "# set the filing (from documentation)\n", "filing = 'historical-price-full'\n", "\n", "# create empty dataframe (before loop!) to collect data for every company in loop\n", "dji_hist = pd.DataFrame()\n", "\n", "# loop over first 5 symbols in the list\n", "for symbol in dji_symbols[:5]:\n", " \n", " # request data for every symbol \n", " response = re.get(base_url+filing+'/'+symbol, params=params)\n", " # break the loop if a response error occurs\n", " if response.status_code != 200:\n", " print('Error! Aborted')\n", " break\n", " # convert the response to json to temporary dataframe\n", " temp_df = pd.DataFrame.from_dict(response.json()['historical'], orient='columns')\n", " # add column with respective symbol\n", " temp_df['symbol'] = symbol\n", " # append temporary dataframe to collect dataframe \n", " dji_hist = pd.concat([dji_hist, temp_df], ignore_index=True)\n", " # delete temporary dataframe before next iteration\n", " del temp_df" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "AxesSubplot(0.125,0.11;0.775x0.77)\n" ] }, { "data": { "image/png": "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NmyYxo4dqwULFmjz5s0aMGCAYmNj1adPH0lSmzZt1LNnTw0ZMkTr1q3T6tWrlZWVpX79+ik2NlaSdOeddyo4OFgZGRnaunWr5s6dq6lTp2r48OH+fkgAAKAW8vvLVS+88IL+8pe/6MEHH1RZWZliY2N13333KTs7214zcuRIHTlyREOHDlV5ebmuvfZa5eXlKTQ01F4ze/ZsZWVl6frrr1dgYKD69u2rnJwce394eLiWLFmizMxMtW/fXs2bN1d2drbPuXQAAEDd5ffz5NQmnCcHcA7nyQHwazl2nhwAAICagMgBAABGInIAAICRiBwAAGAkIgcAABiJyAEAAEYicgAAgJGIHAAAYCQiBwAAGInIAQAARiJyAACAkYgcAABgJCIHAAAYicgBAABGInIAAICRiBwAAGAkIgcAABiJyAEAAEYicgAAgJGIHAAAYCQiBwAAGInIAQAARiJyAACAkYgcAABgJCIHAAAYicgBAABGInIAAICRiBwAAGAkIgcAABiJyAEAAEYicgAAgJGIHAAAYCQiBwAAGInIAQAARiJyAACAkYgcAABgJCIHAAAYicgBAABGInIAAICRiBwAAGAkIgcAABiJyAEAAEYicgAAgJGIHAAAYCQiBwAAGInIAQAARiJyAACAkYgcAABgJCIHAAAYicgBAABGInIAAICRiBwAAGAkIgcAABiJyAEAAEYicgAAgJGIHAAAYCQiBwAAGInIAQAARiJyAACAkYgcAABgpCqJnG+++UZ33XWXmjVrprCwMCUmJmrDhg32fsuylJ2drZiYGIWFhSklJUWff/65z20cOHBA6enpcrlcioiIUEZGhg4fPuyz5tNPP1WXLl0UGhqquLg4TZgwoSoeDgAAqIX8HjkHDx5U586dVb9+fX300Uf67LPPNGnSJDVp0sReM2HCBOXk5GjGjBkqLi5Ww4YNlZqaqmPHjtlr0tPTtXXrVuXn52vhwoUqLCzU0KFD7f1er1c9evRQixYtVFJSookTJ2rMmDF65ZVX/P2QAABALRRgWZblzxscNWqUVq9erZUrV551v2VZio2N1WOPPabHH39ckuTxeBQVFaXc3Fz169dP27ZtU0JCgtavX68OHTpIkvLy8nTDDTfo66+/VmxsrKZPn64///nPcrvdCg4Otu/7vffe0/bt289pVq/Xq/DwcHk8HrlcLj88egDnquWoRU6P8Jt9+Vya0yMAddK5/v72+5GcBQsWqEOHDrrtttsUGRmpK6+8Uq+++qq9f/fu3XK73UpJSbG3hYeHq2PHjioqKpIkFRUVKSIiwg4cSUpJSVFgYKCKi4vtNV27drUDR5JSU1O1Y8cOHTx48KyzHT9+XF6v1+cCAADM5PfI+eKLLzR9+nRdcsklWrx4sR544AE9/PDDmjVrliTJ7XZLkqKionx+Lioqyt7ndrsVGRnps79evXpq2rSpz5qz3caZ9/FD48aNU3h4uH2Ji4v7jY8WAADUVH6PnIqKCl111VV69tlndeWVV2ro0KEaMmSIZsyY4e+7+sVGjx4tj8djX/bu3ev0SAAAoIr4PXJiYmKUkJDgs61Nmzbas2ePJCk6OlqSVFpa6rOmtLTU3hcdHa2ysjKf/adOndKBAwd81pztNs68jx8KCQmRy+XyuQAAADP5PXI6d+6sHTt2+GzbuXOnWrRoIUmKj49XdHS0li5dau/3er0qLi5WUlKSJCkpKUnl5eUqKSmx1yxbtkwVFRXq2LGjvaawsFAnT5601+Tn56tVq1Y+n+QCAAB1k98j59FHH9XatWv17LPPateuXZozZ45eeeUVZWZmSpICAgI0bNgwjR07VgsWLNDmzZs1YMAAxcbGqk+fPpK+P/LTs2dPDRkyROvWrdPq1auVlZWlfv36KTY2VpJ05513Kjg4WBkZGdq6davmzp2rqVOnavjw4f5+SAAAoBaq5+8bvPrqqzV//nyNHj1azzzzjOLj4zVlyhSlp6fba0aOHKkjR45o6NChKi8v17XXXqu8vDyFhobaa2bPnq2srCxdf/31CgwMVN++fZWTk2PvDw8P15IlS5SZman27durefPmys7O9jmXDgAAqLv8fp6c2oTz5ADO4Tw5AH4tx86TAwAAUBMQOQAAwEhEDgAAMBKRAwAAjETkAAAAIxE5AADASEQOAAAwEpEDAACMROQAAAAjETkAAMBIRA4AADASkQMAAIxE5AAAACMROQAAwEhEDgAAMBKRAwAAjETkAAAAIxE5AADASEQOAAAwEpEDAACMROQAAAAjETkAAMBIRA4AADASkQMAAIxE5AAAACMROQAAwEhEDgAAMBKRAwAAjETkAAAAIxE5AADASEQOAAAwEpEDAACMROQAAAAjETkAAMBIRA4AADASkQMAAIxE5AAAACMROQAAwEhEDgAAMBKRAwAAjETkAAAAIxE5AADASEQOAAAwEpEDAACMROQAAAAjETkAAMBIRA4AADASkQMAAIxE5AAAACMROQAAwEhEDgAAMBKRAwAAjETkAAAAIxE5AADASEQOAAAwEpEDAACMROQAAAAjETkAAMBIRA4AADASkQMAAIxU5ZHz3HPPKSAgQMOGDbO3HTt2TJmZmWrWrJkaNWqkvn37qrS01Ofn9uzZo7S0NDVo0ECRkZEaMWKETp065bNmxYoVuuqqqxQSEqKLL75Yubm5Vf1wAABALVGlkbN+/Xq9/PLLuuKKK3y2P/roo/rggw/09ttvq6CgQPv27dMtt9xi7z99+rTS0tJ04sQJrVmzRrNmzVJubq6ys7PtNbt371ZaWpqSk5O1adMmDRs2TIMHD9bixYur8iEBAIBaosoi5/Dhw0pPT9err76qJk2a2Ns9Ho9mzpypyZMn67rrrlP79u31+uuva82aNVq7dq0kacmSJfrss8/05ptvql27durVq5f++te/atq0aTpx4oQkacaMGYqPj9ekSZPUpk0bZWVl6dZbb9Xzzz//kzMdP35cXq/X5wIAAMxUZZGTmZmptLQ0paSk+GwvKSnRyZMnfba3bt1av/vd71RUVCRJKioqUmJioqKiouw1qamp8nq92rp1q73mh7edmppq38bZjBs3TuHh4fYlLi7uNz9OAABQM1VJ5Lz11lvauHGjxo0b96N9brdbwcHBioiI8NkeFRUlt9ttrzkzcCr3V+77uTVer1dHjx4961yjR4+Wx+OxL3v37v1Vjw8AANR89fx9g3v37tUjjzyi/Px8hYaG+vvmf5OQkBCFhIQ4PQYAAKgGfj+SU1JSorKyMl111VWqV6+e6tWrp4KCAuXk5KhevXqKiorSiRMnVF5e7vNzpaWlio6OliRFR0f/6NNWldf/0xqXy6WwsDB/PywAAFDL+D1yrr/+em3evFmbNm2yLx06dFB6err9v+vXr6+lS5faP7Njxw7t2bNHSUlJkqSkpCRt3rxZZWVl9pr8/Hy5XC4lJCTYa868jco1lbcBAADqNr+/XNW4cWNdfvnlPtsaNmyoZs2a2dszMjI0fPhwNW3aVC6XSw899JCSkpLUqVMnSVKPHj2UkJCgu+++WxMmTJDb7daTTz6pzMxM++Wm+++/Xy+++KJGjhypQYMGadmyZZo3b54WLVrk74cEAABqIb9Hzrl4/vnnFRgYqL59++r48eNKTU3VSy+9ZO8PCgrSwoUL9cADDygpKUkNGzbUwIED9cwzz9hr4uPjtWjRIj366KOaOnWqLrjgAr322mtKTU114iEBAIAaJsCyLMvpIZzi9XoVHh4uj8cjl8vl9DhAndJyVO0/6vrlc2lOjwDUSef6+5vvrgIAAEYicgAAgJGIHAAAYCQiBwAAGInIAQAARiJyAACAkYgcAABgJCIHAAAYicgBAABGInIAAICRiBwAAGAkIgcAABiJyAEAAEYicgAAgJGIHAAAYCQiBwAAGInIAQAARiJyAACAkYgcAABgJCIHAAAYicgBAABGInIAAICRiBwAAGAkIgcAABiJyAEAAEYicgAAgJGIHAAAYCQiBwAAGInIAQAARiJyAACAkYgcAABgJCIHAAAYicgBAABGInIAAICRiBwAAGAkIgcAABiJyAEAAEYicgAAgJGIHAAAYCQiBwAAGInIAQAARiJyAACAkYgcAABgJCIHAAAYicgBAABGInIAAICRiBwAAGAkIgcAABiJyAEAAEaq5/QApms5apHTI/jFl8+lOT0CAAC/CEdyAACAkYgcAABgJCIHAAAYicgBAABGInIAAICRiBwAAGAkIgcAABiJyAEAAEYicgAAgJH8Hjnjxo3T1VdfrcaNGysyMlJ9+vTRjh07fNYcO3ZMmZmZatasmRo1aqS+ffuqtLTUZ82ePXuUlpamBg0aKDIyUiNGjNCpU6d81qxYsUJXXXWVQkJCdPHFFys3N9ffDwcAANRSfo+cgoICZWZmau3atcrPz9fJkyfVo0cPHTlyxF7z6KOP6oMPPtDbb7+tgoIC7du3T7fccou9//Tp00pLS9OJEye0Zs0azZo1S7m5ucrOzrbX7N69W2lpaUpOTtamTZs0bNgwDR48WIsXL/b3QwIAALVQgGVZVlXewf79+xUZGamCggJ17dpVHo9H5513nubMmaNbb71VkrR9+3a1adNGRUVF6tSpkz766CP17t1b+/btU1RUlCRpxowZeuKJJ7R//34FBwfriSee0KJFi7Rlyxb7vvr166fy8nLl5eWd02xer1fh4eHyeDxyuVz+f/Diu6uAn2LC3w3+XgDOONff31X+nhyPxyNJatq0qSSppKREJ0+eVEpKir2mdevW+t3vfqeioiJJUlFRkRITE+3AkaTU1FR5vV5t3brVXnPmbVSuqbyNszl+/Li8Xq/PBQAAmKlKI6eiokLDhg1T586ddfnll0uS3G63goODFRER4bM2KipKbrfbXnNm4FTur9z3c2u8Xq+OHj161nnGjRun8PBw+xIXF/ebHyMAAKiZqjRyMjMztWXLFr311ltVeTfnbPTo0fJ4PPZl7969To8EAACqSL2quuGsrCwtXLhQhYWFuuCCC+zt0dHROnHihMrLy32O5pSWlio6Otpes27dOp/bq/z01ZlrfviJrNLSUrlcLoWFhZ11ppCQEIWEhPzmxwYAAGo+vx/JsSxLWVlZmj9/vpYtW6b4+Hif/e3bt1f9+vW1dOlSe9uOHTu0Z88eJSUlSZKSkpK0efNmlZWV2Wvy8/PlcrmUkJBgrznzNirXVN4GAACo2/x+JCczM1Nz5szR+++/r8aNG9vvoQkPD1dYWJjCw8OVkZGh4cOHq2nTpnK5XHrooYeUlJSkTp06SZJ69OihhIQE3X333ZowYYLcbreefPJJZWZm2kdi7r//fr344osaOXKkBg0apGXLlmnevHlatKj2f2IDAAD8dn4/kjN9+nR5PB51795dMTEx9mXu3Ln2mueff169e/dW37591bVrV0VHR+uf//ynvT8oKEgLFy5UUFCQkpKSdNddd2nAgAF65pln7DXx8fFatGiR8vPz1bZtW02aNEmvvfaaUlNT/f2QAABALVTl58mpyThPzrnjfCDwNxP+bvD3AnBGjTlPDgAAgBOIHAAAYCQiBwAAGInIAQAARiJyAACAkYgcAABgJCIHAAAYicgBAABGInIAAICRiBwAAGAkIgcAABiJyAEAAEYicgAAgJGIHAAAYCQiBwAAGInIAQAARqrn9AAAAGe1HLXI6RH84svn0pweATUMR3IAAICRiBwAAGAkIgcAABiJyAEAAEYicgAAgJGIHAAAYCQiBwAAGInIAQAARiJyAACAkYgcAABgJCIHAAAYicgBAABG4gs6UaeY8EWEfAkhAJwbjuQAAAAjETkAAMBIRA4AADASkQMAAIxE5AAAACMROQAAwEhEDgAAMBKRAwAAjETkAAAAIxE5AADASEQOAAAwEpEDAACMROQAAAAjETkAAMBIRA4AADASkQMAAIxE5AAAACMROQAAwEhEDgAAMBKRAwAAjETkAAAAIxE5AADASEQOAAAwEpEDAACMROQAAAAjETkAAMBIRA4AADASkQMAAIxE5AAAACPVc3oAAADwvZajFjk9gl98+Vya0yNIMuBIzrRp09SyZUuFhoaqY8eOWrdundMjAQCAGqBWR87cuXM1fPhwPfXUU9q4caPatm2r1NRUlZWVOT0aAABwWK2OnMmTJ2vIkCG69957lZCQoBkzZqhBgwb6+9//7vRoAADAYbX2PTknTpxQSUmJRo8ebW8LDAxUSkqKioqKzvozx48f1/Hjx+3rHo9HkuT1eqtszorj31XZbVenqvwzqk4mPB88FzUHz0XNYsLzwXPxy27fsqyfXVdrI+d//ud/dPr0aUVFRflsj4qK0vbt28/6M+PGjdPTTz/9o+1xcXFVMqNJwqc4PQEq8VzUHDwXNQvPR81RXc/FoUOHFB4e/pP7a23k/BqjR4/W8OHD7esVFRU6cOCAmjVrpoCAAAcn+/W8Xq/i4uK0d+9euVwup8ep03guahaej5qD56LmMOW5sCxLhw4dUmxs7M+uq7WR07x5cwUFBam0tNRne2lpqaKjo8/6MyEhIQoJCfHZFhERUVUjViuXy1Wr/w9rEp6LmoXno+bguag5THgufu4ITqVa+8bj4OBgtW/fXkuXLrW3VVRUaOnSpUpKSnJwMgAAUBPU2iM5kjR8+HANHDhQHTp00O9//3tNmTJFR44c0b333uv0aAAAwGG1OnLuuOMO7d+/X9nZ2XK73WrXrp3y8vJ+9GZkk4WEhOipp5760ctwqH48FzULz0fNwXNRc9S15yLA+k+fvwIAAKiFau17cgAAAH4OkQMAAIxE5AAAACMROQAAwEhEDgDAL7Zs2eL0CIAPIgcA4BdXXHGFOnbsqFdffVWHDh1yehz8jG3btunxxx93eowqR+QAv1JZWdnP7j916pTWrVtXTdMAzisoKNBll12mxx57TDExMRo4cKBWrlzp9Fj4f44cOaKZM2fqmmuu0WWXXaa8vDynR6pynCenFgkKCjqndadPn67iSSB9/3x8++23ioyMlCQlJibqww8/tL/VvrS0VLGxsTwf1eDML979OZMnT67iSSB9/8t03rx5ys3N1cqVK3XxxRcrIyNDAwcO/MnvFkTVWb16tWbOnKl58+bp6NGjevTRRzV48GC1bt3a6dGqHJFTiwQGBqpFixYaOHCgrrzyyp9cd9NNN1XjVHVXYGCg3G63HTmNGzfWJ598ogsvvFDS95ETExOjiooKJ8esE5KTk32ur1q1Su3bt1dYWJi9LSAgQMuWLavu0eq8Xbt26fXXX9cbb7wht9utnj17asGCBU6PZbyysjLl5ubq73//uzwej/r3768777xTSUlJ+uSTT5SQkOD0iNWCyKlFNmzYoJkzZ+qtt95SfHy8Bg0apPT0dDVp0sTp0eqkc4kcjuQ444fPBZx15MgRzZ49W6NHj1Z5eTl/J6pBWFiYbr31Vt111136wx/+oMDA79+dUr9+/ToVObwnpxbp0KGDpk+frm+//VbDhw/X/PnzdcEFF6hfv37Kz893ejwA8FFYWKh77rlH0dHRGjFihG655RatXr3a6bHqhBYtWmjVqlUqLCzUzp07nR7HMUROLRQaGqq77rpLS5cu1ZYtW1RWVqaePXvqwIEDTo9WpwQEBOjQoUPyer3yeDwKCAjQ4cOH5fV67QtQ1+zbt0/PPvusLr30UnXv3l27du1STk6O9u3bp1dffVWdOnVyesQ6Yfv27XrzzTf17bff6uqrr1b79u31/PPPS/r+3666gperaqmvv/5aubm5ys3N1XfffacBAwZo7NixqlevVn+xfK0SGBjo84+FZVlnvc6h+erHy1XO6NWrl/71r3+pefPmGjBggAYNGqRWrVo5PVadd/jwYf3jH//Q66+/rrVr16pbt26688471adPH5133nlOj1eliJxa5MSJE5o/f75mzpyplStXqlevXho0aJB69ep1zp+8gv8UFBSc07pu3bpV8ST49NNPfa5fc801mjdvni644AKf7VdccUV1jlXn/PGPf1RGRoZ69+7Nv0k11LZt2/Taa6/pzTff1IEDB3Ty5EmnR6pSRE4t0qxZMzVu3FgDBw7U3Xffbb/h9YdcLlc1T1Y3HTp0SI0bN/7ZNQUFBURONag8qna2f84qt3NUDfj/Tp06pQULFuiWW25xepQqReTUIpXvjpfO/poq/5BXr+7du2vx4sUKCQk56/6CggL17t2bM79Wg6+++uqc1rVo0aKKJwFqLsuytHz5ch09elTXXHNNnfhkLm/gqEWWL1/u9Ag4w//+7//q9ttv1/z5830CVPr+UyVpaWm69957HZqubiFeAF/l5eV65JFHtHHjRnXq1EmTJk3SDTfcoDVr1kiSIiMjtWTJEuNfwuVIDvAr7du3T126dFHnzp313//93/b2lStXKi0tTXfffbemTZvm4IR1x549e85p3e9+97sqngSoGQYPHqzCwkINHDhQH3zwgQIDA2VZlqZMmaLAwECNHDlSjRo10gcffOD0qFWKyDHIxo0blZ2drYULFzo9Sp3x73//W126dNFtt92mqVOnatWqVerVq5fS09M1Y8YMp8erM374SbdKZ37iLSAgQKdOnaru0QBHnH/++ZozZ466deumb775RnFxcVq2bJm6d+8uSVq3bp3++Mc/yu12OztoFePlqlpm8eLFys/PV3BwsAYPHqwLL7xQ27dv16hRo/TBBx8oNTXV6RHrlIsuukh5eXnq3r27PB6P5s+fr/79+xM41ezjjz8+63bLsvTWW28pJydHjRo1quapAOeUlpbq0ksvlfR98ISGhtrfqyd9f1Rz//79To1XbYicWmTmzJkaMmSImjZtqoMHD+q1117T5MmT9dBDD+mOO+7Qli1b1KZNG6fHrDMqT/bXsmVLzZ49WzfffLP69OmjiRMn+pwIkE+7Vb22bdv+aNu//vUvjRo1Sjt37tTIkSP12GOPOTAZ4IyKigqfj/EHBQX5HO2sKycEJHJqkalTp2r8+PEaMWKE3n33Xd1222166aWXtHnz5h+dDwRVLyIi4kcn/5s3b57efvtt+zqfdqt+Gzdu1BNPPKGVK1dq8ODB+vDDD3/ydAuAyV577TX7COapU6eUm5ur5s2bS1Kd+dQn78mpRRo2bKitW7eqZcuWsixLISEhWr58uTp37uz0aHXSihUrzum/hjhPTvX497//rT/96U969913dfvtt2vs2LGc8Rh1VsuWLc/p36fdu3dXwzTO4UhOLXL06FE1aNBA0veHGkNCQhQTE+PwVHVX5Rv44LwHH3xQM2fOVHJysjZs2KB27do5PRLgqOXLlys+Pt7pMRzHkZxaJDAwUGPHjrUPPz7xxBMaMWKEffix0sMPP+zEeHXOT32i50x8oqd6BAYGKjQ0VK1bt/7ZdRs3bqymiQBnBQYGqkWLFkpOTtZ1112n5ORknX/++U6PVe2InFrkXA4/BgQE6Isvvqimieq2999//yf3FRUVKScnRxUVFTp27Fg1TlU3jRkz5pwOzT/11FPVMA3gvBUrVtiX4uJinThxQhdeeKEdPMnJyYqKinJ6zCpH5AB+tGPHDvvj/Onp6XrmmWc4Gy8ARx07dkxr1qyxo2fdunU6efKkWrdura1btzo9XpUK/M9LUFMsW7ZMCQkJPh9PruTxeHTZZZdp5cqVDkyGffv2aciQIUpMTNSpU6e0adMmzZo1i8CpJk2aNFHTpk1/dImPj1dqaqry8/OdHhFwTGhoqK677jo9+eSTevrpp/Xwww+rUaNG2r59u9OjVTneeFyLTJkyRUOGDDnreVfCw8N13333afLkyerSpYsD09VNHo9Hzz77rF544QW1a9dOS5cu5c/fAVOmTDnr9vLycpWUlKh379565513dOONN1bvYICDTpw4obVr12r58uX2y1ZxcXHq2rWrXnzxxTrxyU9erqpFWrRooby8vJ884d/27dvVo0ePc/4eH/w2EyZM0Pjx4xUdHa1nn31WN910k9Mj4SdMnjxZ77zzjv3lhIDprrvuOhUXFys+Pl7dunVTly5d1K1btzr3iVwipxYJDQ3Vli1bdPHFF591/65du5SYmKijR49W82R1U2BgoMLCwpSSkuJzZtEf+uc//1mNU+Fsdu7cqU6dOunAgQNOjwJUi/r16ysmJkZ9+vRR9+7d1a1bNzVr1szpsaodL1fVIueff/7PRs6nn35a5yrdSQMGDKgzp0av7Y4fP67g4GCnxwCqTXl5uVauXKkVK1Zo/Pjx6t+/vy699FJ169bNjp7zzjvP6TGrHEdyapGHHnpIK1as0Pr16xUaGuqz7+jRo/r973+v5ORk5eTkODQhUDMNGzZM27dvV15entOjAI44dOiQVq1aZb8/55NPPtEll1yiLVu2OD1alSJyapHS0lJdddVVCgoKUlZWllq1aiXp+/fiTJs2TadPn9bGjRvrxLkPgDMNHz78rNs9Ho82btyonTt3qrCwUO3bt6/myYCaoaKiQuvXr9fy5cu1fPlyrVq1SseOHTP+u/WInFrmq6++0gMPPKDFixer8qkLCAhQamqqpk2bxmm8USclJyefdbvL5VKrVq30wAMP8HcDdUpFRYU2bNigFStWaPny5Vq9erWOHDmi888/3z4ZYHJysvGnuSByaqmDBw9q165dsixLl1xyiZo0aeL0SACAGsLlcunIkSOKjo62g6Z79+666KKLnB6tWhE5AAAY5uWXX1ZycrIuvfRSp0dxFJEDAACMxNc6AAAAIxE5AADASEQOAAAwEpEDAACMROQAqDNatmz5k99Yfq7GjBmjdu3a+WUeAFWLyAEAAEYicgAAgJGIHACOeeedd5SYmKiwsDA1a9ZMKSkpKigoUP369eV2u33WDhs2TF26dJEk5ebmKiIiQgsXLlSrVq3UoEED3Xrrrfruu+80a9YstWzZUk2aNNHDDz/8o+/mOXTokPr376+GDRvq/PPP17Rp03z279mzRzfddJMaNWokl8ul22+/XaWlpVX7BwGgShA5ABzx7bffqn///ho0aJC2bdumFStW6JZbblH79u114YUX6o033rDXnjx5UrNnz9agQYPsbd99951ycnL01ltvKS8vTytWrNDNN9+sDz/8UB9++KHeeOMNvfzyy3rnnXd87nfixIlq27atPv74Y40aNUqPPPKI8vPzJX3/fT833XSTDhw4oIKCAuXn5+uLL77QHXfcUT1/KAD8ywIAB5SUlFiSrC+//PJH+8aPH2+1adPGvv7uu+9ajRo1sg4fPmxZlmW9/vrrliRr165d9pr77rvPatCggXXo0CF7W2pqqnXffffZ11u0aGH17NnT577uuOMOq1evXpZlWdaSJUusoKAga8+ePfb+rVu3WpKsdevWWZZlWU899ZTVtm3b3/DIAVQXjuQAcETbtm11/fXXKzExUbfddpteffVVHTx4UJJ0zz33aNeuXVq7dq2k71+euv3229WwYUP75xs0aODzZYNRUVFq2bKlGjVq5LOtrKzM536TkpJ+dH3btm2SpG3btikuLk5xcXH2/oSEBEVERNhrANQeRA4ARwQFBSk/P18fffSREhIS9MILL6hVq1bavXu3IiMjdeONN+r1119XaWmpPvroI5+XqiSpfv36PtcDAgLOuq2ioqLKHwuAmonIAeCYgIAAde7cWU8//bQ+/vhjBQcHa/78+ZKkwYMHa+7cuXrllVd00UUXqXPnzn65z8qjQ2deb9OmjSSpTZs22rt3r/bu3Wvv/+yzz1ReXq6EhAS/3D+A6lPP6QEA1E3FxcVaunSpevToocjISBUXF2v//v12cKSmpsrlcmns2LF65pln/Ha/q1ev1oQJE9SnTx/l5+fr7bff1qJFiyRJKSkpSkxMVHp6uqZMmaJTp07pwQcfVLdu3dShQwe/zQCgenAkB4AjXC6XCgsLdcMNN+jSSy/Vk08+qUmTJqlXr16SpMDAQN1zzz06ffq0BgwY4Lf7feyxx7RhwwZdeeWVGjt2rCZPnqzU1FRJ3x9Zev/999WkSRN17dpVKSkpuvDCCzV37ly/3T+A6hNgWZbl9BAAcDYZGRnav3+/FixY4PQoAGohXq4CUON4PB5t3rxZc+bMIXAA/GpEDoAa56abbtK6det0//336w9/+IPT4wCopXi5CgAAGIk3HgMAACMROQAAwEhEDgAAMBKRAwAAjETkAAAAIxE5AADASEQOAAAwEpEDAACM9H93P+ruEUg1lAAAAABJRU5ErkJggg==\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# just one example to show all companies' data made it to the collect dataframe: variance of opening price \n", "print(dji_hist.groupby('symbol').open.var().plot(kind='bar'))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We now know how to retrieve data from an API or the whole html content from a normal website. The next chapter will look at how we can extract information displayed on websites in a more directed manner than downloading just all of the website's content." ] } ], "metadata": { "celltoolbar": "Edit 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.10.6" } }, "nbformat": 4, "nbformat_minor": 4 }