0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

千葉県コロナウィルスのページをGASでスクレイピングしてみた

Posted at

動機

本当は東京都のコロナウィルスサイトを参考にして、千葉県のサイトを作りたかったんだけど...
あ...公開できるWebサーバーがない...

あんまり悩んでもしょうがないので、ここでは簡単にGASを使って千葉県の患者数情報を取得して、DataStudioでお手軽に公開する方法にしてみました

3/15時点では千葉県の派生サイトはなかったみたいですが、今現在(4/2)は以下のサイトができています
ちゃんとしたサイトがある以上お手軽のは不要だと思いますが、なんちゃってですぐにデータを皆で見たいときは割とDataStudioは使えると思うのでデータ取得部分のコードをQiitaに載せることにしました

公開サイト 運営者
千葉県 https://chiba-covid19.mypl.net/ 地域情報サイト「まいぷれ」
千葉県 https://covid19.civictech.chiba.jp/ Civic Tech Zen Chiba

ライブラリ

Webページから簡単にHTMLを抽出するのに「Parser」というライブラリを使います
GASプロジェクト画面のリソースからライブラリに以下を追加します

ライブラリ key 出典
Parser M1lugvAXKKtUxn_vdAG9JZleS6DrsjUUV Easy data scraping with Google Apps Script in 5 minutes

GASのコード

スプレッドシートのURLと欲しいWebページのURLを書き換えれば何となく他のサイトからもデータ取れると思います

sample
function myFunction() {
  // データ書込用のスプレッドシートを開く
  var url = '自分のスプレッドシートのURL';
  var ss = SpreadsheetApp.openByUrl(url);
  
  // シートを指定して最終行を調べる
  var sheet = ss.getSheetByName('chiba');
  var lastSheetRow = sheet.getLastRow();

  // 千葉県感染者情報のページを開く
  var url = 'https://www.pref.chiba.lg.jp/shippei/press/2019/ncov-index.html'; 
  var content = UrlFetchApp.fetch(url).getContentText('UTF-8');
  
  // ライブラリにParserを追加しておく
  // Parser	: M1lugvAXKKtUxn_vdAG9JZleS6DrsjUUV
  // 感染者数のテーブルを取得する
  var dataTable = Parser.data(content)
    .from('<table width="100%" summary="" border="1" class="datatable">')
    .to('</table>')
    .iterate()

  // 取得したテーブルごとに処理を行う
  var outPutData = '';
  for(var i=0; i<dataTable.length; i++){
    // 取得したテーブルの各行を配列として取得する
    trItem = getDataRow(dataTable[i]);
    // 各行から必要な情報を取得していく
    outPutData = outPutData + getDataItem(trItem);
  }

  // スプレッドシートにデータを書込
  outPutDataAry = outPutData.split('\n');
  for(var l=outPutDataAry.length-1; l>=0; l--){
    dataValue = outPutDataAry[l].split(',')
    sheet.getRange(l+2,1).setValue(dataValue[0]);
    sheet.getRange(l+2,2).setValue(dataValue[1]);
    sheet.getRange(l+2,3).setValue(dataValue[2]);
    sheet.getRange(l+2,4).setValue(dataValue[3]);
    sheet.getRange(l+2,5).setValue(dataValue[4]);
    sheet.getRange(l+2,6).setValue(dataValue[5]);
    sheet.getRange(l+2,7).setValue(dataValue[6]);
  }
}


function getDataRow(dataTableItem) {
  // 取得したテーブルの各行を配列として取得する
  var trItem = Parser.data(dataTableItem)
    .from('<tr>')
    .to('</tr>')
    .iterate()
  return trItem;
}


function getDataItem(trItem) {
  // 各行から必要な情報を取得していく
  // 出力用の文字列
  var patient = '';
  var patientType = '';
  var patientCount = '';
  var area = '';
  var age = '';
  var sex = '';
  var fdate = '';
  var rdate = '';
  var outPutData = '';
  // テーブル内の患者情報の最大行数
  var nMax = trItem.length;
  
  for(var n=1; n<trItem.length; n++){
    // 各行内の情報を配列で取得
    var tdItem = Parser.data(trItem[n])
      .from('<td ')
      .to('</td>')
      .iterate()
    
    // 各情報をベタに正規表現で処理
    // 患者番号 or 無症状病原体保有者番号
    patient = tdItem[0].replace(/<\/p>|^.+?>|<.+?>|\s/g,'').replace(/,$/g,'');
    // 患者XX~患者YYみたいな表現の場合は正しく数をカウントできなくなるので別処理に回す
    if(patient.match(/~/)){
      var tmpRowItem = tmpRowFunc(tdItem, patient);
      var tmpRowItemAry = tmpRowItem.split(',');
      outPutData = outPutData + tmpRowItemAry;
    }else{
      patientType = patient.replace(/[0-9]/g,'');
      patientCount = patient.replace(/[^0-9]/g,'');
      var area_age_sex = tdItem[1].replace(/<\/p>|<br \/>|・/g,',').replace(/^.+?>|<.+?>|\s/g,'').replace(/,$|&nbsp;/g,'').split(',');
      area = area_age_sex[0];
      age = area_age_sex[1];
      sex = area_age_sex[2];
      var fdate_rdate = tdItem[2].replace(/<\/p>|<br \/>/g,',').replace(/^.+?>|<.+?>|\s/g,'').replace(/,$/g,'').split(',');
      // 無症状病原体保有者テーブルでは確定日のみなので発症日の情報がない
      if(fdate_rdate.length==2){
        if(fdate_rdate[0] != '不詳'){
          fdate = '2020年' + fdate_rdate[0];
        } else {
          fdate = '';
        }
        if(fdate_rdate[1] != '不詳'){
          rdate = '2020年' + fdate_rdate[1];
        } else {
          rdate = '';
        }
      }else{
        fdate = '';
        rdate = '2020年' + fdate_rdate;
      }
      outPutData = outPutData + patientType + ',' + patientCount + ',' + area + ',' + age + ',' + sex + ',' + fdate + ',' + rdate + '\n';
    }
  }
  return outPutData;
}


function tmpRowFunc(tdItem, patient){
  // patientから実際の患者数を算出する
  var patientAry = patient.replace(/患者|\(.*\)|無症状病原体保有者/g,'').split('');
  var patientType = patient.replace(/[0-9]/g,'').split('');
  var tmp = '';
  var area = tdItem[1].replace(/<\/p>|<br \/>|・/g,',').replace(/^.+?>|<.+?>|\s/g,'').replace(/,$/g,'');
  var age = '';
  var sex = '';
  var fdate = '';
  var rdate = tdItem[2].replace(/<\/p>|<br \/>/g,',').replace(/^.+?>|<.+?>|\s/g,'').replace(/,$|検査確定日:/g,'').split('');
  var counterRange = Number(patientAry[1]) - Number(patientAry[0]);
  for(counter=counterRange; counter>=0; counter--){
    var patient_counter = Number(patientAry[0]) + counter; 
    tmp = tmp + patientType[0] + ',' + patient_counter + ',' + area + ',' + age + ',' + sex + ',' + fdate + ',' + '2020年' + rdate[0] + '\n';
  }
  return tmp;
}

DataStudio

DataStudioを起動して上記のデータを書き込んだスプレッドシートをデータソースに指定すれば簡単に可視化できます
公開をすればWebサーバーなくてもなんちゃってなグラフが公開できちゃいます

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?