ヤフーファイナンスは、株価、金融ニュース、レポートなど、さまざまな分野の金融データを掲載する老舗のウェブサイトです。
過去の株価やマーケットサマリーを抽出するために、独自のYahoo Finance APIを持っている。
今回は、APIに頼らず、オリジナルのヤフーファイナンスウェブサイトをスクレイピングします。
ウェブスクレイピングは、Scrapyというオープンソースのウェブクローリングフレームワークで実現されている。
Bulk Scraping Requirement?
人気のあるウェブサイトのほとんどは、ファイアウォールを使って過剰なトラフィックを持つIPをブロックしています。
その場合、Zenscrapeを使用することができます。
Zenscrapeは、大規模なスクレイピングの問題を解決するウェブスクレイピングAPIです。
WebスクレイピングAPIに加え、レジデンシャルプロキシサービスも提供しており、プロキシ自体へのアクセスも可能で、ユースケースに応じた最大限の柔軟性を提供します。
ウェブスクレイパーの要件
具体的な話に入る前に、ある技術的な要件を満たしている必要があります。
- Python – この特定のプロジェクトでは、Pythonを使用します。Python – このプロジェクトではPythonを使用します。膨大なライブラリと簡単なスクリプトは、Webスクレイピングのための最良の選択肢です。
 - Scrapy – PythonでサポートされているこのWeb-crawlingフレームワークは、ウェブサイトからデータを抽出するための最も有用な技術の1つです。
 - HTMLの基本 – スクレイピングは、HTMLタグと属性で遊ぶことを含む。しかし、読者がHTMLの基本を知らない場合、このウェブサイトが役に立ちます。
 - ウェブブラウザ – Google ChromeやMozilla Firefoxのような一般的に使用されているウェブブラウザには、基礎となるHTMLデータを検査する機能が備わっています。
 
Scrapyのインストールとセットアップ
Scrapyの簡単なインストール手順を説明します。
まず、他のPythonライブラリと同様に、Scrapyはpipを使用してインストールします。
pip install Scrapy | 
インストールが完了したら、Web Scraper 用のプロジェクトを作成します。
プロジェクトを格納するディレクトリを入力し、実行します。
scrapy startproject <PROJECT_NAME> | 
import scrapy
class yahooSpider(scrapy.Spider):
        ....
        ....
 | 
上記のターミナルのスニペットに見られるように、Scrapyはプロジェクトをサポートするいくつかのファイルを作成します。
ディレクトリに存在する各ファイルの細部の詳細については、ここでは触れません。
その代わりに、Scrapyを使って最初のスクレイパーを作成することを学ぶことを目的としています。
読者がインストールに関連する問題を抱えている場合に備えて、詳細なプロセスはここで説明されています。
Scrapy を使って最初のスクレイパーを作成する
Scrapyプロジェクトの spiders ディレクトリ内に python ファイルを作成します。
注意点としては、Pythonクラスは Scrapy.Spider クラスを継承する必要があることです。
class yahooSpider(scrapy.Spider):
    # Name of the crawler
    name = "yahoo"
    # The URLs we will scrape one by one
    start_urls = ["https://in.finance.yahoo.com/quote/MSFT?p=MSFT",
    "https://in.finance.yahoo.com/quote/MSFT/key-statistics?p=MSFT",
    "https://in.finance.yahoo.com/quote/MSFT/holders?p=MSFT"]
 | 
以下、これから作成するクローラーの名前とURLです。
import scrapy
import csv
class yahooSpider(scrapy.Spider):
    # Name of the crawler
    name = "yahoo"
    # The URLs we will scrape one by one
    start_urls = ["https://in.finance.yahoo.com/quote/MSFT?p=MSFT",
    "https://in.finance.yahoo.com/quote/MSFT/key-statistics?p=MSFT",
    "https://in.finance.yahoo.com/quote/MSFT/holders?p=MSFT"]
    # Parsing function
    def parse(self, response):
                ....
                ....
 | 
検討中の銘柄は、マイクロソフト(MSFT)のものです。
私たちが設計しているスクレイパーは、以下の3つのウェブページから重要な情報を取得する予定です。
- マイクロソフト株の概要
 - 株価の統計
 - マイクロソフトの財務情報
 
start_urls` リストには、上記の各ウェブページの URL が含まれています。
スクレイピングされたコンテンツのパース
指定されたURLは一つずつスクレイピングされ、HTML文書は parse() 関数に送られます。
# Parsing functiondef parse(self, response):
    # Using xpath to extract all the table rows
    data = response.xpath('//div[@id="quote-summary"]/div/table/tbody/tr')
         # If data is not empty
    if data:
        # Extracting all the text within HTML tags
        values = data.css('*::text').getall()
 | 
parse()` 関数には、Yahoo Finance の Web ページからデータを抽出するためのロジックが含まれています。
関連データを抽出するためのタグを発見する
HTMLコンテンツからのタグの発見は、Webブラウザーを使ってWebページを検査することで行われます。
['Previous close', '217.30', 'Open', '215.10', 'Bid', '213.50 x 1000', 'Ask', '213.60 x 800' ...  'Forward dividend & yield', '2.04 (0.88%)', 'Ex-dividend date', '19-Aug-2020', '1y target est', '228.22']
 | 
Inspect`ボタンを押すと、画面右側に膨大な量のHTMLを含むパネルが表示される。
私たちの仕事は、抽出したいデータを含むタグの名前とその属性を検索することです。
例えば、「Previous Close」を含むテーブルから値を抽出したい場合、そのデータを格納しているタグの名前と属性が必要です。
# Parsing functiondef parse(self, response):
    # Using xpath to extract all the table rows
    data = response.xpath('//div[@id="quote-summary"]/div/table/tbody/tr')
         # If data is not empty
    if data:
        # Extracting all the text within HTML tags
        values = data.css('*::text').getall()
                 # CSV Filename
        filename = 'quote.csv'
        # If data to be written is not empty
        if len(values) != 0:
            # Open the CSV File
            with open(filename, 'a+', newline='') as file:
                                 # Writing in the CSV file
                f = csv.writer(file)
                for i in range(0, len(values[:24]), 2):
                    f.writerow([values[i], values[i+1]])
 | 
目的の情報を格納しているHTMLタグの知識があれば、Scrapyで定義された関数を使って情報を抽出することができます。
データ抽出のためのScrapyセレクタ
今回使用するセレクタ関数は xpath() と css() の2つです。
XPATHは、独立して、XMLやHTMLのドキュメントからデータを選択するためのクエリ言語です。
XPATHはXML Path Languageの略です。
CSSは、独立して、HTML言語用のスタイル付け言語です。
これらのセレクタ関数の詳細については、それぞれの公式サイトを参照してください。
scrapy crawler <CRAWLER-NAME> | 
引数として受け取る response の値には、Webサイト内の全データが含まれる。
HTMLドキュメントにあるように、テーブルは id 属性が quote-summary である div タグ内に格納されている。
上記の情報を xpath 関数にキャストして、指定した div タグ内にある tr タグをすべて抽出します。
そして、タグの名前 (*) に関係なく、すべてのタグからテキストを取得して、 values というリストに格納します。
値のセットは以下のようなものです。
import scrapy
import csv
class yahooSpider(scrapy.Spider):
    # Name of the crawler
    name = "yahoo"
    # The URLs we will scrape one by one
    start_urls = ["https://in.finance.yahoo.com/quote/MSFT?p=MSFT",
    "https://in.finance.yahoo.com/quote/MSFT/key-statistics?p=MSFT",
    "https://in.finance.yahoo.com/quote/MSFT/holders?p=MSFT"]
    # Parsing function
    def parse(self, response):
        # Using xpath to extract all the table rows
        data = response.xpath('//div[@id="quote-summary"]/div/table/tbody/tr')
                 # If data is not empty
        if data:
            # Extracting all the text within HTML tags
            values = data.css('*::text').getall()
                         # CSV Filename
            filename = 'quote.csv'
            # If data to be written is not empty
            if len(values) != 0:
                # Open the CSV File
                with open(filename, 'a+', newline='') as file:
                                         # Writing in the CSV file
                    f = csv.writer(file)
                    for i in range(0, len(values[:24]), 2):
                        f.writerow([values[i], values[i+1]])
        # Using xpath to extract all the table rows
        data = response.xpath('//section[@data-test="qsp-statistics"]//table/tbody/tr')
                 if data:
            # Extracting all the table names
            values = data.css('span::text').getall()
            # Extracting all the table values 
            values1 = data.css('td::text').getall()
            # Cleaning the received vales
            values1 = [value for value in values1 if value != ' ' and (value[0] != '(' or value[-1] != ')')]
                         # Opening and writing in a CSV file
            filename = 'stats.csv'
                     if len(values) != 0:
                with open(filename, 'a+', newline='') as file:
                    f = csv.writer(file)
                    for i in range(9):
                        f.writerow([values[i], values1[i]])
        # Using xpath to extract all the table rows
        data = response.xpath('//div[@data-test="holder-summary"]//table')
        if data:
            # Extracting all the table names
            values = data.css('span::text').getall()
            # Extracting all the table values 
            values1 = data.css('td::text').getall()
            # Opening and writing in a CSV file
            filename = 'holders.csv'
                         if len(values) != 0:
                with open(filename, 'a+', newline='') as file:
                    f = csv.writer(file)
                    for i in range(len(values)):
                        f.writerow([values[i], values1[i]])
 | 
注意しなければならないのは、タグの名前と属性は時間の経過とともに変化し、上記のコードは意味をなさなくなる可能性があるということです。
したがって、読者はそのような情報を抽出する方法を理解する必要があります。
また、HTML文書から無関係な情報を取得することもあります。
したがって、プログラマーは、そのような異常を修正するために適切なサニティチェックを実装する必要があります。
この記事の後半で提供される完全なコードには、HTMLの専門用語の海から重要な情報を得るための例があと2つ含まれています。
取得したデータをCSVファイルに書き出す
このプロジェクトの最後のタスクは、取得したデータをCSVファイルのようなある種の永続的なストレージに保存することです。
Python には csv ライブラリがあり、.csv ファイルへの書き込みを簡単に実装することができます。

上記のコードは quote.csv ファイルを開き、Python の csv ライブラリを用いてスクレイパーが取得した値を書き込んでいます。
注意: csv ライブラリは Python に組み込まれているライブラリではないので、インストールが必要です。
ユーザーは pip install csv を実行して、インストールすることができます。
この記事もチェック:PythonのGeopyライブラリを使って住所のジオコードを取得する方法
Scrapyプロジェクト全体を実行する
進捗状況をすべて保存した後、最初に作成したプロジェクトの最上位ディレクトリに移動して実行します。

この例では、scrapy crawler yahooを実行すると、Pythonスクリプトが指定されたすべての情報をスクレイピングしてCSVファイルに格納します。
スクレイパーの完全なコード

まとめ
Scrapy Frameworkは、他のスクレイピングライブラリと比較して直感的でないように見えるかもしれませんが、Scrapyの深い学習は、その利点を証明します。
この記事は、読者がScrapyを使用してWebスクレイピングを理解するのに役立ったことを願っています。
また、Beautiful Soupを使ったAmazonの商品詳細の抽出など、別のWeb Scrapingの記事もありますので、そちらもご覧になってみてください。
お読みいただきありがとうございました。
ご質問やご提案がありましたら、お気軽にコメントください。