구글 시트 함수 레시피 한 개 추가

  • 태그 연관성: #google-sheets-formula, #recipe

Recipe, 특정 범위에서 12번째 컬럼의 모든 열을 범위로 받고 싶다

INDEX 사용

  • INDEX 함수 설명, 구글
  • INDEX는 보퉁 참조된 범위 내에서 특정 행과 열에 해당하는 만 반환 한다
  • INDEX는 때문에 행, 열의 INDEX는 보통 1이상의 정수가 입력되는데..
  • 하지만 행이나 열 부분에 0이 입력될 경우 0이 아닌 값을 가진 행이나 열의 전체 배열을 반환하게 된다
  • 사용례
    • =INDEX(이름이지정된범위, 0, 12)
    • 이름이지정된범위의 12번째 컬럼 배열이 반환됨

OFFSET 사용

  • OFFSET 함수 설명, 구글
  • OFFSET은 원래 범위 참조를 반환하는 함수다
  • 첫번째 argument인 셀 참조 에는 보통 A2와 같이 지정된 셀주소를 넣지만
    • 이름이지정된범위 를 넣으면 해당 범위의 LeftTop 지점이 OFFSET을 계산할 기준으로 설정된다
  • 행 수를 계산하기 위해 ROWS() 를 사용했다
  • 때문에 위의 INDEX 와 같은 결과를 반환하려면 아래와 같이 사용한다
    • =OFFSET(이름이지정된범위,0,11,ROWS(이름이지정된범위),1)
    • 이름이지정된범위의 12번째 컬럼의 범위 참조가 반환된다

차이점 ?

  • 반환하는 값의 명치이 배열범위 참조로 차이가 있다
  • 배열범위 참조에 어떤 실질적 차이가 있는지는 아직 발견하지 못했다

Plus Recipe, 특정 범위에서 특정 컬럼을 기준으로 Filtering 하고 싶다

  • FILTER 함수 설명, 구글
  • 위의 Recipe 결과를 반환받아 다음과 같이 응용할 수 있다
  • 12번째 컬럼이 B02값을 갖는 행만 필터링해서 보고 싶다
    • =FILTER(이름이지정된범위,INDEX(이름이지정된범위,0,12) = 'B02')

개인위키에서 태그 검색시에 조합 태그를 사용할 수 있을까? (2022-03-14)

  • 태그 연관성: #wiki-setting
  • 스택 오버플로의 태그 페이지를 보면 여러태그의 조합으로 질문 필터링을 할 수 있다
  • 개인 위키 태그 페이지는 한 개의 태그를 선택하면 그 태그에 해당하는 포스팅만 나오는 구조라 조합 태그를 사용할 수 없다
  • 조합 태그를 사용할 수 있도록 구조를 바꿔보자
  • 필요성 ?
    • 위 섹션의 구글 시트 함수 레시피 에 두 개의 태그를 쓰고 싶다
    • #google-sheets-formula, #recipe
    • 두 개의 태그 조합시 이 태그 두개가 붙은 포스팅이 모두 검색되면 좋겠다
  • 여유가 있을 때 해보자
  • 관련 링크

용어정리 필요 - React를 CDN으로 사용할 경우 권장하는 crossorigin 속성에 대해

관련 링크

꼽사리 .. Evans Libary 정리가 잘된 개인 블로그 인듯

구글시트 에서 직접 스크레이핑 하기

GCP에 대해 아라보자 (2022-03-17)

How to puppeteer on Google Cloud Functins - Youtube

  • Tech Youtube 따라해보기
  • 0:59 , Kickstart 등장
    • create-react-app 같은 것인줄 알았는데.. 그런 공식적인 것은 아니고..
    • 아래와 같이 그냥 만든 generic batch function
      1
      2
      3
      4
      
      kickstart () {
        mkdir $1 && cd $1 && git init && npm init -y $$ code .
        echo "You're awesome 🤟"
      }
      

Creating a Puppeteer microservice to deploy to Google Cloud Functions

  • 작성일 : 2021.10.14, 제목에 원본 링크함
  • 이 기사에서는 GitHub에서 키워드를 검색해서 첫번째 결과에서 title을 fetch해오는 예제를 만들어볼것 이다
    • 이것은 순전히 예제를 위한것이며 굳이 Puppeteer를 사용하지 않아도 된다
    • keyword는 URL에 있고 Github의 페이지에 페이지 목록이 있기 때문에 결과로 바로 navigating 할 수 있다
  • 하지만, web page와 interaction이 page URL에 반영되지 않고 이 데이타를 fetch해올수 있는 API가 없다고 가정하자
    • 이 경우 Puppeteer를 통한 자동화가 필요해질것이다

Setting up Puppeteer and Node.js

  • Puppeteer 프로젝트를 처음 시작하기
    • node.js 프로젝트를 시작하고 puppeteer 설치하기
    • 가장 기본적인 템플릿으로 puppeteer가 동작하는지 확인
      1
      2
      3
      4
      5
      6
      7
      8
      
      import puppeteer from 'puppeteer';
          
      const browser = await puppeteer.lauch({
        headless: false
      });
          
      const page = await browser.newPage();
      await page.goto('https://www.github.com');
      
    • 실행방법
      • package.json의 script 에 "run": "node ./src/service.mjs",를 추가하고 npm run-script run을 실행
      • 아니면 그냥 node ./src/service.mjs를 실행

Using automation with Puppeteer

  • Puppeteer로 다음 동작을 자동화하여 실행해봄
    • github.com 을 접속하여 ‘react’로 keyword 검색
    • 프로젝트 리스트중 첫번째 프로젝트의 title을 가져옴
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      
      import puppeteer from 'puppeteer';
      
      const service = async (keyword) => {
        const browser = await puppeteer.launch({
          headless: true,
          defaultViewport: {
            width: 1920,
            height: 1080
          }
        });
      
        const inputField = '.header-search-input';
        const repoList = '.repo-list';
      
        try {
          const page = await browser.newPage();
          await page.goto('https://www.github.com');
      
          await page.waitForSelector(inputField);
          await page.focus(inputField);
          await page.keyboard.type(keyword);
      
          await page.keyboard.press('Enter');
      
          await page.waitForNavigation();
          await page.waitForSelector(repoList);
      
          const title = await page.evaluate((repoList) => (
            document
              .querySelector(repoList)
              .querySelectorAll('li')[0]
              .querySelector('.f4.text-normal')
              .innerText
          ), repoList);
      
          await browser.close();
          return title;
        } catch (e) {
          throw e;
        }
      }
      
      export default service;
      
  • 위 과정중 알게된 knowledge
    • page.waitxxx method로 로딩이 끝나길 기다려 실행할 수 있음
      • page.waitForNavigation, page.waitForSelector 등을 사용해봄
    • page.evalute method로 실제 scrape 를 실행할 수 있음
  • 위 작업의 결과물을 다른 파일에서도 사용할 수 있게 function으로 wrap하고 export 함
    • service.mjs의 최종 결과물은 keyword를 입력받는 async function 임
    • 혹시 에러가 발생하면 알 수 있도록 try..catch 블럭을 사용함
    • 작업이 끝난후 browser.close를 호출하여 용무가 끝난 browser 를 닫음

Creating an Express server

  • 우선 다음 명령으로 express 설치한다
    1
    
    $ npm install express --save
    
  • 서버코드는 다음과 같다
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    // server.mjs
    import express from 'express';
    import service from './service.mjs';
    
    const app = express();
    app.listen(5000);
    
    app.get('/:keyword', async (req, res) => {
      const { keyword } = req.params;
      try {
        const response = await service(keyword);
        res.status(200).send(response);
      } catch (e) {
        res.status(500).send(e);
      }
    });
    
  • 이 섹션에서는 express로 간이 서버를 만들고 service.mjs를 서비스한다
    • express 서버에 접속하면 우리는 contents로 우리가 scraping 해온 title을 얻을수 있다
    • 본문에서는 curl localhost:5000/react 형식으로 실행했는데
      • windows10의 Powershell에서는 다음과 같이 Invoke-WebRequest명령으로 실행한다. Contestfacebook/react를 가져온 것이다
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        
        ❯ Invoke-WebRequest -Uri http://localhost:3000/react
              
        StatusCode        : 200
        StatusDescription : OK
        Content           : facebook/react
        RawContent        : HTTP/1.1 200 OK
                            Connection: keep-alive
                            Keep-Alive: timeout=5
                            Content-Length: 14
                            Content-Type: text/html; charset=utf-8
                            Date: Sat, 19 Mar 2022 06:08:16 GMT
                            ETag: W/"e-snvGvaecsCpaaBiKy352NKIUZX0"...
        Forms             : {}
        Headers           : {[Connection, keep-alive], [Keep-Alive, timeout=5], [Content-Length, 14], [Content-Type, text/html; charset=ut
                            f-8]...}
        Images            : {}
        InputFields       : {}
        Links             : {}
        ParsedHtml        : mshtml.HTMLDocumentClass
        RawContentLength  : 14
        
      • 위 Invke-WebRequest 호출에서 keyword를 다른 것으로 바꿔보며 테스트해보자
  • 이 예제는 최소한으로 동작을 확인하기 위한것이다
    • 실제 사용시에는 endpoint에 보안작업이 필요하며
    • 서버가 아닌 브라우저로부터 request를 send할경우 CORS 설정도 필요하다

Deploying to Google Cloud Functions

  • 드디어.. 이제 이 서비스를 serverless cloud function에 배포해보자
  • cloud function 과 서버의 차이점은 ?
    • cloud function : request 오는 순간 깨어나서 후속 request가 있을동안 깨어있음
    • server : 항상 깨어있는 상태
  • Google Cloud Function에 배포하는 것은 매우 간단하지만
  • Puppeteer가 성공적으로 실행되기 위해서 몇가지 알아둬야할 설정이 있다
    • 첫째로 충분한 메모리를 cloud function에 할당해야 한다
      • 내 경험으로는 512MB 정도면 Puppeteer를 돌릴수 있었는데
      • 혹시 memory-related 문제를 만나게 되면 좀더 할당해라
    • package.json 내용은 다음과 같아야 한다
      1
      2
      3
      4
      5
      6
      7
      8
      9
      
      {
        "name": "puppeteer-example",
        "version": "0.0.1",
        "type": "module",
        "dependencies": {
          "puppeteer": "^10.2.0",
          "express": "^4.17.1"
        }
      }
      
    • dependencies 에 puppeteerexpress를 추가하고 ES6 문법을 사용하기 위해 module로 설정했다

IT문서에서 사용되는 영어 표현 (2022-03-18)

due in part to

  • #english-idiom
  • 발견한 곳 : Creating a Command-line App … 에서 본문 첫번째 paragraph

    This is due in no small part to the fact that command-line apps tend to be efficient, fast, and powerful.

  • due in part to , collins dict : 콜린즈 사전의 예문들
  • due in part vs. in part due: 비슷한 다른 표현과의 예문 비교
  • 의미는 “partly because”
  • 나의 추론은…
    • This is dueto the fact .. (100% 그 사실 때문이다)
    • This is due in part to the fact .. (100%는 아니지만 부분적으로는 그 사실 때문이다)
    • This is due in no small part to the fact .. (100%는 아니지만 결코 작지않은 부분이 그 사실 때문이다)

(질문) Commander.js 와 Pkg는 같은 개념의 Library인가?

  • Commander.js 소개 : node.js 프로그램에 CLI 인터페이스를 지원
  • Pkg 소개 : node.js 애플리케이션을 바이너리 컴파일 하여 nodejs가 없는곳에서도 실행할수 있게 만듬
    • 생각해보니 pkg로 만든 바이너리가 꼭 Command line Interface일 필요는 없겠다고 생각됨
    • 다른게 당연 ?

축구 경기일정 calendar에 추가하기

울버햄턴

윈도우즈 이모지 선택하기

  • 페이지를 하나 만들까 했는데..이미 인터넷상에 있음

클립보드로 복사히기 버튼 만들기

CSS로 그림그리기

Naver Cloud Platform

  • 사용자 아이디 만듬 롱텀 지메일아이디로..
  • cloud function 지원함