- 세상의 모든 계산기 자유(질문) 게시판 일반 ()
(Nginx) "웹 크롤러 request 순위 확인" 스크립트 (우분투)
#!/bin/bash
# monip.sh
# Nginx access 로그에서 상위 25개 IP를 분석하여
# - Bot (Crawler)인 경우: User-Agent 문자열로 Bot 종류를 추출
# - User인 경우: whois 명령으로 Organization Name 조회
# 그리고 IP별 국가 정보(geoiplookup)를 추가하여 출력함
LOG_FILE="/var/log/nginx/access.log"
if [ ! -f "$LOG_FILE" ]; then
echo "로그 파일이 존재하지 않습니다: $LOG_FILE"
exit 1
fi
awk '
# Bot의 종류를 판별하는 함수
function get_bot_type(ua, ua_lower) {
ua_lower = tolower(ua)
if(ua_lower ~ /googlebot/) return "Googlebot"
if(ua_lower ~ /bingbot/) return "Bingbot"
if(ua_lower ~ /slurp/) return "Yahoo Slurp"
if(ua_lower ~ /duckduckbot/) return "DuckDuckBot"
if(ua_lower ~ /baiduspider/) return "Baiduspider"
if(ua_lower ~ /yandex/) return "YandexBot"
return "Unknown Bot"
}
# User-Agent 문자열을 바탕으로 사용자 종류를 판별
function classify_user_agent(ua) {
if(ua == "" || ua == "-") return "알 수 없음"
ua_lower = tolower(ua)
if(ua_lower ~ /bot|crawl|spider|slurp|mediapartners/) return "Bot (Crawler)"
return "User"
}
# geoiplookup 명령을 사용하여 IP의 국가 정보를 가져오는 함수
function get_country(ip, cmd, result, arr, country) {
cmd = "geoiplookup " ip " 2>/dev/null"
if ((cmd | getline result) > 0) {
# 예: "GeoIP Country Edition: US, United States"
split(result, arr, ":")
if(length(arr) > 1) {
country = arr[2]
gsub(/^[ \t]+|[ \t]+$/, "", country)
} else {
country = "Unknown"
}
} else {
country = "조회 실패"
}
close(cmd)
return country
}
{
# Combined log format 예제:
# 127.0.0.1 - - [14/Feb/2025:12:00:00 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 ..."
regex = "([^ ]*) - ([^ ]*) \\[([^\\]]*)\\] \"([^\"]*)\" ([^ ]*) ([^ ]*) \"([^\"]*)\" \"([^\"]*)\""
if(match($0, regex, arr)) {
ip = arr[1]
referer = arr[7]
ua_str = arr[8]
count[ip]++ # IP별 요청 횟수 집계
ua_stats[ip, ua_str]++ # IP별 User-Agent 빈도 집계
ref_stats[ip, referer]++ # (참고용) 리퍼러 집계
}
}
END {
# gawk의 asorti() 함수로 요청 횟수 기준 내림차순 정렬
n = asorti(count, sorted, "@val_num_desc")
# 헤더 출력 (순서: 순위 | IP | 국가 | Requests | 사용자 종류 | 기타정보)
printf("| %-2s | %-15s | %-18s | %-10s | %-17s | %-21s |\n", "순위", "IP", "국가", "Requests", "사용자 종류", "기타정보")
print("|------|-----------------|----------------------|------------|------------------------|-------------------------|")
limit = (n < 25 ? n : 25)
for(i = 1; i <= limit; i++){
ip = sorted[i]
req_count = count[ip]
# 해당 IP의 가장 많이 등장한 User-Agent 선택
max_ua = ""
max_ua_count = 0
for(key in ua_stats) {
split(key, parts, SUBSEP)
if(parts[1] == ip) {
if(ua_stats[key] > max_ua_count) {
max_ua_count = ua_stats[key]
max_ua = parts[2]
}
}
}
user_type = classify_user_agent(max_ua)
extra = ""
if(user_type == "User") {
# User인 경우: whois 명령으로 Organization Name 조회
cmd = "whois " ip " 2>/dev/null | grep -i -m 1 \"orgname:\""
org = ""
if((cmd | getline org) > 0) {
sub(/^[ \t]+/, "", org)
split(org, a, ":")
if(length(a) > 1) {
org = a[2]
gsub(/^[ \t]+/, "", org)
}
} else {
org = "조회 실패"
}
close(cmd)
extra = org
} else if(user_type == "Bot (Crawler)") {
extra = get_bot_type(max_ua)
} else {
extra = "없음"
}
# 각 IP의 국가 정보 추가
country = get_country(ip)
printf("| %-4d | %-15s | %-20s | %-10d | %-22s | %-25s |\n", i, ip, country, req_count, user_type, extra)
}
}
' "$LOG_FILE"
사용 방법
- 스크립트를 파일에 저장 후 실행 권한 부여:
chmod +x monip.sh - 스크립트 실행 (필요한 경우 sudo로):
sudo ./monip.sh
결과

세상의모든계산기 님의 최근 댓글
[fx-570 CW] 와의 차이 CW에 【×10x】버튼이 사라진 것은 아닌데, 버튼을 누를 때 [ES][EX] 처럼 특수기호 뭉치가 생성되는 것이 아니고, 【×】【1】【0】【xㅁ】 버튼이 차례로 눌린 효과가 발생됨. ※ 계산 우선순위 차이가 발생할 수 있으므로 주의. 괄호로 해결할 것! 2026 01.18 26년 1월 기준 국가 전문자격 종류 가맹거래사 감정사 감정평가사 검량사 검수사 경매사 경비지도사 경영지도사 공인노무사 공인중개사 관광통역안내사 관세사 국가유산수리기능자(24종목) 국가유산수리기술자 국내여행안내사 기술지도사 농산물품질관리사 물류관리사 박물관 및 미술관 준학예사 변리사 사회복지사 1급 산업보건지도사 산업안전지도사 세무사 소방시설관리사 소방안전교육사 손해평가사 수산물품질관리사 정수시설운영관리사 주택관리사보 청소년상담사 청소년지도사 한국어교육능력검정시험 행정사 호텔경영사 호텔관리사 호텔서비스사 2026 01.17 국가전문자격 2026 01.17 991CW+ KR 버전이 나오면, 그 때는 (어쩔 수 없이) CW 를 추천하게 될지도 모르겠습니다. 2026 01.14 참고리뷰 : https://www.reddit.com/r/calculators/comments/1o7kj7f/casio_fx9910cw_review_a_much_needed_improvement/ 카시오 FX-9910CW 리뷰: 절실히 필요했던 개선이지만… 너무 늦은 감이 있는 걸까? 2026 01.13