{ "cells": [ { "cell_type": "markdown", "id": "7af094ba", "metadata": {}, "source": [ "# MCS 275 Spring 2022 Lecture 40" ] }, { "cell_type": "markdown", "id": "c6a86b94", "metadata": {}, "source": [ "## Imports" ] }, { "cell_type": "code", "execution_count": 19, "id": "535b2603", "metadata": {}, "outputs": [], "source": [ "from urllib.request import urlopen\n", "import bs4" ] }, { "cell_type": "markdown", "id": "3b7d750e", "metadata": {}, "source": [ "## Utility functions" ] }, { "cell_type": "markdown", "id": "0d4f3b35", "metadata": {}, "source": [ "A function to get the content of a web page as a string (basically, what we did manually in Lecture 39)." ] }, { "cell_type": "code", "execution_count": 20, "id": "95e156a6", "metadata": {}, "outputs": [], "source": [ "def urlreadtext(url,*args,**kwargs):\n", " \"\"\"\n", " Retrieve URL `url` and return the response body decoded as a string. If\n", " content-type specifies a charset, use that. Otherwise, attempt UTF-8\n", " decoding. Returns the resulting string.\n", "\n", " Additional arguments are passed to `urllib.request.urlopen`.\n", " \"\"\"\n", " print(\"Opening URL '{}'\".format(url))\n", " with urlopen(url,*args,**kwargs) as res:\n", " # Get raw data (bytes)\n", " data = res.read()\n", " # Determine the encoding\n", " encoding = res.headers.get_content_charset()\n", " if encoding is None:\n", " # Danger: no encoding was specified in the headers\n", " # Try using UTF-8\n", " encoding = \"UTF-8\"\n", "\n", " # TODO: Detect if the response indicates a non-text content type, and if\n", " # so, raise an informative exception rather than just letting the\n", " # attempt to decode as a string fail.\n", "\n", " # Convert to string and return\n", " return data.decode(encoding)\n", "\n", "# Let's apply caching so that we only make one request to any given\n", "# URL, even if `urlreadtext` is called many times\n", "import functools\n", "urlreadtext = functools.lru_cache(maxsize=None)(urlreadtext)" ] }, { "cell_type": "code", "execution_count": 21, "id": "acae7ff7", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Opening URL 'http://example.com'\n" ] }, { "data": { "text/plain": [ "'\\n\\n\\n Example Domain\\n\\n \\n \\n \\n \\n\\n\\n\\n
\\n

Example Domain

\\n

This domain is for use in illustrative examples in documents. You may use this\\n domain in literature without prior coordination or asking for permission.

\\n

More information...

\\n
\\n\\n\\n'" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "urlreadtext(\"http://example.com\")" ] }, { "cell_type": "code", "execution_count": 22, "id": "5ec266ba", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'\\n\\n\\n Example Domain\\n\\n \\n \\n \\n \\n\\n\\n\\n
\\n

Example Domain

\\n

This domain is for use in illustrative examples in documents. You may use this\\n domain in literature without prior coordination or asking for permission.

\\n

More information...

\\n
\\n\\n\\n'" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "urlreadtext(\"http://example.com\")" ] }, { "cell_type": "markdown", "id": "7afe12cc", "metadata": {}, "source": [ "A function to generate URLs for MCS 275 related things." ] }, { "cell_type": "code", "execution_count": 23, "id": "aaed57fe", "metadata": {}, "outputs": [], "source": [ "def mcs275url(itemtype,number):\n", " urlbase = \"http://www.dumas.io/teaching/2022/spring/mcs275/\"\n", " sub_fmts = {\n", " \"homework\":\"nbview/homework/homework{}.html\",\n", " \"homework solution\":\"nbview/homework/homework{}soln.html\",\n", " \"worksheet\":\"nbview/worksheets/worksheet{}.html\",\n", " \"worksheet solution\":\"nbview/worksheets/worksheet{}soln.html\",\n", " \"project\":\"nbview/projects/project{}.html\",\n", " \"lecture\":\"slides/lecture{}.html\"\n", " }\n", " if itemtype not in sub_fmts:\n", " raise ValueError(\"itemtype '{}' unknown; must be one of {}\".format(itemtype,sub_fmts.keys()))\n", " return urlbase + sub_fmts[itemtype].format(number)" ] }, { "cell_type": "code", "execution_count": 24, "id": "88fd0e29", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture40.html'" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mcs275url(\"lecture\",40)" ] }, { "cell_type": "code", "execution_count": 25, "id": "494f5d90", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'http://www.dumas.io/teaching/2022/spring/mcs275/nbview/homework/homework12soln.html'" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mcs275url(\"homework solution\",12)" ] }, { "cell_type": "code", "execution_count": 26, "id": "cb719bad", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'http://www.dumas.io/teaching/2022/spring/mcs275/nbview/projects/project4.html'" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mcs275url(\"project\",4) # reminder: Due Fri 29 April!" ] }, { "cell_type": "code", "execution_count": 27, "id": "b77f04d5", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture40.html'\n" ] } ], "source": [ "s = urlreadtext(mcs275url(\"lecture\",40))" ] }, { "cell_type": "code", "execution_count": 29, "id": "3625aaf1", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'\\n\\n\\n \\n \")\n", "stop = s.find(\"\")\n", "print(\"The title of lecture 40 is:\",s[start+7:stop])" ] }, { "cell_type": "markdown", "id": "4541e12a", "metadata": {}, "source": [ "## Level 1 HTML parsing" ] }, { "cell_type": "code", "execution_count": 41, "id": "fb0f495b", "metadata": {}, "outputs": [], "source": [ "import html.parser\n", "\n", "class TitleExtractor(html.parser.HTMLParser):\n", " def __init__(self,*args,**kwargs):\n", " super().__init__(*args,**kwargs)\n", " self.listening = False\n", " self.captured = \"\"\n", " def handle_starttag(self, tag, attrs):\n", " #print(\"Start tag\",tag)\n", " if tag == \"title\":\n", " self.listening = True\n", " def handle_endtag(self, tag):\n", " #print(\"End tag\",tag)\n", " if tag == \"title\":\n", " self.listening = False\n", " def handle_data(self, data):\n", " if self.listening:\n", " self.captured += data" ] }, { "cell_type": "code", "execution_count": 44, "id": "de262d88", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The title of lecture 40 is: Lec 40: Parsing and scraping HTML\n" ] } ], "source": [ "X = TitleExtractor()\n", "X.feed(urlreadtext(mcs275url(\"lecture\",40)))\n", "print(\"The title of lecture 40 is:\",X.captured)" ] }, { "cell_type": "markdown", "id": "5765e454", "metadata": {}, "source": [ "## Level 2 HTML parsing" ] }, { "cell_type": "code", "execution_count": 53, "id": "b01bf130", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The title of lecture 40 is: Lec 40: Parsing and scraping HTML\n" ] } ], "source": [ "from bs4 import BeautifulSoup\n", "\n", "soup = BeautifulSoup(\n", " urlreadtext(mcs275url(\"lecture\",40)),\n", " \"html.parser\" # Use Python's built-in parser\n", ")\n", "print(\"The title of lecture 40 is:\",soup.title.text)" ] }, { "cell_type": "markdown", "id": "0e14de75", "metadata": {}, "source": [ "## MCS 275 slides analysis" ] }, { "cell_type": "code", "execution_count": 54, "id": "99162275", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture1.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture2.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture3.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture4.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture5.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture6.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture7.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture8.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture9.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture10.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture11.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture12.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture13.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture14.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture15.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture16.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture17.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture18.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture19.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture20.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture21.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture22.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture23.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture24.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture25.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture26.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture27.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture28.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture29.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture30.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture31.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture32.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture33.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture34.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture35.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture36.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture37.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture38.html'\n", "Opening URL 'http://www.dumas.io/teaching/2022/spring/mcs275/slides/lecture39.html'\n" ] } ], "source": [ "from bs4 import BeautifulSoup\n", "import time\n", "\n", "lecture_titles = {}\n", "for n in range(1,41):\n", " time.sleep(0.1)\n", " soup = BeautifulSoup(\n", " urlreadtext(mcs275url(\"lecture\",n)),\n", " \"html.parser\" # Use Python's built-in parser\n", " )\n", " lecture_titles[n] = soup.title.text" ] }, { "cell_type": "code", "execution_count": 55, "id": "a7c55771", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{1: 'Lec 1: Introduction',\n", " 2: 'Lec 2: Python tour part I',\n", " 3: 'Lec 3: Python tour part II',\n", " 4: 'Lec 4: Operator overloading',\n", " 5: 'Lec 5: Inheritance',\n", " 6: 'Lec 6: Inheritance II',\n", " 7: 'Lec 7: Notebooks',\n", " 8: 'Lec 8: Variadic functions and decorators',\n", " 9: 'Lec 9: Context Managers',\n", " 10: 'Lec 10: Errors and debugging',\n", " 11: 'Lec 11: pdb',\n", " 12: 'Lec 12: Recursion',\n", " 13: 'Lec 13: Recursion vs iteration',\n", " 14: 'Lec 14: Recursion vs iteration II',\n", " 15: 'Lec 15: Recursion with backtracking',\n", " 16: 'Lec 16: Mergesort',\n", " 17: 'Lec 17: Quicksort',\n", " 18: 'Lec 18: Comparison sorts',\n", " 19: 'Lec 19: Trees',\n", " 20: 'Lec 20: Binary Search Trees (BST)',\n", " 21: 'Lec 21: BST and tree traversals',\n", " 22: 'Lec 22: set and defaultdict',\n", " 23: 'Lec 23: CSV and JSON',\n", " 24: 'Lec 24: Pillow',\n", " 25: 'Lec 25: Numpy',\n", " 26: 'Lec 26: Numpy II',\n", " 27: 'Lec 27: Julia sets',\n", " 28: 'Lec 28: Matplotlib',\n", " 29: 'Lec 29: Matplotlib II',\n", " 30: 'Lec 30: Databases',\n", " 31: 'Lec 31: Machine learning',\n", " 32: 'Lec 32: SQL and SQLite II',\n", " 33: 'Lec 33: HTML and CSS',\n", " 34: 'Lec 34: Planning our web app',\n", " 35: 'Lec 35: HTTP and Flask',\n", " 36: 'Lec 36: Using Flask',\n", " 37: 'Lec 37: Forms',\n", " 38: 'Lec 38: Web app wrap-up',\n", " 39: 'Lec 39: HTTP Requests',\n", " 40: 'Lec 40: Parsing and scraping HTML'}" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lecture_titles" ] }, { "cell_type": "code", "execution_count": 56, "id": "58cd34ff", "metadata": {}, "outputs": [], "source": [ "from bs4 import BeautifulSoup\n", "\n", "soup = BeautifulSoup(\n", " urlreadtext(mcs275url(\"lecture\",40)),\n", " \"html.parser\" # Use Python's built-in parser\n", ")" ] }, { "cell_type": "code", "execution_count": 62, "id": "f5f04636", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "

Lecture 40

" ] }, "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ "soup.find(\"section\").h1 # Does the first slide have an h1?" ] }, { "cell_type": "code", "execution_count": 67, "id": "a92097f1", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "21" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(soup.find_all(\"section\")) # number of slides in lecture 40" ] }, { "cell_type": "code", "execution_count": 73, "id": "20677e93", "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "import matplotlib.pyplot as plt\n", "from bs4 import BeautifulSoup\n", "\n", "lecture_numbers = list(range(1,41))\n", "lecture_slide_counts = []\n", "for n in range(1,41):\n", " soup = BeautifulSoup(\n", " urlreadtext(mcs275url(\"lecture\",n)),\n", " \"html.parser\" # Use Python's built-in parser\n", " )\n", " lecture_slide_counts.append(len(soup.find_all(\"section\")))\n", " \n", "\n", "plt.bar(lecture_numbers,lecture_slide_counts)\n", "plt.title(\"Number of slides in MCS 275 lectures\")\n", "plt.xlabel(\"Lecture number\")\n", "plt.show()" ] } ], "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.12" } }, "nbformat": 4, "nbformat_minor": 5 }