疑念は探究の動機であり、探究の唯一の目的は信念の確定である。

数学・論理学・哲学・語学のことを書きたいと思います。どんなことでも何かコメントいただけるとうれしいです。特に、勉学のことで間違いなどあったらご指摘いただけると幸いです。 よろしくお願いします。くりぃむのラジオを聴くこととパワポケ2と日向坂46が人生の唯一の楽しみです。

【GAS】フォルダ配下にあるファイルを再帰的に探索する

概要
GAS(GoogleAppsScript)において、あるフォルダ配下のファイル(スプレッドシート)を再帰的に検索するプログラムを作成した。


フォルダ構成

myDrive
├── GoogleAppsScriptProject
└── folder
├── folder1
│   ├── folder1-1
│   │   ├── folder1-1-1
│   │   │   ├── folder1-1-1-1
│   │   │   ├── folder1-1-1-2
│   │   │   │   └── folder1-1-1-2-1
│   │   │   │   ├── spreadsheet1-1-1-2-1
│   │   │   │   └── spreadsheet1-1-1-2-1_2
│   │   │   ├── folder1-1-1-3
│   │   │   ├── spreadsheet1-1-1
│   │   │   ├── spreadsheet1-1-1_2
│   │   │   └── spreadsheet1-1-1_3
│   │   └── folder1-1-2
│   │   └── spreadsheet1-1-2
│   └── folder1-2
├── folder2
└── folder3
├── folder3-1
│   ├── folder3-1-1
│   │   ├── spreadsheet3-1-1
│   │   └── spreadsheet3-1-1_2
│   ├── folder3-1-2
│   ├── spreadsheet3-1
│   └── spreadsheet3-1_2
└── spreadsheet3

f:id:yoheiwatanabe0606:20210430232121p:plain


期待値
指定引数: folderのID
期待値:

  1. spreadsheet1-1-1-2-1
  2. spreadsheet1-1-1-2-1_2
  3. spreadsheet1-1-1
  4. spreadsheet1-1-1_2
  5. spreadsheet1-1-1_3
  6. spreadsheet1-1-2
  7. spreadsheet3-1-1
  8. spreadsheet3-1-1_2
  9. spreadsheet3-1
  10. spreadsheet3-1_2
  11. spreadsheet3


GoogleAppsScriptProject(GASのファイル名)

function myFunction() {
  // もしも指定フォルダがマイドライブ以外の場合 
  var folderId = 'myomyomyomyomyo_xxxxxx_id';

  // もしも指定フォルダがマイドライブの場合
  // var rootId = DriveApp.getRootFolder().getId();
  // folderId = rootId;

  var folderArr = [folderId];
  folderArr = searchRecursiveFolders(folderId, folderArr);

  var assoArr = {};
  for (var i = 0; i < folderArr.length; i++) {
    var folderId = folderArr[i];
    var fileIdList = existFile(folderId);
    if (fileIdList.length) {
      assoArr[folderId] = fileIdList;
    }
  }

  for (folderId in assoArr) {
    var folderName = DriveApp.getFolderById(folderId).getName();
    // デバッグ
    Logger.log('<------------ START ------------>');
    Logger.log('folderName: ' + folderName); // フォルダ名

    for (var i = 1; i < assoArr[folderId].length; i++) {
      var fileName = DriveApp.getFileById(assoArr[folderId][i]).getName();

      // デバッグ
      Logger.log('fileName: ' + fileName); // ファイル名
    }

    // デバッグ
    Logger.log('<------------ END ------------>');
  }
}

function searchRecursiveFolders(folderId, folderArr) {
  var folders = DriveApp.getFolderById(folderId).getFolders();  
  while (folders.hasNext()) {
    var folderId = folders.next().getId();
    folderArr.push(folderId);
    searchRecursiveFolders(folderId, folderArr);
  }

  return folderArr;
}

/************************************ */
function existFile(folderId) {
  var fileIdList = [];
  var folder = DriveApp.getFolderById(folderId);
  var fileIterator = folder.getFiles();
  while (fileIterator.hasNext()) {
      fileIdList[0] = true;
      // ファイルIDのオブジェクト取得
      var fileId = fileIterator.next().getId();
      fileIdList.push(fileId);
  }

  return fileIdList;
}


実行結果
f:id:yoheiwatanabe0606:20210430224218p:plainf:id:yoheiwatanabe0606:20210430224221p:plainf:id:yoheiwatanabe0606:20210430224225p:plain


前提/改善点

  • GASでHello, World!ができる人
  • JavaScriptができる人ならば、もう少しスマートに書けると思う(fileIdList[0] = true;とか。Pythonのように実装したらうまくいかなかったため、このようなへんてこりんなコードで妥協した)

僕から以上

近況報告

毎月のブログ更新のためサボり記事。
今日付で会社を辞めた。
2019年の4月1日からちょうど2年で辞めた。明日から別の会社で働く。
今の会社ではいろいろのことを学んだ。その内容は今は書かないが、それが次の会社で活かせればと思う。

当初は起業する予定で辞めたのだが、その後、代表取締役が採算が取れないと起業を諦めたため、起業は頓挫して、新しい会社に入った。
次の会社ではとりあえずなんとか受注を受けて生き抜くことが当面の目標である。その間に何か別のビジネスができればいいと思っている。

**********

在宅勤務をおこなっているとき、しばしば隣の家から怒号が聞こえていた。その家はおじいさんとおばあさんの二人暮らしであり、その罵声の主はおじいさんであった。
「ばばあ!!」と叫ぶ声は近所に広がり、業務に集中できなかった。じいさんはほぼ寝たきりの状態で体が悪く、たいしてばあさんは買い物に行くなど一通りのことはできる状態であった(と思う)。
私は「これから毎日のように在宅で仕事をしなければならないのに、この罵声を聞かなければならないのか」と嫌な気持ちになっていた。そして「おそらくこの怒号が消え去るのはじいさんが死んだ後のことになるだろう」と思っていた。
昨日、起きて窓を開けてみると隣の家に喪服姿の人たちが何人かいた。「どうしたのだとう」と眺めてしばらく観察してみた。どうやら隣の家に不幸があったようだった。いつも家の中にいるじいさんが車椅子に乗って、どこかへ出かけている。おばあさんが亡くなったようだった。
おばあさんとは関わりはなかった。しかし少しショックだった。亡くなったと知って(正確にはそのように推測したに過ぎないが)、振り返ってみると、最後におばあさんを見たのは1週間ぐらい前の夜であった。
夜10時ごろに家に帰った時、おばあさんが玄関前で猫に「もうそろそろ家にお入り」と話しているところだった。私はそれをじとっと見て、向こうも自分のことに気づき、お互いに目があったが、そのまま無視して家に入った。それが最後だった。部屋に入って「『こんばんは』と一言、言えばよかったな」と少し思ったが、まさかそれが最後になるとは夢にも思わなかった。人はあっけなく急に死ぬこともあるんだなと気づかされた。そして今のところおばあさんが可愛がっていた猫を見かけていない。あの猫はどこに行ったのだろうか。
葬儀が終わった後、家に戻ってきたおじいさんは少し弱気になっていたように見えた。というのも親族の一人にたいして「俺はもう一人なんだから、たまには顔を出しておくれ」と言っていたからである。じいさんもばあさんが死ぬことは想定していなかったのだろう。
個人的にはこれでもう近隣から罵声を聞かずに済むこととなるので嬉しいのだが、まさか罵声を浴びせるほうではなく、罵声を浴びせられていたほうが消えるとは思っていなかった。

母親にこのことを話したら、自分のじいさんとばあさんも似たようなものだったとのことだった。曰く、おばあさんは晩年、毎日のように「くそじじい、さっさと死ね!」と罵声を発していたが、いざおじいさんが死ぬと「なんで死ぬんだ! 悲しいよ」とおめおめと悲劇のヒロインとなっていたらしい。「そんな後悔するんだったら、最初っからそんな罵詈雑言、言わなきゃいいのに」と思うけども、キレやすくなる認知症のパターンがあるらしく、怒号を発せずにはいられない。そのようなケースが意外に多いのだとのことだった。

*********

とりあえずは私は自分のしたいことをしよう。いつ死ぬかもわからないから。


僕から以上

Pythonでコマンドライン引数を使って実行する方法

概要
コマンドライン引数を使ってPythonのファイルを実行する方法を示す。
コマンドライン引数を実行するためにはargparseをインポートすればよい。


ソースコード arg_parse.py

import argparse
parser = argparse.ArgumentParser()

num1 = 6
num2 = 3

#### Caution:
#### The command '-h' does not allowed
#### because '-h' is preserved that '-h' is '--help'.
parser.add_argument('-a', '--add', help='operation add', action='store_true')
parser.add_argument('-s', '--subtraction', help='operation subtraction', action='store_true')
parser.add_argument('-m', '--multiplication', help='operation multiplication', action='store_true')
parser.add_argument('-d', '--division', help='operation division', action='store_true')
parser.add_argument('-taa', '--two_args_add', nargs=2, type=int, help='two arguments add')

parser.add_argument('-t', '--test_one_arg', type=int, default=0, help='test one argument with default')

args = parser.parse_args()
print('args = {}'.format(args))
print('num1 = {}'.format(num1))
print('num2 = {}'.format(num2))

if args.add:
    print('num1 + num2 = {}'.format(num1 + num2))

if args.subtraction:
    print('num1 - num2 = {}'.format(num1 - num2))

if args.multiplication:
    print('num1 * num2 = {}'.format(num1 * num2))

if args.division:
    print('num1 / num2 = {}'.format(num1 / num2))

if args.two_args_add:
    args1 = args.two_args_add[0]
    args2 = args.two_args_add[1]
    print('args1 + args2 = {} + {} = {}'.format(args1, args2, args1 + args2))

####
print('type(args) = {}'.format(type(args)))
print('vars(args) = {}'.format(vars(args)))
print('type(vars(args)) = {}'.format(type(vars(args))))

####
dict_args = vars(args)
bool_flag = False
for var in list(dict_args.values()):
    if var:
        bool_flag = True

if not bool_flag:
    print('NO OPTION')

####
for key, value in dict_args.items():
    if value:
       print('key: {}, value: {}'.format(key, value))


実行結果
(I) NO OPTIONS:
f:id:yoheiwatanabe0606:20210228223042p:plain

(II) OPTION: f:id:yoheiwatanabe0606:20210228223202p:plain

(III) TWO ARGUMENTS:
f:id:yoheiwatanabe0606:20210228223404p:plain

(IV) help option:
f:id:yoheiwatanabe0606:20210228223451p:plain

(未完)

PythonでChromeDriverを自動更新するプログラムを作った(再掲)。

概要
Seleniumchrome driverを使ってスクレイピングをおこなうが、Googleクロムのアプリは自動的に最新版となる。それによって、chrome driverのバージョンとクロムのバージョンが異なることによって、次のようなエラーが生じる。

selenium.common.exceptions.SessionNotCreatedException: Message: session not created: This version of ChromeDriver only supports Chrome version 83

通常は最新のchrome driverをウェブ上からダウンロードして新しいchrome driverに替えなければならない。
今回はchrome driverを最新版のバージョンに自動的にアップデートするようなプログラムをrequestsBeautifulSoupなどを用いて作る。


プログラム

### import Selenium
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys

import subprocess
import re
import os
import urllib.request
import requests
from bs4 import BeautifulSoup

### get the current chrome version
def get_chrome_version():
    chrome = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'

    chrome_data = subprocess.run([chrome, '--version'], stdout=subprocess.PIPE, encoding='UTF-8')

    chrome_str  = chrome_data.stdout
    ch_reg_exp  = re.findall('\d+', chrome_str)
    ch_full_ver = '.'.join(ch_reg_exp)
    ch_int_ver  = ch_reg_exp[0]

    chrome_version = ch_full_ver, ch_int_ver

    return chrome_version


### download the suitable chrome driver
def download_chrome_driver(chrome_version):
    download_return = False
    download_dir = '/Users/USERNAME_XXXXX/Downloads'
    url = 'https://chromedriver.chromium.org/downloads'
    res   = requests.get(url)
    soup  = BeautifulSoup(res.text, 'html.parser')
    list_notes_txt = soup.find_all('a', href=re.compile('notes.txt'))

    download_url = None
    mac_file     = '/chromedriver_mac64.zip'
    for notes_txt in list_notes_txt:
        match = re.search(r'\d+', notes_txt.get('href'))
        if match.group(0) == chrome_version:
            notes_txt = notes_txt.get('href')
            download_url = os.path.dirname(notes_txt) + mac_file
            break

    if download_url != None:
        new_chrome_driver = download_dir + mac_file
        ### download
        urllib.request.urlretrieve(download_url, new_chrome_driver)

        ### unzip the file 'chromedriver_mac64.zip'
        subprocess.run(['unzip', new_chrome_driver], stdout=subprocess.PIPE, encoding='UTF-8')

        ### delete the zip file
        subprocess.run(['rm', new_chrome_driver])

        ### Because the unzipped chrome driver lies in the current directory, move it to the directory 'download_dir'
        subprocess.run(['mv', './chromedriver', download_dir])
        download_return = True

    return download_return

### change the new chrome driver
def change_new_chrome_driver():
    old_chrome_driver = '/Users/USERNAME_XXXXX/opt/anaconda3/lib/python3.7/site-packages/chromedriver_binary/chromedriver'
    new_chrome_driver = '/Users/USERNAME_XXXXX/Downloads/chromedriver'

    subprocess.run(['open', new_chrome_driver])
    subprocess.run(['rm', old_chrome_driver])
    subprocess.run(['mv', new_chrome_driver, old_chrome_driver])

### main
### Initialize Chrome
try:
    ### Success
    DRIVER_PATH = r'/Users/USERNAME_XXXXX/opt/anaconda3/lib/python3.7/site-packages/chromedriver_binary/chromedriver'
    options = Options()
    options.add_argument('--headless')

    driver = webdriver.Chrome(executable_path=DRIVER_PATH, options=options)

except Exception:
    #### Version Error
    ### STEP 1: get the current chrome version
    ret_val_1 = get_chrome_version()

    ### STEP 2: download the suitable chrome driver
    ret_val_2 = download_chrome_driver(ret_val_1[1])

    ### STEP 3: change the new chrome driver
    if ret_val_2 == True:
        change_new_chrome_driver()


プログラムの方針
STEP 1: 現在のGoogle Chromeのバージョンを取得する。
1.1: subprocessを使って、Chromeのバージョンを取得する。
ターミナル上で次のコマンドを打つと、現在使用中のChromeのバージョンがわかる。

$ Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --version
$ Google Chrome 87.0.4280.67

このコマンド操作をsubprocessを使って、Pythonのファイルでおこなう。

1.2: reを使って、取得したChromeの情報からバージョンの数値のみを取得する。
(87.0.4280.67, 87)


STEP 2: requestsBeautifulSoupで適切なバージョンのchrome driverを取得する。
2.1: バージョンに合うURLを取得する。
https://chromedriver.storage.googleapis.com/87.0.4280.88/chromedriver_mac64.zip

2.2: urllib.request.urlretrieveを使って、ダウンロードする(requestsでもできると思う)。

2.3: subprocessを使って、zip形式を解凍して、zipファイルを捨てる。


STEP 3: subprocessを使って、すでにあるchrome driverをDownloads配下にある最新のchrome driverに変更させる。

(だいたい完)

C言語の文字列について: 完全攻略ガイド

概要
C言語において文字列の扱いは極めて難しい。
今回はC言語の文字列についてステップバイステップで説明する。

対象者
とりあえずC言語の配列やポインタを一通り勉強したけれども、まだ全然よくわからない人。


プログラム

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    // STEP 1
    printf("-----STEP 1-----\n");
    printf("Hello, World!\n");
    printf("\n");

    // STEP 2: use place holders 
    printf("-----STEP 2-----\n");
    printf("%s\n", "Hello, World!!");
    printf("Addr of \"Hello, World!!\"  = %p\n", "Hello, World!!");
    printf("Addr of &\"Hello, World!!\" = %p\n", &"Hello, World!!");
    printf("\"Hello, World!!\"[0]  = %c\n", "Hello, World!!"[0]);
    printf("\"Hello, World!!\"[1]  = %c\n", "Hello, World!!"[1]);
    printf("\"Hello, World!!\"[2]  = %c\n", "Hello, World!!"[2]);
    printf("\"Hello, World!!\"[3]  = %c\n", "Hello, World!!"[3]);
    printf("\"Hello, World!!\"[4]  = %c\n", "Hello, World!!"[4]);
    printf("\"Hello, World!!\"[5]  = %c\n", "Hello, World!!"[5]);
    printf("\"Hello, World!!\"[6]  = %c\n", "Hello, World!!"[6]);
    printf("\"Hello, World!!\"[7]  = %c\n", "Hello, World!!"[7]);
    printf("\"Hello, World!!\"[8]  = %c\n", "Hello, World!!"[8]);
    printf("\"Hello, World!!\"[9]  = %c\n", "Hello, World!!"[9]);
    printf("\"Hello, World!!\"[10] = %c\n", "Hello, World!!"[10]);
    printf("\"Hello, World!!\"[11] = %c\n", "Hello, World!!"[11]);
    printf("\"Hello, World!!\"[12] = %c\n", "Hello, World!!"[12]);
    printf("\"Hello, World!!\"[13] = %c\n", "Hello, World!!"[13]);
    printf("\"Hello, World!!\"[14] = %c\n", "Hello, World!!"[14]);
    printf("\n");

    printf("\\x020 = %c\n", '\x020');
    printf("\\0 = %c\n", '\0');

    printf("Hello,\\x020World! = %s\n", "Hello,\x020World!");

    // STEP 3: use variables
    // 3.1: Initialize
    // Pointers 
    char *ptr_str_init  = "PTR INIT: Hello, World!!!";

    // Arrays
    char arr_str_init[] = "ARR INIT: Hello, World!!!";
    printf("-----STEP 3.1-----\n");
    printf("%s\n", arr_str_init);
    printf("%s\n", ptr_str_init);
    printf("\n");

    // 3.2: Declaration and Substitution
    // Pointers
    char *ptr_str_dec;
    ptr_str_dec = "PTR DEC: Hello, World!!!";

    // Arrays
    char arr_str_dec[30];
    arr_str_dec[0] = 'A';
    arr_str_dec[1] = 'R';
    arr_str_dec[2] = 'R';
    arr_str_dec[3] = ' ';
    arr_str_dec[4] = 'D';
    arr_str_dec[5] = 'E';
    arr_str_dec[6] = 'C';
    arr_str_dec[7] = ':';
    arr_str_dec[8] = ' ';
    arr_str_dec[9] = 'H';
    arr_str_dec[10] = 'e';
    arr_str_dec[11] = 'l';
    arr_str_dec[12] = 'l';
    arr_str_dec[13] = 'o';
    arr_str_dec[14] = ',';
    arr_str_dec[15] = ' ';
    arr_str_dec[16] = 'W';
    arr_str_dec[17] = 'o';
    arr_str_dec[18] = 'r';
    arr_str_dec[19] = 'l';
    arr_str_dec[20] = 'd';
    arr_str_dec[21] = '!';
    arr_str_dec[22] = '!';
    arr_str_dec[23] = '!';
    arr_str_dec[24] = '\0';

    // Mallocs
    char *mlc_str_dec;
    mlc_str_dec = malloc(30);
    mlc_str_dec[0] = 'M';
    mlc_str_dec[1] = 'L';
    mlc_str_dec[2] = 'C';
    mlc_str_dec[3] = ' ';
    mlc_str_dec[4] = 'D';
    mlc_str_dec[5] = 'E';
    mlc_str_dec[6] = 'C';
    mlc_str_dec[7] = ':';
    mlc_str_dec[8] = ' ';
    mlc_str_dec[9] = 'H';
    mlc_str_dec[10] = 'e';
    mlc_str_dec[11] = 'l';
    mlc_str_dec[12] = 'l';
    mlc_str_dec[13] = 'o';
    mlc_str_dec[14] = ',';
    mlc_str_dec[15] = ' ';
    mlc_str_dec[16] = 'W';
    mlc_str_dec[17] = 'o';
    mlc_str_dec[18] = 'r';
    mlc_str_dec[19] = 'l';
    mlc_str_dec[20] = 'd';
    mlc_str_dec[21] = '!';
    mlc_str_dec[22] = '!';
    mlc_str_dec[23] = '!';
    mlc_str_dec[24] = '\0';


    printf("-----STEP 3.2-----\n");
    printf("%s\n", ptr_str_dec);
    printf("%s\n", arr_str_dec);
    printf("%s\n", mlc_str_dec);
    printf("\n");
    free(mlc_str_dec);


    printf("-----STEP 4-----\n");
    // Pointers
    printf("Addr of \"PTR STO: Hello, World!!!!\" = %p\n", "PTR STO: Hello, World!!!!");
    char *ptr_str_sto;
    ptr_str_sto = "PTR STO: Hello, World!!!!";

    /* Notes:   */
    /*
    error: redefinition of 'ptr_str_sto'
    char *ptr_str_sto = "PTR STO: hello, world!!!!"; 
    */

    printf("Addr of ptr_str_sto       = %p\n", ptr_str_sto);
    printf("%s\n", ptr_str_sto);
    
    printf("Addr of \"ptr sto: hello, world!!!!\" = %p\n", "ptr sto: hello, world!!!!");
    ptr_str_sto = "ptr sto: hello, world!!!!"; 
    printf("Addr of ptr_str_sto                 = %p\n", ptr_str_sto);
    printf("%s\n", ptr_str_sto);
    
    
    /* -------- */
    char arr_str_sto[30] = {'A', 'R', 'R', ' ', 'S', 'T', 'O', ':', ' ', 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', '!', '!', '!', '\0'};

    printf("Addr of arr_str_sto = %p\n", arr_str_sto);
    printf("%s\n", arr_str_sto);
    printf("\n");
    arr_str_sto[0] = 'a';
    arr_str_sto[1] = 'r';
    arr_str_sto[2] = 'r';
    arr_str_sto[4] = 's';
    arr_str_sto[5] = 't';
    arr_str_sto[6] = 'o';
    arr_str_sto[9] = 'h';
    arr_str_sto[16] = 'w';

    printf("Addr of arr_str_sto = %p\n", arr_str_sto);
    printf("%s\n", arr_str_sto);
    
   //copy
   int i = 1;
   int j = 2;
   printf("Addr of int i = %p\n", &i);
   printf("int i         = %d\n", i);
   i = j;
   printf("Addr of int i = %p\n", &i);
   printf("int i         = %d\n", i);

   char *mlc_string1 = malloc(10);
   char *mlc_string2 = malloc(10);
   mlc_string1[0] = 'H';
   mlc_string1[1] = 'e';
   mlc_string1[2] = 'l';
   mlc_string1[3] = 'l';
   mlc_string1[4] = 'o';

   mlc_string2[0] = 'h';
   mlc_string2[1] = 'e';
   mlc_string2[2] = 'l';
   mlc_string2[3] = 'l';
   mlc_string2[4] = 'o';

//Error: Abort   mlc_string2 = "hello";   
   printf("mlc_string1 = %s\n", mlc_string1);
   printf("mlc_string2 = %s\n", mlc_string2);
   
//Error: Abort   mlc_string1 = mlc_string2;

   printf("mlc_string1 = %s\n", mlc_string1);
   free(mlc_string1);
   free(mlc_string2);


    return 0;
}


実行結果

-----STEP 1-----
Hello, World!

-----STEP 2-----
Hello, World!!
Addr of "Hello, World!!"  = 0x103f71b99
Addr of &"Hello, World!!" = 0x103f71b99
"Hello, World!!"[0]  = H
"Hello, World!!"[1]  = e
"Hello, World!!"[2]  = l
"Hello, World!!"[3]  = l
"Hello, World!!"[4]  = o
"Hello, World!!"[5]  = ,
"Hello, World!!"[6]  =  
"Hello, World!!"[7]  = W
"Hello, World!!"[8]  = o
"Hello, World!!"[9]  = r
"Hello, World!!"[10] = l
"Hello, World!!"[11] = d
"Hello, World!!"[12] = !
"Hello, World!!"[13] = !
"Hello, World!!"[14] = 

\x020 =  
\0 = 
Hello,\x020World! = Hello, World!
-----STEP 3.1-----
ARR INIT: Hello, World!!!
PTR INIT: Hello, World!!!

-----STEP 3.2-----
PTR DEC: Hello, World!!!
ARR DEC: Hello, World!!!
MLC DEC: Hello, World!!!

-----STEP 4-----
Addr of "PTR STO: Hello, World!!!!" = 0x103f71e77
Addr of ptr_str_sto       = 0x103f71e77
PTR STO: Hello, World!!!!
Addr of "ptr sto: hello, world!!!!" = 0x103f71edb
Addr of ptr_str_sto                 = 0x103f71edb
ptr sto: hello, world!!!!
Addr of arr_str_sto = 0x7ffeebc8f860
ARR STO: Hello, World!!!!

Addr of arr_str_sto = 0x7ffeebc8f860
arr sto: hello, world!!!!
Addr of int i = 0x7ffeebc8f834
int i         = 1
Addr of int i = 0x7ffeebc8f834
int i         = 2
mlc_string1 = Hello
mlc_string2 = hello
mlc_string1 = Hello


(未完)

PythonでChromeDriverを自動更新するプログラムを作った。

概要
Seleniumchrome driverを使ってスクレイピングをおこなうが、Googleクロムのアプリは自動的に最新版となる。それによって、chrome driverのバージョンとクロムのバージョンが異なることによって、次のようなエラーが生じる。

selenium.common.exceptions.SessionNotCreatedException: Message: session not created: This version of ChromeDriver only supports Chrome version 83

通常は最新のchrome driverをウェブ上からダウンロードして新しいchrome driverに替えなければならない。
今回はchrome driverを最新版のバージョンに自動的にアップデートするようなプログラムをrequestsBeautifulSoupなどを用いて作る。


プログラム

### import Selenium
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys

import subprocess
import re
import os
import urllib.request
import requests
from bs4 import BeautifulSoup

### get the current chrome version
def get_chrome_version():
    chrome = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'

    chrome_data = subprocess.run([chrome, '--version'], stdout=subprocess.PIPE, encoding='UTF-8')

    chrome_str  = chrome_data.stdout
    ch_reg_exp  = re.findall('\d+', chrome_str)
    ch_full_ver = '.'.join(ch_reg_exp)
    ch_int_ver  = ch_reg_exp[0]

    chrome_version = ch_full_ver, ch_int_ver

    return chrome_version


### download the suitable chrome driver
def download_chrome_driver(chrome_version):
    download_return = False
    download_dir = '/Users/USERNAME_XXXXX/Downloads'
    url = 'https://chromedriver.chromium.org/downloads'
    res   = requests.get(url)
    soup  = BeautifulSoup(res.text, 'html.parser')
    list_notes_txt = soup.find_all('a', href=re.compile('notes.txt'))

    download_url = None
    mac_file     = '/chromedriver_mac64.zip'
    for notes_txt in list_notes_txt:
        match = re.search(r'\d+', notes_txt.get('href'))
        if match.group(0) == chrome_version:
            notes_txt = notes_txt.get('href')
            download_url = os.path.dirname(notes_txt) + mac_file
            break

    if download_url != None:
        new_chrome_driver = download_dir + mac_file
        ### download
        urllib.request.urlretrieve(download_url, new_chrome_driver)

        ### unzip the file 'chromedriver_mac64.zip'
        subprocess.run(['unzip', new_chrome_driver], stdout=subprocess.PIPE, encoding='UTF-8')

        ### delete the zip file
        subprocess.run(['rm', new_chrome_driver])

        ### Because the unzipped chrome driver lies in the current directory, move it to the directory 'download_dir'
        subprocess.run(['mv', './chromedriver', download_dir])
        download_return = True

    return download_return

### change the new chrome driver
def change_new_chrome_driver():
    old_chrome_driver = '/Users/USERNAME_XXXXX/opt/anaconda3/lib/python3.7/site-packages/chromedriver_binary/chromedriver'
    new_chrome_driver = '/Users/USERNAME_XXXXX/Downloads/chromedriver'

    subprocess.run(['open', new_chrome_driver])
    subprocess.run(['rm', old_chrome_driver])
    subprocess.run(['mv', new_chrome_driver, old_chrome_driver])

### main
### Initialize Chrome
try:
    ### Success
    DRIVER_PATH = r'/Users/USERNAME_XXXXX/opt/anaconda3/lib/python3.7/site-packages/chromedriver_binary/chromedriver'
    options = Options()
    options.add_argument('--headless')

    driver = webdriver.Chrome(executable_path=DRIVER_PATH, options=options)

except Exception:
    #### Version Error
    ### STEP 1: get the current chrome version
    ret_val_1 = get_chrome_version()

    ### STEP 2: download the suitable chrome driver
    ret_val_2 = download_chrome_driver(ret_val_1[1])

    ### STEP 3: change the new chrome driver
    if ret_val_2 == True:
        change_new_chrome_driver()


プログラムの方針
STEP 1: 現在のGoogle Chromeのバージョンを取得する。
1.1: subprocessを使って、Chromeのバージョンを取得する。
ターミナル上で次のコマンドを打つと、現在使用中のChromeのバージョンがわかる。

$ Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --version
$ Google Chrome 87.0.4280.67

このコマンド操作をsubprocessを使って、Pythonのファイルでおこなう。

1.2: reを使って、取得したChromeの情報からバージョンの数値のみを取得する。
(87.0.4280.67, 87)


STEP 2: requestsBeautifulSoupで適切なバージョンのchrome driverを取得する。
2.1: バージョンに合うURLを取得する。
https://chromedriver.storage.googleapis.com/87.0.4280.88/chromedriver_mac64.zip

2.2: urllib.request.urlretrieveを使って、ダウンロードする(requestsでもできると思う)。

2.3: subprocessを使って、zip形式を解凍して、zipファイルを捨てる。


STEP 3: subprocessを使って、すでにあるchrome driverをDownloads配下にある最新のchrome driverに変更させる。

(だいたい完)

C言語の構造体とtypedefとsizeofについて

C言語の構造体の書き方についてまとめました。
また、構造体のサイズを取得するときのsizeofについてまとめました。
typedefをtypedefすることは基本的にないそうです。
また、構造体をsizeofをすると自動的にパディングします。余計なビットが加わります。

ソースコード

#include <stdio.h>

// without typedef
struct st_example {
    char char_;
    int  int_;
};

// with typedef (1)
typedef struct {
    char char_;
    short short_;
} st_example_typedef;


//with typedef (2)
typedef struct _st_example {
    char char_;
    int int_;
} st_example_;

// we do not define typedef struct st_example_ *example_ptr;
typedef struct _st_example *example_ptr;

int main(void) {

// without typedef
struct st_example ins;
ins.char_ = 'a';
ins.int_ = 1;

printf("ins.char_ = %c\n", ins.char_);
printf("ins.int_ = %d\n", ins.int_);
printf("sizeof(struct st_example) = %lu\n", sizeof(struct st_example));
printf("-------------------\n");

// with typedef (1)
st_example_typedef ins_td;
ins_td.char_ = 'b';
ins_td.short_ = 2; 

printf("ins_td.char_ = %c\n", ins_td.char_);
printf("ins_td.short_ = %d\n", ins_td.short_);

printf("sizeof(st_example_typedef) = %lu\n", sizeof(st_example_typedef));


実行結果

ins.char_ = a
ins.int_ = 1
sizeof(struct st_example) = 8
ーーーーーーーーーー
ins_td.char_ = b
ins_td.short_ = 2
sizeof(st_example_typedef) = 4

最初の構造体st_exampleのサイズはintが4バイトであるため、charの1バイトプラス3バイト分、追加されます。したがって、sizeof(struct st_example)は4 + 1 + 3 = 8バイトとなります。

一方で、次の構造体st_example_typedefのサイズはshortが2バイトですので、charの1バイトプラス1バイト分、追加されます。したがって、sizeof(st_example_typedef)は2 + 1 + 1 = 4バイトとなります。


また、一度typedefしたものをさらにtypedefはしないそうです。
つまり、typedef struct _st_example *example_ptr;はしますが、typedef st_example_ *example_ptr;はしません。理由はよくわかりませんが。



僕から以上