Python project 08
Python Web Scraper Project
Last updated: 31 August 2026
Create a small web-page title and link collector using only Python’s standard library. This project introduces HTTP requests, HTML parsing, URLs, and responsible data collection.
Learn ethical Python web automationView all project ideas
What you will build
The program fetches a public HTML page you are allowed to access, displays its title, and lists up to ten unique links it finds.
Skills practised
- urllib requests
- HTMLParser
- URLs and relative links
- Network error handling
Requirements
- Python 3.8 or later
- A terminal or command prompt
- No external packages
- About 30 minutes to build
Full Python code
Save it as web_scraper.py, then run it from a terminal.
"""Fetch and display the title and links from a public web page you are allowed to access."""
from html.parser import HTMLParser
from urllib.error import HTTPError, URLError
from urllib.parse import urljoin, urlparse
from urllib.request import Request, urlopen
class PageSummary(HTMLParser):
def __init__(self):
super().__init__()
self.in_title = False
self.title_parts = []
self.links = []
def handle_starttag(self, tag, attrs):
attributes = dict(attrs)
if tag == "title":
self.in_title = True
if tag == "a" and attributes.get("href"):
self.links.append(attributes["href"])
def handle_endtag(self, tag):
if tag == "title":
self.in_title = False
def handle_data(self, data):
if self.in_title:
self.title_parts.append(data.strip())
def fetch_page(url):
request = Request(url, headers={"User-Agent": "LearningWebScraper/1.0"})
with urlopen(request, timeout=15) as response:
content_type = response.headers.get_content_type()
if content_type != "text/html":
raise ValueError(f"Expected an HTML page, received {content_type}.")
return response.read().decode(response.headers.get_content_charset() or "utf-8", errors="replace")
def main():
print("Web Page Title and Link Collector")
print("Only use this on public pages you are allowed to access. Respect each site's terms and robots.txt.\n")
url = input("Public page URL (including https://): ").strip()
if urlparse(url).scheme not in {"http", "https"}:
print("Enter a complete http or https URL.")
return
try:
html = fetch_page(url)
except (HTTPError, URLError, ValueError) as error:
print(f"Could not fetch the page: {error}")
return
summary = PageSummary()
summary.feed(html)
title = " ".join(part for part in summary.title_parts if part) or "No title found"
unique_links = []
for link in summary.links:
absolute = urljoin(url, link)
if absolute not in unique_links:
unique_links.append(absolute)
print(f"\nPage title: {title}")
print(f"Links found: {len(unique_links)}")
for link in unique_links[:10]:
print(f"- {link}")
if len(unique_links) > 10:
print("- ...")
if __name__ == "__main__":
main()
How it works
fetch_page() requests an HTML page with a clear learning user-agent. PageSummary collects the title and link attributes during parsing, then urljoin() turns relative links into complete URLs.
Run the project
- Run
python web_scraper.py. - Enter a public URL you are permitted to access.
- Read the title and first ten unique links.
- Stop if a site disallows the activity or requires authentication.
Notes for your notebook
- Permission: follow terms of service and robots.txt.
- Rate limits: never overload a website with repeated requests.
- Public content: do not bypass logins, paywalls, or access controls.
Ways to extend it
Add a CSV export, optional CSS-selector parsing with Beautiful Soup, or a polite request delay for approved data-collection tasks.
What to learn next
Strengthen your foundations through Python functions and choose another task from the Softenant project library.