技術は使ってなんぼ

自分が得たものを誰かの役に立てたい

【Python】yahooショッピングの商品名と値段をスクレイピングしてみた

機械学習系の仕事だけでなく、データサイエンス系の仕事もやってみたい。。


そもそもデータサイエンティストって、呼び名がもうなんかかっこいいじゃないですか。


私は・・『データサイエンティスト』だ!


ってことで思いついた今回のMisson!

【Mission】

「yahooショッピングで検索をかけた結果、表示される商品名と値段をスクレイピングせよ!」


という訳で書いてみたソースコードがこちら。

import urllib.robotparser
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import requests
from bs4 import BeautifulSoup
import csv

# ECサイトURLを指定
url = "https://shopping.yahoo.co.jp/"
keywd = "python 本"

def robot_check(url):
    rp = urllib.robotparser.RobotFileParser()

    rp.set_url(url + "robots.txt")
    rp.read()

    # クローリングへの指示書があるか
    req_rate = rp.request_rate("*")
    if req_rate is None:
        print("クローリングへの指示書はありません")

        # URLの取得が許可されているかを確認
        req_URL = rp.can_fetch("*", url)
        if req_URL == True:
            print("URLの取得も許可されています。これよりスクレイピングを開始します。")
        else:
            print("URLの取得が許可されていません。スクレイピングを中止します")
    else:
        print("クローリングへの指示書があります。問題がないか、利用規約を確認ください。")


def scraping(url, keywd):
    option = Options()

    # Chromeオプションについては以下URLを参照
    # http://chrome.half-moon.org/43.html#l3e9a23d

    # Chromeの通知バーを表示しない
    option.add_argument("--disable-infobars")
    # 最大化で起動
    option.add_argument("--start-maximized")
    # 拡張機能を無効化
    option.add_argument("--disable-extensions")

    # ポップアップ通知を、1:許可、2:ブロック
    option.add_experimental_option("prefs", {"profile.default_content_setting_values.notifications": 2})

    driver = webdriver.Chrome(options=option, executable_path="driver/chromedriver.exe")

    driver.get(url)

    # 検索キーワードを指定
    elem_keyword = driver.find_element_by_name("p")
    # 検索キーワードを入力
    elem_keyword.send_keys(keywd)
    # 検索ボタンを押す
    driver.find_element_by_id("ss_srch_btn").click()
    
    
    # 検索結果のページのURLを取得
    cur_url = driver.current_url

    # 検索結果のURLのHTMLを取得
    r_html = requests.get(cur_url)

    soup = BeautifulSoup(r_html.content, 'html.parser')

    # "LoopList__item"のテキスト部分を取り出す
    item_list = []
    for i in soup.find_all(class_="LoopList__item"):
        item_list.append(i.text)

    # 文字コードをShift_JISに指定
    with open("item_list.csv", "w", encoding="Shift_jis") as f: 
        # writerオブジェクトの作成 改行記号で行を区切る
        writer = csv.writer(f, lineterminator="\n")
        # csvファイルに書き込み
        writer.writerows(item_list) 


def main():
    # 利用制限のチェック
    robot_check(url)
    # ECサイトのブラウザ表示して検索(Chrome)
    scraping(url, keywd)


if __name__ == '__main__':
    main()


ひとつずつ見ていきましょう。

そもそもスクレイピングってなんですの?

WEBサイトから必要な情報を抜き取る処理のことを指すようです。


抜き取る、なんていうとハッキングみたいですよね。


作ってみた感想として、確かにハッキングしてるような気分になりました。笑


事実、スクレイピングが禁止されているサイトもあります。


なので、作成の際は対象のサイトの規約などに十分ご注意ください

import urllib.robotparser
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import requests
from bs4 import BeautifulSoup
import csv


スクレイピングの定番であろうseleniumBeautifulSoupを使いました。

使ってみた感想として、seleniumuはWEBを操作する系(今回はブラウザを立ち上げて、キーワードを入力して検索する)、
BeautifulSoupは抜き出したHTMLを加工する系という違いがあるように思います。


スクレイピングをやる時は、この2つをインストールしましょう。


pipでインストールを勧めるサイトが多いですが、私はAnacondaで管理したいので、condaでインストールしました。


ブラウザはChromeを立ち上げます。立ち上げるにはwebdriverが要ります。


ここからダウンロードしましょう。
chromedriver.chromium.org


webdriverの説明は後のソースコードで説明します。

規約の確認

# ECサイトURLを指定
url = "https://shopping.yahoo.co.jp/"

keywd = "python 本"


def robot_check(url):
    rp = urllib.robotparser.RobotFileParser()

    rp.set_url(url + "robots.txt")
    rp.read()

    # クローリングへの指示書があるか
    req_rate = rp.request_rate("*")
    if req_rate is None:
        print("クローリングへの指示書はありません")

        # URLの取得が許可されているかを確認
        req_URL = rp.can_fetch("*", url)
        if req_URL == True:
            print("URLの取得も許可されています。これよりスクレイピングを開始します。")
        else:
            print("URLの取得が許可されていません。スクレイピングを中止します")
    else:
        print("クローリングへの指示書があります。問題がないか、利用規約を確認ください。")


これは何をしているのかというと、スクレイピングしても問題ないサイトなのかどうかのチェックをしてます。


スクレイピング前に必ず確認しましょう。禁止されているサイトでやると、罰則があったりするようです。


yahooショッピングにはクローリングの指示書はなく、スクレイピングも禁止されていないようです。

WEBを自動操作する

def scraping(url, keywd):
    option = Options()

    # Chromeオプションについては以下URLを参照
    # http://chrome.half-moon.org/43.html#l3e9a23d

    # Chromeの通知バーを表示しない
    option.add_argument("--disable-infobars")
    # 最大化で起動
    option.add_argument("--start-maximized")
    # 拡張機能を無効化
    option.add_argument("--disable-extensions")

    # ポップアップ通知を、1:許可、2:ブロック
    option.add_experimental_option("prefs", {"profile.default_content_setting_values.notifications": 2})

    driver = webdriver.Chrome(options=option, executable_path="driver/chromedriver.exe")

    driver.get(url)

    # 検索キーワードを指定
    elem_keyword = driver.find_element_by_name("p")
    # 検索キーワードを入力
    elem_keyword.send_keys(keywd)
    # 検索ボタンを押す
    driver.find_element_by_id("ss_srch_btn").click()


メイン処理の上半分。


スクレイピングにおいて、ポップアップとかの通知があると、上手く動かないことがあるようです。


なので、表示しないか無効化にしておくのが無難でしょう。


option.add_argumentで設定を変更できます。


ここ地味に苦労しましたが、この書き方でポップアップは出なくなります。


先ほどダウンロードしたwebdriverがここで出てきます。


私は実行ファイルの直下に「driver」フォルダを作り、その中にダウンロードした「chromedriver.exe」を置いてます。


このexeファイルがないと、Chromeブラウザが起動できません。なので、保存場所を指定してあげます。


ヤフーショッピングの検索タグは"p"です。


ヤフーショップのトップページでF12押すとHTML画面見れます。


f:id:yonesuke0716:20200211142513p:plain
ヤフーショップのhtml

ちなみにGoogle"q"


HTML、CSS、JavaScripの知識もあった方が理解が深まります。
(私も勉強中)


この時点のソースコードを動かすと、以下のような動きがあるはずです。
Chromeでヤフーショッピングのサイトが立ち上がる
・検索欄に自動的に「python 本」と記入される
・検索ボタンが押される


keywd変数の中身は自由に変えられます。

検索結果のページのHTMLを取得

# 検索結果のページのURLを取得
    cur_url = driver.current_url

    # 検索結果のURLのHTMLを取得
    r_html = requests.get(cur_url)

    soup = BeautifulSoup(r_html.content, 'html.parser')

    # "LoopList__item"のテキスト部分を取り出す
    item_list = []
    for i in soup.find_all(class_="LoopList__item"):
        item_list.append(i.text)

    # 文字コードをShift_JISに指定
    with open("item_list.csv", "w", encoding="Shift_jis") as f: 
        # writerオブジェクトの作成 改行記号で行を区切る
        writer = csv.writer(f, lineterminator="\n")
        # csvファイルに書き込み
        writer.writerows(item_list) 


検索画面のURLからHTMLを取得します。


取得はBeautifulSoupです。


BeautifulSoupを使って検索する際は、classやidなどを指定して検索します。


今回私は、"LoopList__item"というclassに注目しました。


これが、商品のひとつひとつに共通したclass名としてつけられていることがわかったからです。


スクレイピングをやっていて思ったのが、どうやったら欲しい情報が抜けるかをHTMLの構造から考える必要があります。


マクロとか効率化のツールをよく作っているので、この辺は共通な感じで親近感(?)を覚えました。


あとは抜き出した内容をPythonのリストに格納して、CSVファイルで出力します。


その出力結果がこちら!

f:id:yonesuke0716:20200211145646p:plain
 ? 



あ?



とりあえず「,」を置換してっと・・


f:id:yonesuke0716:20200211145956p:plain
あー・・



さらに色々キーワードを削って・・

f:id:yonesuke0716:20200211150805p:plain
よし!


ん~・・・


Mission complete!!(?)


いやー難しいですねぇ、スクレイピングって。


もっとスマートに出力結果出せるようになるには、色々工夫が必要ですね。


もっと勉強してできるようになろう!


とりあえず今回はここまで。