スクレイピングいろいろ

ウェブスクレイピングの手法をいくつかご紹介致します。
GAS、VBA、PHP、Python、それぞれを使って、Yahoo!Japanの主要ニュースを取得します。
結論からいうと、GAS + Spreadsheetのほうが気軽に使えてイチオシです。

##GAS + Spreadsheet
###良い点
Googleアカウントさえあれば、一切の環境を用意する必要がなく、GASのトリガーで定期的に実行できます。
###悪い点
大規模の実行にはパフォーマンスの懸念があります。
セキュリティ上、重要なデータの扱いはちょっと厳しいです。

###コード
```gas.js
function yahoo() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('yahoo');
  //書き込むシート名を指定
  var getUrl = 'https://www.yahoo.co.jp/';
  //ターゲットページを指定
  var content = UrlFetchApp.fetch(getUrl).getContentText('UTF-8');
  var content = content.replace(/\r?\n/g, '');
  var data = content.match(/<div class="_2jjSS8r_I9Zd6O9NFJtDN-" aria-label="主要 ニュース">(.*?)<\/div><div>/);
  //コンテンツのブロックを設定
  var data = data[0];
  var URLs = data.match(/<a class="yMWCYupQNdgppL-NV6sMi _3sAlKGsIBCxTUbNi86oSjt" href="(.*?)"/g);
  //URL群を一括で配列へ
  var Titles = data.match(/<span class="fQMqQTGJTbIMxjQwZA2zk _3tGRl6x9iIWRiFTkKl3kcR">(.*?)<\/span>/g);
  //記事名群を一括で配列へ
  for (var i = 0; i < 8; i++) {
    var URL = URLs[i];
    URL = URL.replace('<a class="yMWCYupQNdgppL-NV6sMi _3sAlKGsIBCxTUbNi86oSjt" href="', '');
    URL = URL.replace('"', '');
    sheet.getRange(i + 2, 1).setValue(URL); 
    
    var Title = Titles[i];
    Title = Title.replace('<span class="fQMqQTGJTbIMxjQwZA2zk _3tGRl6x9iIWRiFTkKl3kcR">', '');
    Title = Title.replace('<\/span>', '');
    sheet.getRange(i + 2, 2).setValue(Title);
    
  }
  Browser.msgBox('Done！');
}
```
##VBA + Excel
###良い点
リテラシーの低い利用者向けで、おなじみのエクセルで使って頂ける文はやはりありがたいです。
###悪い点
IEオブジェクトに依存しますので、Windows端末は必須となります。
IEの独特の仕様で現代的なウェブサイトでうまく動作しないケースがしばしばあります。

###ライブラリの追加
ExcelのVBA画面で
メニューバー > ツール > 参照設定
に下記2つのライブラリにチェックをつけます。
・Microsoft HTML Object Library
・Microsoft Internet Controls

###コード
```vb
Sub GetData_Click()
Application.ScreenUpdating = False
Dim objIE As InternetExplorer
Dim htmlDoc As HTMLDocument
Dim NewsItem IHTMLElement
Dim NewsList, NewsTitle, NewsURL As IHTMLElementCollection
Dim PageURL As String
Dim LastRow As Long
PageURL = "https://www.yahoo.co.jp/"

'新しいIEオブジェクトを作成してセット
Set objIE = CreateObject("Internetexplorer.Application")
objIE.Visible = False

'IEでURLを開く
objIE.navigate PageURL
'読み込み待ち
Do While objIE.Busy = True Or objIE.readyState < READYSTATE_COMPLETE
  DoEvents
Loop
'objIEで読み込まれているHTMLドキュメントをセット
Set htmlDoc = objIE.document

'各項目のコンテンツ取得
Set NewsList = htmlDoc.getElementsByClassName("_2jjSS8r_I9Zd6O9NFJtDN-")

For Each NewsItem In NewsList
  '各タグの検索用件を指定
  Set NewsTitle = NewsItem.getElementsByTagName("a")
  Set NewsURL = NewsItem.getElementsByClassName("fQMqQTGJTbIMxjQwZA2zk _3tGRl6x9iIWRiFTkKl3kcR")
  '最終行を取得
  LastRow = Worksheets("result").Cells(Rows.Count, 1).End(xlUp).Row
  '各セルに該当する値を埋める
  Worksheets("result").Cells(LastRow + 1, 1).Value = Right(NewsURL(0).href, 4)
  Worksheets("result").Cells(LastRow + 1, 2).Value = NewsTitle(0).innerText
  '見つからない場合にはスキップ
  On Error Resume Next
  Worksheets("result").Cells(LastRow + 1, 5).Value = Mid(Campagin(0).innerText, 2)
  Worksheets("result").Cells(LastRow + 1, 6).Value = Mid(Campagin(1).innerText, 1)
Next NewsItem

MsgBox "Done!"
End Sub
```

##PHP + csv
###良い点
パフォーマンスがよいです。依存するライブラリも少ないです。
###悪い点
PHPを実行する環境が必要です。
###必要なライブラリ
[phpQuery-onefile.php](https://code.google.com/archive/p/phpquery/)
上記ファイルをダウンロードし、本体のphpファイルと同じ階層に置く
###コード
```scraping.php
<?php
  require_once("phpQuery-onefile.php");
  $path = "xxx/xxx.csv"; //出力するｃｓｖを指定
  $header = "URL".", ". "Title"."\n";
  $file = fopen($path, "w");
  $target = "https://www.yahoo.co.jp/";
  $html = file_get_contents($target);
  $list = phpQuery::newDocument($html)->find("div._2jjSS8r_I9Zd6O9NFJtDN-");
  for($i = 0; $i < 8; $i++){
   $url[$i] = phpQuery::newDocument($list)->find("li:eq($i)")->find("a")->attr("href");
   $title[$i] = str_replace(",", "", phpQuery::newDocument($list)->find("span.fQMqQTGJTbIMxjQwZA2zk _3tGRl6x9iIWRiFTkKl3kcR:eq($i)")->text());
   $data .= ".$url[$i].", ".$title[$i]."."\n";
  }
    $content = $header . $data;
  fputs($file, $content);
  fclose($file);
?>

```
##Python + csv
###良い点
パフォーマンスがよいです。すでにPythonを使っていれば、連携しやすいです。
###悪い点
Pythonの環境構築するにはちょっと手間です。すでにPythonを使っていれば、いろいろ連結して活用できるかもしれませんが、スクレイピングだけのためなら、PHPのほうが圧倒的に環境構築しやすいです。

###必要なライブラリをインストール
```
pip3 install requests
pip3 install beautifulsoup4
```

###コード
```scraping.py
# coding: utf-8
import requests
from bs4 import BeautifulSoup
import csv

r = requests.get("https://yahoo.co.jp/")
data = BeautifulSoup(r.content, "html.parser")
list = data.find("div", "_2jjSS8r_I9Zd6O9NFJtDN-")
links = list.find_all("a", "")
titles = list.find_all("span", "fQMqQTGJTbIMxjQwZA2zk _3tGRl6x9iIWRiFTkKl3kcR")

with open('xxx/xxx.csv', 'w') as f:
# csvファイルの配置場所を決める
    writer = csv.writer(f)
    writer.writerow(['url', 'title'] )
    for i in range(7):
        writer.writerow([links[i].attrs['href'], titles[i].text])
```

##おまけ：ログインが必要なページの場合

ログインしないとコンテンツの閲覧ができない場合、Pythonのchromedriverを使うと便利です。
chromedriverの使い方についてはこちらの記事に詳しく紹介されています。
[Python + Selenium で Chrome の自動操作を一通り](https://qiita.com/memakura/items/20a02161fa7e18d8a693)
また、PATHの通し方やバージョンの注意点についてはこちらの記事をご参考してください。
[[selenium向け] ChromeDriverをpipでインストールする方法（パス通し不要、バージョン指定可能）](https://qiita.com/hanzawak/items/2ab4d2a333d6be6ac760)

###必要なライブラリ
```
pip3 install selenium
pip3 install chromedriver-binary
```

###コード
```login_scraping.py
# coding: utf-8
import time, os, requests, sys, csv
from selenium import webdriver
import chromedriver_binary

# ユーザー名とパスワードの指定
user_id = "xxxxxxxxxx"
password = "xxxxxxxxxx"
download_dir = os.path.dirname(__file__)
# loginページURLの指定
login = 'https://www.example.com/login/'
# 保存先などオプションを指定してChromeを起動
opt = webdriver.ChromeOptions()
opt.add_experimental_option("prefs", {
    "download.default_directory": download_dir,
    "download.prompt_for_download": False,
    "plugins.always_open_pdf_externally": True
})
driver = webdriver.Chrome(options=opt)
# ログインページを開く
driver.get(login)
time.sleep(3) # ページが開くまで待つ
# ログイン画面のユーザー名にキーを送信
u = driver.find_element_by_name('xxx')
u.send_keys(user_id)
# ログイン画面のパスワードにキーを送信
p = driver.find_element_by_name('yyy')
p.send_keys(password)
p.submit()
time.sleep(3) # ページが開くまで待つ

driver.get("https://www.example.com/listdata/")
list = driver.find_element_by_tag_name("_2jjSS8r_I9Zd6O9NFJtDN-")
links = list.find_all("a", "")
titles = list.find_all("span", "fQMqQTGJTbIMxjQwZA2zk _3tGRl6x9iIWRiFTkKl3kcR")

with open('xxx/xxx.csv', 'w') as f:
# csvファイルの配置場所を決める
    writer = csv.writer(f)
    writer.writerow(['url', 'title'] )
    for i in range(7):
        writer.writerow([links[i].attrs['href'], titles[i].text])

# ページが開くまで待つ
time.sleep(3)
driver.quit()
```

以上、5つの方法をご紹介しました。
使い道によっては、それぞれのメリット、デメリットがあります。
お役に立てれば幸いです。