Closed3

soup.find() vs soup.select() in Python BeautifulSoup4

PeacockPeacock

モチベーション

PythonのBeautifulSoup4でsoup.find()soup.select()の使い分けを悩んで調べたのでメモ

個人的見解

単純なスクレイピングの場合、この(プロダクトの実装)レベルでパフォーマンスチューニングに走るのは悪手なので、読みやすさやメンテナンス性を重視して使い分けるとよい

特に1回数ページほどのバッチタスクの場合、顕著ではないのは自明であるため。

パフォーマンス的な話

  • 内部実装のパフォーマンス的には.find()の方が効率的
    • dictのindex accessをつかっているから
    • .selectだと、一度reモジュールを呼び出してタグの中身を解析している
      • BeautifulSoup 4.7で追加されたコードとのことなので、こちらの方がtype hintもある

細かい使い分けをどうするか

  • .selectはHTML構造的に深いタグを取る場合に使いやすい
    • .findをチェーンして使うことになると、早期ガードの可能性も増える
      • bs4.Tag.find("div").divなどになり、未定義属性にアクセスすることになるので、メンテナンス性が損なわれる
  • 深くない(直接の子要素でclass指定などで取れる)場合は.findでよい
  • 再帰的に取りたい場合は.findを使うしかない
PeacockPeacock

Example

<body>
    <h1 class="heading1">This is title!!</h1>
    <div>
        <a class="link-style1" href="#h1">this is an external URL</a>
     </div>
        <div>this is a veeeeery loooong detail</div>
    <div>
        <h2>This is the summary<h2>
        <ul>
            <li>
                <a class="link-style2" href="#section1">this is an internal URL 1</a>
            </li>
            <li>
                <a class="link-style2" href="#section2">this is an internal URL 2</a>
            </li>
            <li>
                <a class="link-style2" href="#section3">this is an internal URL 3</a>
            </li>
        </ul>
    </div>
</body>
soup = bs4.beautifulsoup(html, "html.parser")
recomennded_select: str = soup.select_one("#main > div > a.link-style1")
# -> '<a class="some-class">this is an anchor URL</a>'

may_use_find1 = soup.find("h1", class_="heading1")
# -> '<h1 class="heading1">This is title!!</h1>'
recommended_find2 = soup.find_all("a", recursive=True)
# -> 
# [
# '<a class="link-style1" href="#h1">this is an external URL</a>', 
# '<a class="link-style2" href="#section1">this is an internal URL 1</a>'
# ...
# ]
このスクラップは2023/01/03にクローズされました