Pythonプログラム練習問題10問:Webスクレイピング入門と実践
Webスクレイピングは、ウェブサイトからデータを自動的に抽出する技術です。Pythonはその柔軟性と豊富なライブラリのおかげで、Webスクレイピングに非常に適した言語として広く利用されています。本記事では、Webスクレイピングの基礎から応用までを理解できるよう、Pythonプログラム練習問題10問を通して解説します。
対象読者:
- プログラミング初心者~中級者
- Pythonの基本的な文法を理解している方
- Webスクレイピングに興味がある方
前提知識:
- Pythonの基本構文 (変数、データ型、制御構造、関数など)
- HTML/CSSの基礎知識 (タグ、属性など)
- HTTPリクエストとレスポンスの基本的な概念
使用するライブラリ:
- requests: ウェブサイトへのHTTPリクエストを送信するためのライブラリ。
- Beautiful Soup 4: HTMLやXMLファイルを解析し、必要なデータを抽出するためのライブラリ。
- lxml: Beautiful Soupで使用される高速なパーサー。 (オプション)
これらのライブラリは以下のコマンドでインストールできます。
pip install requests beautifulsoup4 lxml
1. WebサイトへのアクセスとHTMLの取得
問題: https://www.example.com/
にアクセスし、HTMLコンテンツを取得するプログラムを作成してください。
解説:
まず、requests
ライブラリを使ってウェブサイトにGETリクエストを送信します。レスポンスオブジェクトからHTMLコンテンツを取り出し、文字列として保存します。このプロセスは、Webサーバーに対して特定のURLのリソース(この場合はHTMLドキュメント)を要求する最初のステップです。
import requests url = "https://www.example.com/" try: response = requests.get(url) response.raise_for_status() # HTTPエラーが発生した場合に例外を発生させる html_content = response.text print(html_content[:500]) # 最初の500文字を表示 except requests.exceptions.RequestException as e: print(f"Error fetching URL: {e}")
ポイント:
requests.get()
は指定されたURLへのGETリクエストを送信します。これは、Webサーバーに「このページのコンテンツを送ってください」と要求するものです。response.raise_for_status()
は、HTTPステータスコードがエラーを示す場合 (4xxまたは5xx) に例外を発生させます。例えば、404 Not Foundはページが見つからないことを意味し、500 Internal Server Errorはサーバー側の問題を示します。この処理により、スクリプトがエラーを検出し、適切に対応することができます。response.text
はレスポンスのコンテンツを文字列として取得します。これは、HTMLドキュメント全体を表すテキストデータです。
Explanation in English:
This problem introduces the fundamental step of accessing a website and retrieving its HTML content using the requests
library. The code sends a GET request to the specified URL (https://www.example.com/
) and then extracts the HTML content from the response object as a string. The response.raise_for_status()
method is crucial for error handling, raising an exception if the HTTP status code indicates an error (e.g., 404 Not Found). Finally, the first 500 characters of the retrieved HTML are printed to the console.
2. HTMLの解析とタイトルの抽出
問題: 上記のHTMLコンテンツから<title>
タグの内容を抽出し、表示するプログラムを作成してください。
解説:
Beautiful Soupを使ってHTMLを解析し、<title>
タグを探してその内容を取得します。Beautiful Soupは、複雑なHTML構造を扱いやすくするための強力なツールです。
import requests from bs4 import BeautifulSoup url = "https://www.example.com/" try: response = requests.get(url) response.raise_for_status() html_content = response.text soup = BeautifulSoup(html_content, 'html.parser') # HTMLパーサーを指定 title = soup.title.text print(f"Title: {title}") except requests.exceptions.RequestException as e: print(f"Error fetching URL: {e}") except AttributeError as e: print(f"Error finding title tag: {e}")
ポイント:
BeautifulSoup(html_content, 'html.parser')
はHTMLコンテンツを解析し、Beautiful Soupオブジェクトを作成します。'html.parser'
はPython標準のパーサーですが、より高速な'lxml'
や'html5lib'
も利用できます。lxml
はC言語で実装されており、通常は最も高速です。html5lib
は、HTML5の仕様に準拠した解析を提供します。soup.title
はHTMLドキュメント内の<title>
タグを表すBeautiful Soupオブジェクトを取得します。これは、HTML構造をナビゲートするための基本的な操作です。.text
属性を使って、タグの内容 (テキスト) を取得します。 これにより、<title>
タグの実際のタイトル文字列が抽出されます。
Explanation in English:
This problem demonstrates how to parse the retrieved HTML content using Beautiful Soup and extract the title of the webpage. The code creates a BeautifulSoup object from the HTML string, specifying 'html.parser' as the parser. Then, it uses soup.title
to access the <title>
tag within the parsed HTML structure and extracts its text content using .text
. The extracted title is then printed to the console.
3. 特定のクラスを持つ要素の抽出
問題: ウェブサイトから、クラス名が "example-class" のすべての要素を抽出し、そのテキスト内容を表示するプログラムを作成してください。
解説:
Beautiful Soupのfind_all()
メソッドを使って、特定のクラス名を持つ要素を検索します。CSSセレクタを使用して要素を選択する方法を示しています。
import requests from bs4 import BeautifulSoup url = "https://www.example.com/" # クラス名が存在するURLに変更 try: response = requests.get(url) response.raise_for_status() html_content = response.text soup = BeautifulSoup(html_content, 'html.parser') elements = soup.find_all('div', class_='example-class') # クラス名で検索 for element in elements: print(element.text) except requests.exceptions.RequestException as e: print(f"Error fetching URL: {e}") except AttributeError as e: print(f"Error finding elements with class 'example-class': {e}")
ポイント:
soup.find_all('div', class_='example-class')
は、HTMLドキュメント内のすべての<div>
タグで、class
属性が "example-class" であるものを検索します。class_
のようにアンダースコアを使用しているのは、Pythonの予約語であるclass
を避けるためです。- 複数の要素が見つかった場合は、ループを使って各要素を処理します。
Explanation in English:
This problem focuses on extracting elements with a specific class name from the HTML content. The code uses soup.find_all('div', class_='example-class')
to locate all <div>
tags that have the class attribute set to "example-class". The extracted elements are then iterated through, and their text content is printed to the console.
4. 特定のIDを持つ要素の抽出
問題: ウェブサイトから、IDが "example-id" の要素を抽出し、そのテキスト内容を表示するプログラムを作成してください。
解説:
find()
メソッドは、指定された条件に一致する最初の要素のみを返します。特定の要素を確実に取得したい場合に役立ちます。
import requests from bs4 import BeautifulSoup url = "https://www.example.com/" # IDが存在するURLに変更 try: response = requests.get(url) response.raise_for_status() html_content = response.text soup = BeautifulSoup(html_content, 'html.parser') element = soup.find('div', id='example-id') # IDで検索 if element: print(element.text) else: print("Element with ID 'example-id' not found.") except requests.exceptions.RequestException as e: print(f"Error fetching URL: {e}") except AttributeError as e: print(f"Error finding element with ID 'example-id': {e}")
ポイント:
soup.find('div', id='example-id')
は、HTMLドキュメント内の最初の<div>
タグで、id
属性が "example-id" であるものを検索します。- 要素が見つからない場合は、
element
がNone
になるため、条件分岐で処理する必要があります。
Explanation in English:
This problem demonstrates how to extract a specific element based on its ID attribute. The code uses soup.find('div', id='example-id')
to locate the first <div>
tag with the ID "example-id". If the element is found, its text content is printed; otherwise, a message indicating that the element was not found is displayed.
5. すべてのリンクの抽出
問題: ウェブサイトからすべての<a href="...">
タグを抽出し、そのURLを表示するプログラムを作成してください。
解説:
find_all()
メソッドを使って、すべての<a href="...">
タグを検索し、href
属性の値を取得します。ウェブサイト内の他のページへのリンクを収集する場合に役立ちます。
import requests from bs4 import BeautifulSoup url = "https://www.example.com/" try: response = requests.get(url) response.raise_for_status() html_content = response.text soup = BeautifulSoup(html_content, 'html.parser') links = soup.find_all('a', href=True) # href属性を持つ<a>タグを検索 for link in links: print(link['href']) except requests.exceptions.RequestException as e: print(f"Error fetching URL: {e}") except KeyError as e: print(f"Error accessing 'href' attribute: {e}")
ポイント:
soup.find_all('a', href=True)
は、HTMLドキュメント内のすべての<a>
タグで、href
属性を持つものを検索します。- リンクのURLは、タグの
href
属性の値として格納されています。link['href']
でアクセスできます。
Explanation in English:
This problem focuses on extracting all hyperlinks from the webpage. The code uses soup.find_all('a', href=True)
to locate all anchor tags (<a>
) that have an href
attribute, which specifies the URL of the link. The extracted URLs are then printed to the console.
6. 特定のテキストを含む要素の抽出
問題: ウェブサイトから、テキスト内容に "example" という文字列が含まれるすべての<p>
タグを抽出し、そのテキスト内容を表示するプログラムを作成してください。
解説:
Beautiful Soupのfind_all()
メソッドとstring
属性を使って、特定のテキストを含む要素を検索します。キーワードに基づいてコンテンツをフィルタリングする場合に役立ちます。
import requests from bs4 import BeautifulSoup url = "https://www.example.com/" try: response = requests.get(url) response.raise_for_status() html_content = response.text soup = BeautifulSoup(html_content, 'html.parser') paragraphs = soup.find_all('p', string=lambda text: "example" in text) # テキストに"example"が含まれる<p>タグを検索 for paragraph in paragraphs: print(paragraph.text) except requests.exceptions.RequestException as e: print(f"Error fetching URL: {e}") except AttributeError as e: print(f"Error finding paragraphs containing 'example': {e}")
ポイント:
string=lambda text: "example" in text
は、<p>
タグのテキスト内容が "example" という文字列を含むかどうかをチェックするラムダ関数を指定します。find_all()
メソッドは、このラムダ関数がTrue
を返す要素のみを検索します。
Explanation in English:
This problem demonstrates how to extract elements that contain specific text. The code uses soup.find_all('p', string=lambda text: "example" in text)
to locate all <p>
tags whose text content contains the word "example". The extracted paragraphs are then iterated through, and their text content is printed to the console.
7. 複数の条件での要素抽出
問題: ウェブサイトから、クラス名が "item" であり、かつテキスト内容に "product" という文字列が含まれるすべての<li>
タグを抽出し、そのテキスト内容を表示するプログラムを作成してください。
解説:
find_all()
メソッドで複数の条件を指定します。複雑なフィルタリング要件に対応できます。
import requests from bs4 import BeautifulSoup url = "https://www.example.com/" # 該当する要素が存在するURLに変更 try: response = requests.get(url) response.raise_for_status() html_content = response.text soup = BeautifulSoup(html_content, 'html.parser') items = soup.find_all('li', class_='item', string=lambda text: "product" in text) # 複数の条件を組み合わせる for item in items: print(item.text) except requests.exceptions.RequestException as e: print(f"Error fetching URL: {e}") except AttributeError as e: print(f"Error finding items with class 'item' and containing 'product': {e}")
ポイント:
find_all()
メソッドに複数の引数を渡すことで、複数の条件を指定できます。 この例では、class_='item'
でクラス名が "item" である要素を検索し、さらにstring=lambda text: "product" in text
でテキスト内容に "product" という文字列が含まれる要素を検索しています。
Explanation in English:
This problem demonstrates how to extract elements based on multiple criteria. The code uses soup.find_all('li', class_='item', string=lambda text: "product" in text)
to locate all <li>
tags that have the class name "item" and whose text content contains the word "product". The extracted list items are then iterated through, and their text content is printed to the console.
8. データの整形と保存
問題: ウェブサイトからすべての<dt>
タグの内容を抽出し、CSVファイルとして保存するプログラムを作成してください。
解説:
抽出したデータをリストに格納し、csv
ライブラリを使ってCSVファイルに書き込みます。スクレイピングで収集したデータを構造化して保存する場合に役立ちます。
import requests from bs4 import BeautifulSoup import csv url = "https://www.example.com/" # 該当する要素が存在するURLに変更 try: response = requests.get(url) response.raise_for_status() html_content = response.text soup = BeautifulSoup(html_content, 'html.parser') dt_tags = soup.find_all('dt') # <dt>タグを検索 data = [tag.text for tag in dt_tags] # テキスト内容をリストに格納 with open('output.csv', 'w', newline='', encoding='utf-8') as csvfile: writer = csv.writer(csvfile) writer.writerow(['Data']) # ヘッダー行 for item in data: writer.writerow([item]) except requests.exceptions.RequestException as e: print(f"Error fetching URL: {e}") except AttributeError as e: print(f"Error finding dt tags: {e}")
ポイント:
csv.writer()
はCSVファイルにデータを書き込むためのオブジェクトを作成します。writerow()
メソッドを使って、1行のデータを書き込みます。encoding='utf-8'
を指定することで、日本語などの文字化けを防ぎます。
Explanation in English:
This problem demonstrates how to extract data from a webpage and save it to a CSV file. The code extracts the text content of all <dt>
tags, stores them in a list, and then writes them to a CSV file named "output.csv". The csv
library is used for writing the data in a structured format.
9. ページネーションへの対応
問題: ウェブサイトがページネーション (ページ番号) を使用している場合、すべてのページからデータを抽出するプログラムを作成してください。
解説:
for
ループを使って、各ページのURLにアクセスし、HTMLを解析してデータを抽出します。大規模なWebサイトからデータを収集する場合に役立ちます。
import requests from bs4 import BeautifulSoup base_url = "https://www.example.com/page/" # ページネーションのベースURLに変更 num_pages = 5 # 抽出するページ数 all_data = [] for page_num in range(1, num_pages + 1): url = base_url + str(page_num) + "/" try: response = requests.get(url) response.raise_for_status() html_content = response.text soup = BeautifulSoup(html_content, 'html.parser') # 各ページのHTMLを解析してデータを抽出する処理をここに記述 data = soup.find_all('p') # 例としてすべての<p>タグを抽出 all_data.extend([item.text for item in data]) except requests.exceptions.RequestException as e: print(f"Error fetching URL {url}: {e}") # 抽出したデータを処理する (例: CSVファイルに保存) print(all_data)
ポイント:
base_url
はページネーションのベースURLです。num_pages
は抽出するページ数です。- 各ページのURLを構築し、
requests.get()
でアクセスします。 - 抽出したデータをリストに格納し、必要に応じて処理します。
Explanation in English:
This problem demonstrates how to handle pagination when scraping a website. The code iterates through each page of the website (up to num_pages
), constructs the URL for each page, and extracts data from the HTML content. This is useful for scraping large websites that use pagination to divide their content across multiple pages.
10. robots.txt の確認とリクエスト制限
問題: ウェブサイトの robots.txt
ファイルを確認し、スクレイピングが許可されているか確認するプログラムを作成してください。また、サーバーへの負荷を軽減するために、リクエスト間に遅延を入れる処理を追加してください。
解説:
ウェブサイトの robots.txt
ファイルは、クローラー (ボット) がアクセスしてはいけないページやディレクトリを指定するためのファイルです。スクレイピングを行う前に robots.txt
を確認し、許可されている範囲内でスクレイピングを行うことが重要です。また、サーバーへの負荷を軽減するために、リクエスト間に遅延を入れることで、サーバーに過剰な負担をかけないようにします。
import requests from bs4 import BeautifulSoup import time url = "https://www.example.com/" try: # robots.txt の確認 robots_url = url + "/robots.txt" response = requests.get(robots_url) response.raise_for_status() robots_content = response.text print("Robots.txt content:") print(robots_content) # スクレイピング処理 (例: タイトル抽出) response = requests.get(url) response.raise_for_status() html_content = response.text soup = BeautifulSoup(html_content, 'html.parser') title = soup.title.text print(f"Title: {title}") # リクエスト間に遅延を入れる time.sleep(1) # 1秒待機 except requests.exceptions.RequestException as e: print(f"Error: {e}")
ポイント:
robots_url
はウェブサイトのrobots.txt
ファイルのURLです。time.sleep()
関数を使って、リクエスト間に遅延を入れることができます。 遅延時間は、サーバーの負荷状況やスクレイピングポリシーに合わせて調整してください。
Explanation in English:
This problem emphasizes the importance of respecting website policies and avoiding overloading servers when scraping data. The code first checks the robots.txt
file to see if scraping is allowed, then proceeds to scrape the webpage (in this example, extracting the title). Finally, it introduces a delay between requests using time.sleep()
to avoid overwhelming the server.
Additional Considerations and Best Practices for Web Scraping:
User-Agent Spoofing: Many websites block requests from known web scraping tools. To avoid this, you can set a custom User-Agent header in your request:
python headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'} response = requests.get(url, headers=headers)
Error Handling: Implement robust error handling to gracefully handle situations where a website is unavailable or the HTML structure changes unexpectedly. Use
try...except
blocks to catch exceptions and log errors appropriately.Rate Limiting: Be mindful of the rate at which you make requests to avoid overwhelming the server. Implement delays between requests, and consider using techniques like exponential backoff if you encounter temporary errors.
Respect Website Terms of Service: Always review a website's terms of service before scraping data. Some websites explicitly prohibit web scraping, and violating these terms can have legal consequences.
Data Storage and Processing: Consider how you will store and process the scraped data. Common options include CSV files, databases (e.g., SQLite, MySQL, PostgreSQL), and NoSQL databases (e.g., MongoDB).
Dynamic Content (JavaScript Rendering): If a website heavily relies on JavaScript to render its content, standard web scraping techniques using
requests
andBeautiful Soup
may not be sufficient. In such cases, you might need to use tools like Selenium or Puppeteer, which can execute JavaScript code and render the page before extracting data.API Alternatives: Before resorting to web scraping, check if the website provides an API (Application Programming Interface). APIs often offer a more structured and reliable way to access data than scraping HTML directly.
Legal and Ethical Considerations: Be aware of copyright laws and privacy regulations when scraping data. Avoid collecting personal information without consent, and respect intellectual property rights.
Scalability: If you need to scrape large amounts of data from many websites, consider using a distributed web scraping framework like Scrapy or Apify. These frameworks can help you manage concurrency, handle errors, and scale your scraping operations efficiently.
Advanced Web Scraping Techniques:
- XPath: XPath is a query language for navigating XML documents (including HTML). It provides a more powerful and flexible way to select elements than CSS selectors. The
lxml
library supports XPath queries in Beautiful Soup. - Regular Expressions: Regular expressions can be used to extract specific patterns from text data. While they can be useful, they are often less robust than using HTML parsers like Beautiful Soup or XPath.
- Web Scraping Frameworks (Scrapy): Scrapy is a powerful and flexible web scraping framework that provides tools for crawling websites, extracting data, and storing it in various formats. It's well-suited for large-scale web scraping projects.
- Headless Browsers (Selenium, Puppeteer): These tools allow you to automate browser actions, such as clicking buttons, filling out forms, and scrolling through pages. They are essential for scraping dynamic websites that rely heavily on JavaScript.
By mastering these concepts and techniques, you can effectively scrape data from a wide range of websites while respecting their terms of service and avoiding overloading their servers. Remember to always prioritize ethical considerations and legal compliance when engaging in web scraping activities.