メルカリをスクレイピングしていきます。
最初は、カテゴリー一覧ページからスクレイピングします。
なぜ、カテゴリー一覧ページからスクレイピングすると思いますか?
その回答は、後ほど説明します。
本記事の内容
- スクレイピングの種類
- 大量データのスクレイピング方法
- カテゴリー一覧ページのスクレイピング
- メルカリの珍しいスクレイピング対策
それでは、上記に沿って解説していきます。
スクレイピングの種類
スクレイピングには、大きく分けて二つの種類があります。
- 大量データの抜き出し
- 指定ページの監視
大量データとは、その言葉通りに多くのデータのことです。
場合によっては、全データということもあるでしょう。
また、指定した分類のみのデータということもあります。
分類の例としては、以下のようなモノがあります。
- カテゴリー
- 年
- キーワード
上記の大量データの抜き出しは、イメージしやすいでしょうね。
もう一つの指定ページの監視は、あまり認知されていないかもしれません。
例えば、ある商品の在庫をチェックするなどで使う手段です。
実際、私はSwitchが手に入りにくいときにその手をつかいました。
販売ページにおいて在庫があるなら、「〇」が表示される仕様だったはずです。
「〇」を認識したら、自動でLineに通知するようにしていました。
当時は、その仕組みによりSwitchを手に入れることができました。
スクレイピングには、そのような使い方もあるという良い例ですね。
今回は、大量データの抜き出しのパターンとなります。
このパターンを説明していきます。
大量データのスクレイピング方法
大量データを取得するためには、各データ(メルカリなら商品)のURLを知る必要があります。
正直、このデータのURLリストを用意することがスクレイピングの肝となります。
ここは、設計能力が問われる部分と言っても過言ではありません。
つまり、対象サイトのデータの持ち方(データ構造)を理解する必要があるのです。
このことをターゲットとなるメルカリで確認していきましょう。
まず、スクレイピングする際、カテゴリー一覧からデータを抽出していきます。
カテゴリー一覧をスクレイピングすれば、カテゴリーIDを取得できます。
メルカリにもカテゴリー一覧ページが存在します。
https://www.mercari.com/jp/category/
現時点では、以下が大カテゴリーとして扱われています。
大カテゴリーの数は、全部で13個ですね。
大カテゴリーの下には、多くのカテゴリーが紐づいています。
しかし、大カテゴリーのIDを取得できれば、それでOKです。
次に、カテゴリーIDからそのカテゴリーに紐づく商品一覧ページのURLを作成できます。
そして、商品一覧ページをスクレイピングすれば、商品IDを取得できます。
さらに、商品IDからその商品詳細ページのURLが作成可能です。
このようにドリルダウンしていくことで、最小単位となる商品までたどり着けます。
結果として、商品ページのURLリストを作成できます。
このURLリストがあれば、あとはそれをバッチ処理で対応していくだけです。
では、メルカリのカテゴリーページをスクレイピングしてみましょう。
カテゴリー一覧ページのスクレイピング
これから実際に動くプログラムを載せていきます。
各自でそのプログラムを動かす場合は、次の記事で準備をしてください。
そして、絶対に【必須】は読んでください。
そうしないと、大変なことになりかねません。
準備が整ったら、次のコードを動かしていきましょう。
サンプルコードとして、現時点(2021年2月4日)で動くコードを載せています。
サンプルコード
import bs4 import traceback from selenium import webdriver from selenium.webdriver.chrome.options import Options # ドライバーのフルパス CHROMEDRIVER = "chromedriver.exeのパス" # ドライバー準備 def get_driver(): # ヘッドレスモードでブラウザを起動 options = Options() options.add_argument('--headless') # ブラウザーを起動 driver = webdriver.Chrome(CHROMEDRIVER, options=options) return driver # 対象ページのソース取得 def get_source_from_page(driver, page): try: # ターゲット driver.get(page) driver.implicitly_wait(10) # 見つからないときは、10秒まで待つ page_source = driver.page_source return page_source except Exception as e: print("Exception\n" + traceback.format_exc()) return None # ソースからスクレイピングする def get_data_from_source(src): # スクレイピングする soup = bs4.BeautifulSoup(src, features='lxml') #print(soup) try: info = [] # 大カテゴリー毎に要素を取得 elems = soup.find_all(attrs={"data-test": "category-list-individual-box"}) for elem in elems: # 最初に出てくるaタグ(「すべて」)の要素を取得 a_tag = elem.find("a") if a_tag: href = a_tag.attrs['href'] category_id = href.replace("/jp/category/", "") info.append(category_id) return info except Exception as e: print("Exception\n" + traceback.format_exc()) return None if __name__ == "__main__": # 対象ページURL page = "https://www.mercari.com/jp/category/" # ブラウザのdriver取得 driver = get_driver() # ページのソース取得 source = get_source_from_page(driver, page) # ソースからデータ抽出 data = get_data_from_source(source) # 閉じる driver.quit() # 結果表示 print(data)
上記を実行すると、次の結果が表示されます。
大カテゴリーのIDです。
['1', '2', '3', '4', '5', '1328', '6', '7', '8', '9', '1027', '1318', '10']
全部で13個あるので、上手くスクレイピングできています。
正直、13個程度ならスクレイピングまでする必要はありませんけどね。
プログラムの内容は、細かくは説明しません。
「大量データのスクレイピング方法」をベースにプログラミングしています。
それに、コメントを見れば大体は理解できるはずです。
以下だけ説明しておきましょう。
# ドライバーのフルパス CHROMEDRIVER = "chromedriver.exeのパス"
これは、それぞれの環境で異なるでしょう。
各自で値を変更してください。
以上で終わってもいいのですが、最後にメルカリのスクレイピング対策について説明しておきます。
メルカリの珍しいスクレイピング対策
「カテゴリー一覧ページのスクレイピング」では、サクッとスクレイピングしています。
しかし、少しだけ苦労しました。
それは、メルカリのサイトがスクレイピング対策をしているからです。
それも地味に嫌な対策をしてきます。
私は、過去に多くのサイトをスクレイピングしてきました。
しかし、メルカリの対策は初めてのケースかもしれません。
その対策とは、タグ要素のclass名をセッション毎に変更するのです。
例えば、カテゴリー一覧には次ようなタグが存在しています。
「name=”category-1″」で検索すれば、ヒットします。
<div name="category-1" data-test="category-list-individual-box" class="sc-kvkilB ducAME">
ただし、「class=”sc-kvkilB ducAME”」部分は異なる値のはずです。
このようなclass名の値が、セッション毎に異なってきます。
だから、class名を使って要素を抽出できないのです。
スクレイピングをやる上で、これは地味にダメージを受けます。
しかし、データ属性に関してはセッション毎に変更することはありません。
上記の例でいえば、「data-test=”category-list-individual-box”」の部分です。
そのため、メルカリではclass名ではなくデータ属性でスクレイピングをしていきます。
次回は、商品一覧画面のスクレイピングを行う予定です。
その際にも、この考え方で対応できるのかどうかということですね。
やっぱり、スクレイピングは面白いです。
各サイトのエンジニアとの知恵比べが、単純にワクワクします。