Skip to content

Python Scripts

A collection of Python examples and tutorials organized by topic.

Python Cheat Sheet

Download Python Cheat Sheet by Real Python

A comprehensive Python reference guide created by Real Python. This cheat sheet covers essential Python syntax, data structures, and common operations.


BeautifulSoup

Web scraping and HTML parsing with BeautifulSoup.

Python
#!/usr/bin/env python3
"""
BASIC BEAUTIFULSOUP USAGE - Creating and parsing HTML
Demonstrates basic BeautifulSoup initialization and parsing
"""

from bs4 import BeautifulSoup

print("=" * 60)
print("BASIC BEAUTIFULSOUP USAGE")
print("=" * 60)

# Sample HTML
html = """
<html>
<head><title>Sample Page</title></head>
<body>
    <h1>Welcome</h1>
    <p class="intro">This is a paragraph.</p>
    <p id="main">Another paragraph with <b>bold</b> text.</p>
</body>
</html>
"""

# Example 1: Create BeautifulSoup object
print("\n1. Creating BeautifulSoup Object")
print("-" * 40)
soup = BeautifulSoup(html, 'html.parser')
print(f"  Type: {type(soup)}")
print(f"  Parser: html.parser")

# Example 2: Get title
print("\n2. Accessing Title")
print("-" * 40)
print(f"  Title tag: {soup.title}")
print(f"  Title text: {soup.title.string}")

# Example 3: Get first tag
print("\n3. Getting First Tag")
print("-" * 40)
print(f"  First h1: {soup.h1}")
print(f"  First p: {soup.p}")

# Example 4: Tag name and attributes
print("\n4. Tag Properties")
print("-" * 40)
first_p = soup.p
print(f"  Tag name: {first_p.name}")
print(f"  Attributes: {first_p.attrs}")
print(f"  Class: {first_p.get('class')}")

# Example 5: Get text content
print("\n5. Extracting Text")
print("-" * 40)
print(f"  Body text: {soup.body.get_text(strip=True)[:50]}...")

print("\n" + "=" * 60)
print("Key Points:")
print("  - BeautifulSoup(html, 'html.parser')")
print("  - Access tags directly: soup.title")
print("  - get_text() extracts all text")
print("  - attrs contains tag attributes")
print("=" * 60)

For more BeautifulSoup examples, click here


Enumerate

Using Python's enumerate() function for indexed iteration.

Python
#!/usr/bin/env python3
"""
BASIC ENUMERATE EXAMPLES
Learn the fundamentals of enumerate()
"""

print("=" * 60)
print("BASIC ENUMERATE - Getting Index and Value Together")
print("=" * 60)

# Example 1: Basic enumerate usage
print("\n1. Basic Iteration with Index")
print("-" * 40)
fruits = ["apple", "banana", "cherry", "date"]

print("Without enumerate (manual counter):")
index = 0
for fruit in fruits:
    print(f"  {index}: {fruit}")
    index += 1

print("\nWith enumerate (automatic counter):")
for index, fruit in enumerate(fruits):
    print(f"  {index}: {fruit}")

# Example 2: Numbered list output
print("\n2. Creating a Numbered Menu")
print("-" * 40)
menu_items = ["Coffee", "Tea", "Juice", "Soda"]

for number, item in enumerate(menu_items, start=1):
    print(f"{number}. {item}")

# Example 3: Finding position of items
print("\n3. Finding Position of Specific Items")
print("-" * 40)
colors = ["red", "green", "blue", "yellow", "green", "purple"]

print(f"Looking for 'green' in: {colors}")
for index, color in enumerate(colors):
    if color == "green":
        print(f"  Found 'green' at position {index}")

# Example 4: Converting to list of tuples
print("\n4. enumerate() Returns Tuples")
print("-" * 40)
letters = ["A", "B", "C"]
result = list(enumerate(letters))
print(f"Letters: {letters}")
print(f"Enumerated: {result}")

# Example 5: Custom start value
print("\n5. Starting Count from Different Number")
print("-" * 40)
chapters = ["Introduction", "Methods", "Results", "Conclusion"]

print("Starting from 0 (default):")
for i, chapter in enumerate(chapters):
    print(f"  Chapter {i}: {chapter}")

print("\nStarting from 1:")
for i, chapter in enumerate(chapters, start=1):
    print(f"  Chapter {i}: {chapter}")

print("\nStarting from 10:")
for i, chapter in enumerate(chapters, start=10):
    print(f"  Chapter {i}: {chapter}")

print("\n" + "=" * 60)
print("Key Takeaway: enumerate(iterable, start=0)")
print("  - Returns (index, value) pairs")
print("  - Default starts at 0, but can be changed")
print("  - Avoids manual counter variables")
print("=" * 60)

For more Enumerate examples, click here


If Statements

Conditional logic and decision-making in Python.

Python
#!/usr/bin/env python3
"""Simple age checker"""

age = int(input("Enter your age: "))

if age >= 18:
    print("You are an adult.")
else:
    print("You are a minor.")

For more If Statements examples, click here


Lists

List operations, methods, and data manipulation.

Python
#!/usr/bin/env python3
"""Basic List Operations - CRUD

Summary: Demonstrates Create, Read, Update, Delete operations on lists.
Use when: You need to manage a collection of items that can change over time.
Common in: Shopping carts, todo lists, user management systems.
"""

# CREATE - Initialize a list
tasks = ["Write code", "Test code", "Deploy code"]
print("Initial tasks:", tasks)

# READ - Access elements
print(f"\nFirst task: {tasks[0]}")
print(f"Last task: {tasks[-1]}")
print(f"Total tasks: {len(tasks)}")

# UPDATE - Modify existing element
tasks[1] = "Write tests and test code"
print(f"\nUpdated tasks: {tasks}")

# DELETE - Remove element
removed = tasks.pop(0)
print(f"\nCompleted: {removed}")
print(f"Remaining: {tasks}")

# ADD - Append new element
tasks.append("Monitor production")
print(f"Added new task: {tasks}")

For more Lists examples, click here


Loops

Iteration with for and while loops.

Python
#!/usr/bin/env python3
"""Count from 1 to 10"""

for i in range(1, 11):
    print(i)

For more Loops examples, click here


File Operations (open)

Reading and writing files with Python's open() function.

Python
#!/usr/bin/env python3
"""
BASIC FILE READING - Reading entire file content
Demonstrates the most basic way to read a file
"""

import os
import tempfile

print("=" * 60)
print("BASIC FILE READING - Reading Entire File")
print("=" * 60)

# Create a sample file for demonstration
temp_dir = tempfile.gettempdir()
sample_file = os.path.join(temp_dir, "sample_text.txt")

# Write sample content
print("\n1. Creating Sample File")
print("-" * 40)
content = """Hello, this is line 1
This is line 2
And here is line 3
Finally, line 4"""

file_handle = open(sample_file, 'w')
file_handle.write(content)
file_handle.close()
print(f"Created: {sample_file}")

# Method 1: read() - read entire file as single string
print("\n2. Method 1: read() - Entire File as String")
print("-" * 40)
file_handle = open(sample_file, 'r')
full_content = file_handle.read()
file_handle.close()

print("Content:")
print(full_content)
print(f"\nType: {type(full_content)}")
print(f"Length: {len(full_content)} characters")

# Method 2: readlines() - read as list of lines
print("\n3. Method 2: readlines() - List of Lines")
print("-" * 40)
file_handle = open(sample_file, 'r')
lines_list = file_handle.readlines()
file_handle.close()

print(f"Type: {type(lines_list)}")
print(f"Number of lines: {len(lines_list)}")
print("\nLines:")
for i, line in enumerate(lines_list, 1):
    print(f"  Line {i}: {repr(line)}")

# Method 3: readline() - read one line at a time
print("\n4. Method 3: readline() - One Line at Time")
print("-" * 40)
file_handle = open(sample_file, 'r')
print("First line:", repr(file_handle.readline()))
print("Second line:", repr(file_handle.readline()))
print("Third line:", repr(file_handle.readline()))
file_handle.close()

# Cleanup
os.remove(sample_file)
print("\n" + "=" * 60)
print("Key Points:")
print("  - Always close files after opening")
print("  - read() returns entire content as string")
print("  - readlines() returns list of lines")
print("  - readline() reads one line per call")
print("=" * 60)

For more File Operations examples, click here


OS File Operations

Working with the filesystem using the os module.

Python
#!/usr/bin/env python3
"""
LISTING DIRECTORY CONTENTS - Using os.listdir()
Demonstrates various ways to list files and directories
"""

import os
import tempfile

print("=" * 60)
print("LISTING DIRECTORY CONTENTS - os.listdir()")
print("=" * 60)

temp_dir = tempfile.gettempdir()
test_dir = os.path.join(temp_dir, "listdir_demo")

# Create test directory structure
os.makedirs(test_dir, exist_ok=True)

# Create sample files and subdirectories
files_to_create = ["file1.txt", "file2.py", "file3.log", ".hidden"]
dirs_to_create = ["subdir1", "subdir2", ".hidden_dir"]

for filename in files_to_create:
    filepath = os.path.join(test_dir, filename)
    with open(filepath, 'w') as f:
        f.write(f"Content of {filename}\n")

for dirname in dirs_to_create:
    os.makedirs(os.path.join(test_dir, dirname), exist_ok=True)

print(f"Created test directory: {test_dir}\n")

# Example 1: Basic listdir()
print("1. Basic os.listdir()")
print("-" * 40)
items = os.listdir(test_dir)
print(f"Found {len(items)} items:")
for item in sorted(items):
    print(f"  {item}")

# Example 2: Separate files and directories
print("\n2. Separate Files and Directories")
print("-" * 40)
files = []
directories = []

for item in os.listdir(test_dir):
    full_path = os.path.join(test_dir, item)
    if os.path.isfile(full_path):
        files.append(item)
    elif os.path.isdir(full_path):
        directories.append(item)

print(f"Files ({len(files)}):")
for f in sorted(files):
    print(f"  {f}")

print(f"\nDirectories ({len(directories)}):")
for d in sorted(directories):
    print(f"  {d}/")

# Example 3: Filter by extension
print("\n3. Filter by File Extension")
print("-" * 40)
extensions = {'.txt': [], '.py': [], '.log': []}

for item in os.listdir(test_dir):
    full_path = os.path.join(test_dir, item)
    if os.path.isfile(full_path):
        ext = os.path.splitext(item)[1]
        if ext in extensions:
            extensions[ext].append(item)

for ext, file_list in extensions.items():
    if file_list:
        print(f"{ext} files:")
        for f in file_list:
            print(f"  {f}")

# Example 4: Include hidden files
print("\n4. Hidden Files (Starting with '.')")
print("-" * 40)
all_items = os.listdir(test_dir)
hidden_items = [item for item in all_items if item.startswith('.')]
visible_items = [item for item in all_items if not item.startswith('.')]

print(f"Visible items ({len(visible_items)}):")
for item in sorted(visible_items):
    print(f"  {item}")

print(f"\nHidden items ({len(hidden_items)}):")
for item in sorted(hidden_items):
    print(f"  {item}")

# Example 5: List with full paths
print("\n5. List with Full Paths")
print("-" * 40)
full_paths = [os.path.join(test_dir, item) for item in os.listdir(test_dir)]
print("Full paths (first 5):")
for path in sorted(full_paths)[:5]:
    print(f"  {path}")

# Example 6: Get file sizes
print("\n6. List Files with Sizes")
print("-" * 40)
for item in sorted(os.listdir(test_dir)):
    full_path = os.path.join(test_dir, item)
    if os.path.isfile(full_path):
        size = os.path.getsize(full_path)
        print(f"  {item:20s} {size:>6} bytes")

# Example 7: Count items by type
print("\n7. Count Items by Type")
print("-" * 40)
counts = {'files': 0, 'directories': 0, 'other': 0}

for item in os.listdir(test_dir):
    full_path = os.path.join(test_dir, item)
    if os.path.isfile(full_path):
        counts['files'] += 1
    elif os.path.isdir(full_path):
        counts['directories'] += 1
    else:
        counts['other'] += 1

for item_type, count in counts.items():
    print(f"  {item_type.capitalize()}: {count}")

# Example 8: List sorted by modification time
print("\n8. Sort by Modification Time")
print("-" * 40)
items_with_time = []
for item in os.listdir(test_dir):
    full_path = os.path.join(test_dir, item)
    mtime = os.path.getmtime(full_path)
    items_with_time.append((item, mtime))

items_with_time.sort(key=lambda x: x[1], reverse=True)

print("Most recently modified (first 5):")
for item, _ in items_with_time[:5]:
    print(f"  {item}")

# Example 9: List comprehension patterns
print("\n9. List Comprehension Patterns")
print("-" * 40)

# Only .txt files
txt_files = [f for f in os.listdir(test_dir)
             if f.endswith('.txt') and os.path.isfile(os.path.join(test_dir, f))]
print(f"Text files: {txt_files}")

# Only directories
subdirs = [d for d in os.listdir(test_dir)
           if os.path.isdir(os.path.join(test_dir, d))]
print(f"Subdirectories: {subdirs}")

# Example 10: Empty directory check
print("\n10. Check if Directory is Empty")
print("-" * 40)
if os.listdir(test_dir):
    print(f"  Directory is NOT empty ({len(os.listdir(test_dir))} items)")
else:
    print("  Directory is empty")

# Cleanup
import shutil
shutil.rmtree(test_dir)

print("\n" + "=" * 60)
print("Key Points:")
print("  - os.listdir() returns list of names")
print("  - Does not include '.' and '..'")
print("  - Returns basenames, not full paths")
print("  - Does not recurse into subdirectories")
print("  - Order is arbitrary (use sorted())")
print("=" * 60)

For more OS File Operations examples, click here


Power Function (pow)

Using Python's pow() function for exponentiation.

Python
#!/usr/bin/env python3
"""
BASIC POW() EXAMPLES
Learn the fundamentals of pow() function
"""

print("=" * 60)
print("BASIC POW() - Exponentiation Fundamentals")
print("=" * 60)

# Example 1: Basic exponentiation
print("\n1. Simple Powers")
print("-" * 40)
print(f"pow(2, 3) = {pow(2, 3)}")  # 2^3 = 8
print(f"pow(5, 2) = {pow(5, 2)}")  # 5^2 = 25
print(f"pow(10, 4) = {pow(10, 4)}")  # 10^4 = 10000

# Example 2: Comparing pow() with ** operator
print("\n2. pow() vs ** Operator")
print("-" * 40)
base = 3
exponent = 4

result_pow = pow(base, exponent)
result_operator = base ** exponent

print(f"Using pow({base}, {exponent}) = {result_pow}")
print(f"Using {base} ** {exponent} = {result_operator}")
print(f"Are they equal? {result_pow == result_operator}")

# Example 3: Powers of different numbers
print("\n3. Powers Table (2^n)")
print("-" * 40)
print("n  | 2^n")
print("---|-------")
for n in range(0, 11):
    result = pow(2, n)
    print(f"{n:2d} | {result:4d}")

# Example 4: Square and cube
print("\n4. Common Operations - Square and Cube")
print("-" * 40)
numbers = [2, 5, 10, 12]

for num in numbers:
    square = pow(num, 2)
    cube = pow(num, 3)
    print(f"Number: {num:2d} | Square: {square:3d} | Cube: {cube:4d}")

# Example 5: Zero and one as exponents
print("\n5. Special Exponents (0 and 1)")
print("-" * 40)
test_numbers = [5, 10, 100, 999]

print("Any number to the power of 0 equals 1:")
for num in test_numbers:
    result = pow(num, 0)
    print(f"  pow({num}, 0) = {result}")

print("\nAny number to the power of 1 equals itself:")
for num in test_numbers:
    result = pow(num, 1)
    print(f"  pow({num}, 1) = {result}")

# Example 6: Calculating area and volume
print("\n6. Practical: Area of Square, Volume of Cube")
print("-" * 40)
side_length = 7

area = pow(side_length, 2)
volume = pow(side_length, 3)

print(f"Side length: {side_length} units")
print(f"Area of square: {area} square units")
print(f"Volume of cube: {volume} cubic units")

# Example 7: Powers of 10 (scientific notation base)
print("\n7. Powers of 10 (Magnitude)")
print("-" * 40)
print("Power | Result     | Name")
print("------|------------|------------")
magnitude_names = ["one", "ten", "hundred", "thousand", "ten thousand",
                   "hundred thousand", "million"]

for power in range(0, 7):
    result = pow(10, power)
    name = magnitude_names[power]
    print(f"10^{power}  | {result:10d} | {name}")

# Example 8: Simple interest-like calculation
print("\n8. Practical: Compound Growth")
print("-" * 40)
initial_value = 100
growth_rate = 2  # doubles each period

print(f"Initial value: {initial_value}")
print(f"Growth factor: {growth_rate}x per period\n")
print("Period | Value")
print("-------|-------")

for period in range(0, 6):
    value = initial_value * pow(growth_rate, period)
    print(f"   {period}   | {value:5d}")

print("\n" + "=" * 60)
print("Key Concepts:")
print("  - pow(base, exp) calculates base^exp")
print("  - pow(x, 2) gives square, pow(x, 3) gives cube")
print("  - pow(n, 0) always equals 1")
print("  - pow(n, 1) always equals n")
print("  - Equivalent to ** operator for basic cases")
print("=" * 60)

For more Power Function examples, click here


Slicing

String and sequence slicing operations.

Python
#!/usr/bin/env python3
"""
BASIC SLICE() EXAMPLES
Learn the fundamentals of slice objects and slicing
"""

print("=" * 60)
print("BASIC SLICE() - Understanding Slice Objects")
print("=" * 60)

# Example 1: Basic slice notation vs slice object
print("\n1. Slice Notation vs slice() Object")
print("-" * 40)

data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(f"Data: {data}\n")

# Traditional slice notation
result1 = data[2:7]
print(f"Using notation data[2:7]: {result1}")

# Using slice object
s = slice(2, 7)
result2 = data[s]
print(f"Using slice(2, 7):        {result2}")
print(f"Results are equal: {result1 == result2}")

# Example 2: Three forms of slice
print("\n2. Different slice() Forms")
print("-" * 40)

numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# Form 1: slice(stop)
s1 = slice(5)
print(f"slice(5):           {numbers[s1]}")

# Form 2: slice(start, stop)
s2 = slice(2, 8)
print(f"slice(2, 8):        {numbers[s2]}")

# Form 3: slice(start, stop, step)
s3 = slice(1, 9, 2)
print(f"slice(1, 9, 2):     {numbers[s3]}")

# Example 3: Slice attributes
print("\n3. Examining Slice Attributes")
print("-" * 40)

s = slice(2, 10, 3)
print(f"Slice object: slice(2, 10, 3)")
print(f"  start: {s.start}")
print(f"  stop:  {s.stop}")
print(f"  step:  {s.step}")

s_simple = slice(5)
print(f"\nSlice object: slice(5)")
print(f"  start: {s_simple.start}")
print(f"  stop:  {s_simple.stop}")
print(f"  step:  {s_simple.step}")

# Example 4: Why use slice objects?
print("\n4. Reusing Slice Objects")
print("-" * 40)

# Define once, use many times
first_three = slice(3)
middle_section = slice(3, 7)

fruits = ["apple", "banana", "cherry", "date", "elderberry", "fig", "grape"]
numbers = [10, 20, 30, 40, 50, 60, 70]
letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G']

print(f"Fruits:  {fruits}")
print(f"Numbers: {numbers}")
print(f"Letters: {letters}\n")

print(f"First three of fruits:  {fruits[first_three]}")
print(f"First three of numbers: {numbers[first_three]}")
print(f"First three of letters: {letters[first_three]}\n")

print(f"Middle section of fruits:  {fruits[middle_section]}")
print(f"Middle section of numbers: {numbers[middle_section]}")
print(f"Middle section of letters: {letters[middle_section]}")

# Example 5: Slicing strings
print("\n5. Slicing Strings")
print("-" * 40)

text = "Hello, World!"
print(f"Text: '{text}'\n")

first_five = slice(5)
last_six = slice(-6, None)  # None means "to the end"
every_other = slice(None, None, 2)

print(f"First 5 chars:  '{text[first_five]}'")
print(f"Last 6 chars:   '{text[last_six]}'")
print(f"Every other:    '{text[every_other]}'")

# Example 6: Common slice patterns
print("\n6. Common Slice Patterns")
print("-" * 40)

data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(f"Data: {data}\n")

# All elements
all_elements = slice(None)
print(f"All elements:        {data[all_elements]}")

# First half
half = len(data) // 2
first_half = slice(half)
print(f"First half:          {data[first_half]}")

# Second half
second_half = slice(half, None)
print(f"Second half:         {data[second_half]}")

# Every second element
evens = slice(0, None, 2)
print(f"Every 2nd (0,2,4...): {data[evens]}")

# Odd positions
odds = slice(1, None, 2)
print(f"Every 2nd (1,3,5...): {data[odds]}")

# Example 7: Slicing from the end
print("\n7. Negative Indices in Slices")
print("-" * 40)

words = ["one", "two", "three", "four", "five", "six", "seven"]
print(f"Words: {words}\n")

# Last 3 elements
last_three = slice(-3, None)
print(f"Last 3:              {words[last_three]}")

# All except last 2
except_last_two = slice(None, -2)
print(f"Except last 2:       {words[except_last_two]}")

# From 3rd-to-last to 1st-to-last
slice_end = slice(-3, -1)
print(f"From -3 to -1:       {words[slice_end]}")

# Example 8: Step parameter (skip elements)
print("\n8. Using Step to Skip Elements")
print("-" * 40)

alphabet = list("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
print(f"Alphabet: {alphabet}\n")

every_3rd = slice(0, None, 3)
print(f"Every 3rd letter:    {alphabet[every_3rd]}")

every_5th = slice(0, None, 5)
print(f"Every 5th letter:    {alphabet[every_5th]}")

every_4th_from_2 = slice(2, None, 4)
print(f"Every 4th from C:    {alphabet[every_4th_from_2]}")

print("\n" + "=" * 60)
print("Key Concepts:")
print("  - slice(stop) - from beginning to stop")
print("  - slice(start, stop) - from start to stop")
print("  - slice(start, stop, step) - with custom step")
print("  - Slice objects can be stored and reused")
print("  - None means 'default' (beginning, end, or step of 1)")
print("  - Negative indices count from the end")
print("=" * 60)

For more Slicing examples, click here


urllib

HTTP requests and URL handling with urllib.

Python
#!/usr/bin/env python3
"""
BASIC GET REQUEST - Using urllib.request
Demonstrates simple HTTP GET requests
"""

import urllib.request
import urllib.error

print("=" * 60)
print("BASIC GET REQUEST - urllib.request.urlopen()")
print("=" * 60)

# Example 1: Simple GET request
print("\n1. Simple GET Request")
print("-" * 40)
url = "http://httpbin.org/get"
try:
    response = urllib.request.urlopen(url)
    print(f"  URL: {url}")
    print(f"  Status: {response.status}")
    print(f"  Reason: {response.reason}")
    data = response.read()
    print(f"  Response length: {len(data)} bytes")
except urllib.error.URLError as e:
    print(f"  Error: {e.reason}")

# Example 2: Read response as string
print("\n2. Read Response as String")
print("-" * 40)
try:
    response = urllib.request.urlopen("http://httpbin.org/get")
    html = response.read().decode('utf-8')
    print(f"  Response type: {type(html)}")
    print(f"  First 100 chars: {html[:100]}...")
except Exception as e:
    print(f"  Error: {e}")

# Example 3: Response info
print("\n3. Get Response Headers")
print("-" * 40)
try:
    response = urllib.request.urlopen("http://httpbin.org/get")
    print(f"  Content-Type: {response.getheader('Content-Type')}")
    print(f"  Server: {response.getheader('Server')}")
    print(f"  Date: {response.getheader('Date')}")
except Exception as e:
    print(f"  Error: {e}")

# Example 4: Get URL info
print("\n4. Get URL Information")
print("-" * 40)
try:
    response = urllib.request.urlopen("http://httpbin.org/get")
    print(f"  URL: {response.url}")
    print(f"  Status: {response.status}")
    print(f"  Headers type: {type(response.headers)}")
except Exception as e:
    print(f"  Error: {e}")

# Example 5: Context manager
print("\n5. Using Context Manager")
print("-" * 40)
try:
    with urllib.request.urlopen("http://httpbin.org/get") as response:
        print(f"  Inside context: status = {response.status}")
        data = response.read()
        print(f"  Data length: {len(data)}")
    print("  Context closed automatically")
except Exception as e:
    print(f"  Error: {e}")

print("\n" + "=" * 60)
print("Key Points:")
print("  - urlopen() performs GET request by default")
print("  - Returns HTTPResponse object")
print("  - read() returns bytes, decode to string")
print("  - Use context manager for auto-cleanup")
print("  - Check status code for success")
print("=" * 60)

For more urllib examples, click here