[nodejs] request, cheerio 를 이용한 웹페이지 크롤링

nodejs 를 이용하 웹페이지를 크롤링하는 것을 스터디 하고 있다. 아래는 nodejs의 request, cheerio 모듈을 이용하여 SIR 의 자유게시판의 제목, 작성자이름, ip 정보를 크롤링하는 코드이다. 자유게시판 리스트에 접속하여 게시글보기 링크의 href 값을 얻어 각 게시글보기 페이지에 접속하여 제목, 작성자명, ip 정보를 수집한다. SIR 사이트에 동시접속하는 것을 막기 위해 async, await 구문을 사용하여 순차적으로 게시글 보기가 실행되도록 했다.

사용모듈

const request = require('request').defaults({jar: true});
const cheerio = require('cheerio');

function downloadPage(url)
{
    return new Promise((resolve, reject) => {
        request(url, (error, response, body) => {
            if (error) reject(error);
            if (response.statusCode != 200) {
                reject('Invalid status code <' + response.statusCode + '>');
            }
            resolve(body);
        });
    });
}

function sleep(ms){
    return new Promise(resolve => {
        setTimeout(resolve, ms)
    });
}

async function getInfo(urls)
{
    try {
        for (i=0; i<urls.length; i++) {
            if (i > 0)
                await sleep(5000);

            var url = urls[i];
            var patt = /^https?:/;
            if (!patt.test(url))
                url = "https:" + url;
            var body = await downloadPage(url);

            var $ = cheerio.load(body);

            var title = $("#head_title", $("header.vbo_head")).text().trim();
            var name  = $("span.member", $("ul#head_info")).text().trim();
            var ip    = $("#info_name", $("ul#head_info")).children().remove().end().text().trim();

            console.log(title + " => " + name + " " + ip);
        }
    } catch (error) {
        console.log(error);
    }
}

try {
    request("https://sir.kr/cm_free", (error, response, body) => {
        var $ = cheerio.load(body);
        var hrefs = [];

        var lists = $("a.title_link", ".li_title", $("#sir_lbo"));

        lists.each(function() {
            var href = $(this).attr("href");

            hrefs.push(href);
        });

        if (hrefs.length > 0) {
            getInfo(hrefs);
        }
    });
} catch (error) {
    console.log(error);
}

각 게시글보기 실행은 await sleep(5000);  코드를 통해 5초 간격으로 실행되도록 했다.

smartmontools의 저장장치 오류 알림 메일로 받기

smartmontools 는 SSD 등의 저자장치 상태를 모니터링하는 툴이다. 저장장치에서 오류가 발생했을 때 메일로 오류 알림을 받을 수 있어 서버의 저장장치 오류를 확인하고 대비할 수 있는 방법이 될 수 있다. smartmontools 를 설치하고 메일 알림을 받기 위한 설정이다. 우분투 서버 16.04 x64 환경에서 테스트했다.

sudo apt-get -y install sendmail
sudo apt-get -y install mailutils
sudo apt-get -y install smartmontools

sendmail 등의 메일 패키지와 smartmontools 를 설치한다.

smartd 데몬 실행을 위해 /etc/default/smartmontools 파일을 아래와 같이 수정한다. #start_smartd=yes 의 주석을 제거한다.

# Defaults for smartmontools initscript (/etc/init.d/smartmontools)
# This is a POSIX shell fragment

# List of devices you want to explicitly enable S.M.A.R.T. for
# Not needed (and not recommended) if the device is monitored by smartd
#enable_smart="/dev/hda /dev/hdb"

# uncomment to start smartd on system startup
start_smartd=yes

# uncomment to pass additional options to smartd on startup
#smartd_opts="--interval=1800"

/etc/smartd.conf 에 메일 설정을 한다.

# The word DEVICESCAN will cause any remaining lines in this
# configuration file to be ignored: it tells smartd to scan for all
# ATA and SCSI devices.  DEVICESCAN may be followed by any of the
# Directives listed below, which will be applied to all devices that
# are found.  Most users should comment out DEVICESCAN and explicitly
# list the devices that they wish to monitor.
DEVICESCAN -d removable -n standby -m usermail@gmail.com -M exec /usr/share/smartmontools/smartd-runner

-m root 부분을 -m usermail@gmail.com 으로 변경한다. usermail@gmail.com 은 실제 알림을 받을 메일 주소를 지정한다. 설정 변경 후 smartd 데몬의 설정을 다시 로드 한다.

/etc/init.d/smartmontools reload

smartd 데몬에서 메일이 발송되는지 확인해 보기 위해서는 아래 명령을 실행한다.

sudo echo "/dev/sda -m usermail@gmail.com -M test" > /etc/smartd.conf.test
sudo smartd -c /etc/smartd.conf.test
sudo rm -f /etc/smartd.conf.test

smartmontools 등의 패키지 설치와 메일 발송 테스트를 자동화한 스크립트는 아래와 같다.

#!/bin/bash

# Install mail
sudo apt-get -y install sendmail
sudo apt-get -y install mailutils
sudo apt-get -y install smartmontools

# add email
sudo sed -i "21s/-m root/-m usermail@gmail.com/" /etc/smartd.conf
/etc/init.d/smartmontools reload

# email test
sudo echo "/dev/sda -m usermail@gmail.com -M test" > /etc/smartd.conf.test
sudo smartd -c /etc/smartd.conf.test
sudo rm -f /etc/smartd.conf.test

 

참고자료

우분투 서버 netdata 에 smart_log 차트 표시

운영 중인 서버의 모니터링을 위해 netdata 를 사용하고 있다. 리얼 단독서버인 경우에는 디스크의 오류를 모니터링할 수 있어야 하는데 netdata 에서  S.M.A.R.T 정보를 차트로 표시하기 위해서는 약간의 작업이 필요하다. 우분투 서버에서는 smartmontools 패키지를 설치한다.

sudo apt-get -y install smartmontools

smartd 데몬 실행을 위해 /etc/default/smartmontools 파일을 아래와 같이 수정한다.

# Defaults for smartmontools initscript (/etc/init.d/smartmontools)
# This is a POSIX shell fragment

# List of devices you want to explicitly enable S.M.A.R.T. for
# Not needed (and not recommended) if the device is monitored by smartd
#enable_smart="/dev/hda /dev/hdb"

# uncomment to start smartd on system startup
start_smartd=yes

# uncomment to pass additional options to smartd on startup
smartd_opts="--interval=600 -A /var/log/smartd/"

-A /var/log/smartd/ 옵션을 통해 smartd 로그 파일을 /var/log/smartd/ 디렉토리에 생성한다. netdata 에서 기본으로 smartd 로그를 읽는 위치이다. smartd 디렉토리가 없다면 생성해 둔다. smartd 를 재시작한다.

service smartmontools restart

smartd 로그 파일을 확인할 수 있으면 netdata 를 재시작한다. netdata 에서는 추가적인 설정없어도 smartd_log 차트를 표시할 것이다.

service netdata restart

참고자료

우분투 서버에서 uptime 체크 후 일정일 이상이면 자동 재부팅 스크립트

관리하는 서버가 많아지니 서버의 uptime 체크 후 재부팅하는 것도 일이다. 그래서 각 서버에서 cron 으로 uptime 체크 후 일정일 이상 경과했으면 보안패치 등을 적용하고 자동 재부팅하는 쉘스크립트를 작성했다. 실제 서버에 적용 전이라 오류를 확인해보진 않았다. 적용 후 오류가 발견된다면 코드를 수정할 예정이다.

#!/bin/bash
read -d. seconds < /proc/uptime

# 10일 이상 경과
DATES=10

UPTIME=24*60*60*$DATES

if (( $seconds > $UPTIME )); then
    sudo apt-get -y update
    #sudo apt-get -y upgrade
    DEBIAN_FRONTEND=noninteractive DEBIAN_PRIORITY=critical sudo apt-get -q -y -o "Dpkg::Options::=--force-confdef" -o "Dpkg::Options::=--force-confold" dist-upgrade
    sudo apt-get -y autoremove
    sudo reboot
fi

코드에서는 10일 이상 경과했을 경우에 보안패치 등을 적용하고 자동 재부팅한다.

  • 2018-09-18 16:00 업그레이드 때 설정파일 유지 등의 화면 표시가 되지 않고 자동 업그레이드 되도록 코드 수정