ウェブスクレイピングのためのHTMLセレクタガイド

ガイド, スクレイピング, パイソン, Nov-08-20245分で読める

HTMLセレクタはウェブスクレイピングの鍵であり、開発者はウェブページ上の特定の要素をターゲットにすることができる。これらのセレクタを使用することで、開発者は正確にデータを抽出することができます。

Webスクレイピングは、HTML構造をナビゲートすることによってWebサイトからデータを取得することを含む。HTMLセレクタは、特定のタグ、属性、またはコンテンツをピンポイントで特定できる重要なものです。商品の価格や見出しを抽出する際にも、セレクタはあなたのガイドとなります。

HTMLセレクタを使用すると、データ抽出が効率的になり、エラーが減少します。重要な要素に集中し、オンライン・ソースからインサイトを収集する時間と労力を節約できます。

このブログでは、Pythonと"Beautifulsoup"ライブラリを使って、以下のセレクタの使い方を探ります:

  • IDセレクタ
  • クラス・セレクタ
  • 属性セレクタ
  • 階層型セレクタ
  • これらのセレクタを組み合わせる

IDセレクタ

HTMLでは、IDは特定の要素に割り当てられる一意の識別子であり、2つの要素が同じIDを共有することはありません。この一意性により、IDセレクタはウェブページ上の特定の要素をターゲットにするのに理想的です。例えば、複数のセクションがあるウェブページをスクレイピングする場合、各セクションが独自のIDを持っている可能性があり、干渉されることなく特定のセクションからデータを抽出することができます。

例えば このウェブサイト特に以下の要素 <div id="pages"> ...</div>

この要素は他のネストされたHTML要素を含みますが、主なことは、この要素がこのウェブサイト上でユニークであるということであり、例えばウェブサイトの特定のセクションをスクレイピングしたいときに、このシナリオを利用することができます。この場合、この要素には他の記事も含まれているので、以下で他のセレクタを使って説明します。ページ上のこのセクションがどのように見えるかを示します:

Pythonの "requests "ライブラリと "bs4 "ライブラリを使った簡単な例を見てみよう:

import requests
from bs4 import BeautifulSoup
# Step 1: Send a GET request to the website
url = "https://www.scrapethissite.com/pages/"
response = requests.get(url)
if response.status_code == 200:
   # Step 2: Parse the HTML content with BeautifulSoup
   soup = BeautifulSoup(response.text, 'html.parser')
  
   # Step 3: Find the div with id="pages"
   pages_div = soup.find("div", id="pages")
  
   # Step 4: Display the content or handle it as needed
   if pages_div:
       print("Content of the div with id='pages':")
       print(pages_div.text.strip())
   else:
       print("No div with id='pages' found.")
else:
   print(f"Failed to retrieve the webpage. Status code: {response.status_code}")

説明する:

  • リクエストを送信する:リクエストライブラリは、ターゲットURLからHTMLコンテンツを取得するためにGETリクエストを送信します。
  • HTMLを解析する:BeautifulSoupはHTMLを解析し、文書構造を検索できるようにする。
  • Find Specific <div>: を使用している。 soup.find("div", id="pages") を見つける。 <div> 要素を持つ id="pages".
  • 表示内容: もし <div> が見つかれば、その内容を表示する。見つからない場合は、メッセージが表示される。

IDセレクタの限界:

IDセレクタは強力ですが、限界があります。ページの読み込みごとに変化する動的なIDは、一貫したデータ抽出を困難にする可能性があります。このような状況では、信頼できる結果を得るために代替のセレクタを使用する必要があります。

クラス・セレクタ

クラス・セレクタは、同じクラスを共有する要素のグループをターゲットにできるため、柔軟性があります。そのため、繰り返し使用される要素があるウェブページには欠かせません。例えば、商品のリストを表示するウェブサイトでは、各商品に同じクラスを割り当てることができます。

を使ってもう一度例を挙げてみよう。 このウェブサイト.上記で我々は <div id="pages"> 要素にIDセレクタを使用し、このdiv要素の中に同じクラスを持つ記事がいくつかあります。

ご覧のように、同じクラスを持つ4つの要素がある。 <div class="page">

ウェブサイトではこうなっている:

以下のコードでは、クラス "page "を持つすべての要素を選択し、さらなる解析に使用できるリストを返します。

import requests
from bs4 import BeautifulSoup
# Step 1: Send a GET request to the website
url = "https://www.scrapethissite.com/pages/"
response = requests.get(url)
if response.status_code == 200:
   # Step 2: Parse the HTML content with BeautifulSoup
   soup = BeautifulSoup(response.text, 'html.parser')
  
   # Step 3: Find all elements with class="page"
   page_elements = soup.find_all("div", class_="page")
  
   # Step 4: Save each element's text content in a list
   pages_list = [page.text.strip() for page in page_elements]
  
   print("Content of elements with class 'page':")
   for i, page in enumerate(pages_list, start=1):
       print(f"Page {i}:")
       print(page)
       print("-" * 20)
else:
   print(f"Failed to retrieve the webpage. Status code: {response.status_code}")

説明する:

  • リクエストを送信します:リクエストを使ってURLにGETリクエストを送信し、ウェブページのHTMLコンテンツを取得します。
  • BeautifulSoupでHTMLを解析する:リクエストが成功した場合、BeautifulSoupはHTMLをパースし、要素を検索して対話できるようにする。
  • クラスからエレメントを探す: を使用している。 soup.find_all("div", class_="page") すべての <div> 要素をリストとして返す。
  • リストに保存: 各要素のテキスト・コンテンツを抽出してクリーニングし、pages_listというリストに保存します。

クラス・セレクタの限界

クラス・セレクタを使用する場合は、意図しない要素が選択されるなどの潜在的な問題に注意してください。1つの要素に複数のクラスがある場合、正確なターゲティングを達成するために追加のフィルタリングが必要になることがあります。

属性セレクタ

属性セレクタは、HTMLタグ内の特定の属性の存在、値、または部分的な値に基づいて要素をターゲットにすることができます。これは、クラスやIDが一意でない場合や、次のような動的属性を持つ要素をフィルタリングする必要がある場合に特に役立ちます。 データ または href = "/stock/stock_detail.html? の値をリンクに含める。

以下の例では、この ウェブページ にアクセスし、ソースのURLまたは ソース 属性を持つ。これが、html構造とウェブページ表示における要素の見え方です:

以下のコードでは、BeautifulSoupを利用して、すべての <img> 要素を抽出する。 ソース 属性をリストに格納する。

import requests
from bs4 import BeautifulSoup
# Step 1: Send a GET request to the website
url = "https://www.scrapethissite.com/pages/frames/"
response = requests.get(url)
if response.status_code == 200:
   # Step 2: Parse the HTML content with BeautifulSoup
   soup = BeautifulSoup(response.text, 'html.parser')
  
   # Step 3: Find all <img> elements with a 'src' attribute
   image_elements = soup.find_all("img", src=True)
  
   # Step 4: Save the 'src' attributes in a list
   images_list = [img['src'] for img in image_elements]
  
   print("Image sources found on the page:")
   for i, src in enumerate(images_list, start=1):
       print(f"Image {i}: {src}")
else:
   print(f"Failed to retrieve the webpage. Status code: {response.status_code}")

クラス・セレクタの限界

属性セレクタは、静的な属性を持つ要素しか選択できないため、JavaScriptで読み込まれる要素のような動的なコンテンツにはあまり効果的ではありません。また、安定したHTML構造に依存するため、ウェブサイトのレイアウトが頻繁に変更されると、セレクタが混乱してしまいます。また、複雑なフィルタリングや複数の条件を管理できないため、精度に限界があります。また、classやnameなどの属性が複数の要素で共有されている場合、意図しない要素を拾ってしまう可能性もあります。

階層型セレクタ

階層セレクタを使うと、HTML構造内の他の要素との位置関係に基づいてHTML要素をターゲットにすることができます。この方法は、データが親子形式で構成されているテーブルや入れ子リストを扱う場合に特に便利です。

この例では、階層セレクタを使って、ホッケーのチーム統計のテーブルからデータをスクレイピングしています。 このウェブページ.
テーブルには以下の行が含まれる。 <tr> 各チームを表し、各行には <td> チーム名、年、勝敗などの情報を含む。各行には class="チーム"と表示され、データの関連項目であることがわかる。からナビゲートすることで <table> to each <tr> and then to each <td>私たちは、構造化された方法で効率的にデータを取得することができます。

以下に、このテーブルがHTML構造のどこに位置し、実際のウェブページでどのように表示されるかを視覚化するのに役立つ2つの画像を掲載する。

では、階層セレクタを使ってどのようにこのデータを抽出できるのか、以下のコードを見てみよう:

import requests
from bs4 import BeautifulSoup

url = "https://www.scrapethissite.com/pages/forms/"

# Step 1: Send a GET request to the website
response = requests.get(url)

if response.status_code == 200:
   # Step 2: Parse the HTML content with BeautifulSoup
   soup = BeautifulSoup(response.text, 'html.parser')
  
   # Step 3: Find all rows in the table with class="team"
   teams_data = []
   team_rows = soup.find_all("tr", class_="team")
  
   # Step 4: Extract and store each team's data
   for row in team_rows:
       team = {
           "name": row.find("td", class_="name").text.strip(),
           "year": row.find("td", class_="year").text.strip(),
           "wins": row.find("td", class_="wins").text.strip(),
           "losses": row.find("td", class_="losses").text.strip(),
           "ot_losses": row.find("td", class_="ot-losses").text.strip(),
           "win_pct": row.find("td", class_="pct").text.strip(),
           "goals_for": row.find("td", class_="gf").text.strip(),
           "goals_against": row.find("td", class_="ga").text.strip(),
           "goal_diff": row.find("td", class_="diff").text.strip(),
       }
       teams_data.append(team)
  
   # Step 5: Display the extracted data
   for team in teams_data:
       print(team)
else:
   print(f"Failed to retrieve the webpage. Status code: {response.status_code}")

階層型セレクタの限界

階層型セレクタはHTML構造に依存するため、レイアウトを変更するとスクレイピング・スクリプトが簡単に壊れてしまいます。また、静的なコンテンツに限られ、JavaScriptによって動的に読み込まれた要素にはアクセスできません。これらのセレクタは、親子関係を通じて正確なナビゲーションを必要とすることが多く、深い入れ子構造では困難な場合があります。さらに、散在したデータを抽出する場合、特定の要素に到達するために複数の階層を横断しなければならないため、効率が悪くなる可能性があります。

より良いターゲティングのための複合セレクタの使用

セレクタの種類はそれぞれユニークな目的を持ち、それらを組み合わせることで、入れ子になったコンテンツや構造化されたコンテンツをナビゲートし、正確にデータを取得することができます。たとえば、IDセレクタを使用するとメイン・コンテンツ・エリアを特定することができ、クラス・セレクタを使用すると繰り返される要素を分離することができ、属性セレクタを使用すると特定のリンクや画像を抽出することができ、階層セレクタを使用すると特定のセクションに入れ子になっている要素に到達することができます。これらのテクニックを組み合わせることで、構造化データをスクレイピングするための強力なアプローチが提供される。

import requests
from bs4 import BeautifulSoup
# Target URL
url = "https://www.scrapethissite.com/pages/"
response = requests.get(url)
if response.status_code == 200:
   # Step 2: Parse the HTML content with BeautifulSoup
   soup = BeautifulSoup(response.text, 'html.parser')
  
   # Use ID selector to find the main content
   main_content = soup.find(id="pages")
  
   # Use class selector to find each "page" section
   pages = main_content.find_all("div", class_="page") if main_content else []
  
   # Extract details from each "page" section using hierarchical selectors
   for page in pages:
       # Use hierarchical selector to find title link and URL within each "page"
       title_tag = page.find("h3", class_="page-title")
       title = title_tag.text.strip() if title_tag else "No Title"
       link = title_tag.find("a")["href"] if title_tag and title_tag.find("a") else "No Link"
      
       # Use class selector to find the description
       description = page.find("p", class_="lead session-desc").text.strip() if page.find("p", class_="lead session-desc") else "No Description"
      
       print(f"Title: {title}")
       print(f"Link: {link}")
       print(f"Description: {description}")
       print("-" * 40)
else:
   print(f"Failed to retrieve the webpage. Status code: {response.status_code}")

規約の説明

  • IDセレクタ 必要なセクションを保持するid="pages "のメインコンテンツエリアを見つけることから始めます。
  • クラス・セレクター: このメインエリア内では class="ページ" をクリックして、関心のあるセクションを表す個々のコンテンツブロックを見つける。
  • 階層的セレクタ: 各 "ページ "ブロック内では、次のように使う:
    • page.find("h3", class_="page-title") をクリックしてタイトルを探す。
    • title_tag.find("a")["href"]. をクリックして、タイトルのアンカータグからリンクURLを取得します。
  • 属性セレクタ:各リンクのhref 属性にアクセスし、各セクションに関連する正確なURLを取得します。
  • 出力:スクリプトは、各セクションのタイトル、リンク、説明を表示し、ページからスクレイピングされたデータの構造化されたビューを提供する。

結論

Webスクレイピングでは、HTMLセレクタの使い方を知ることで、データ抽出のスキルが大幅に向上し、重要な情報を正確に収集できるようになります。ID、class、attribute、hierarchicalセレクタなどのセレクタは、それぞれ異なるスクレイピングタスクに特有の用途があります。これらのツールを併用することで、様々なウェブスクレイピングの課題に自信を持って対応することができます。

練習のために、 Scrape This Siteや Books to Scrapeのようなサイトは、あなたのスキルを磨くのに役立つ素晴らしい例を提供しています。また、もし何か助けが必要だったり、ウェブスクレイピングに興味のある人たちと繋がりたい場合は、私たちのDiscordチャンネル https://discord.com/invite/scrape に気軽に参加してください。

ハッピー・スクレイピング!