- 세상의 모든 계산기 자유(질문) 게시판 일반 ()
(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
결과
세상의모든계산기 님의 최근 댓글
고장남 - POST 진입 실패, 모니터 안나옴 직접 사용할 일이 없어져서, 고향집에 가져다 놓고 어댑터만 꼽아 두었습니다. 마지막으로 켠 것은 25년 6월쯤이 아니었을까 싶습니다. (이상증상은 없었구요) 이번 추석에 가서 켜 보니까, 화면이 아예 안나오더라구요. 집에 가져와서 분해해 살펴보니까 - 어댑터 12V는 정상 - 어댑터 꼽으면 바로 POWER 는 켜집니다. ㄴ POWER ON -> Fan 돌아감 + 파워 LED 들어옴 + NVME에 LED 들어옴 ㄴ HDMI 1, 2 신호 전혀 안들어옴 (모니터 2대 확인) ㄴ 키보드에 LED 안들어옴 (USB 5V 가 안들어오는 듯 함) - 옆구리 버튼은 작동하지 않습니다. 길게 눌러도 꺼지지 않음. 하나씩 제거하면서 변수를 제거해 봤는데, 뭘 해도 상태가 똑같습니다. 보드쪽에 문제가 생긴 것 같습니다. 2025 10.14 다항식 나눗셈 (가장 정석적인 방법) (피제수, 나뉠 식) r1*r3 를 (제수, 나누는 식) r1+r3 로 직접 나누며, 여기서 r1을 변수로 취급합니다. 1. 몫 구하기: r1*r3 (나뉠 식)의 최고차항을 r1+r3 (나누는 식)의 최고차항 r1로 나눕니다. (r1*r3) / r1 = r3 <-- 이것이 몫(Quotient)이 됩니다. 2. 나머지 구하기: (원래 분자) - (몫 × 분모) 를 계산합니다. (r1*r3) - (r3 × (r1+r3)) = r1*r3 - (r1*r3 + r3^2) = -r3^2 <-- 이것이 나머지(Remainder)가 됩니다. 3. 결과 조합: 최종 결과는 `몫 + (나머지 / 나누는 식)` 형태로 씁니다. r3 + (-r3^2 / (r1+r3)) \[ \begin{array}{l} \phantom{r_1+r_3 \overline{) r_1 r_3}} r_3 \\ r_1+r_3 \overline{) \begin{array}[t]{@{}r@{}} r_1 r_3 \phantom{+r_3^2} \\ - (r_1 r_3 + r_3^2) \\ \hline -r_3^2 \\ \end{array}} \end{array} \] 2025 10.14 부분적 과정으로 분자(변수의 곱)를 다른 변수로 치환할 수 있다면 (r1*r3=a, r2*r4=b) 다항식에서도 강제 나눗셈 과정을 막을 수 있겠습니다만, 원래의 식에 적용시킬 수는 없어 의미가 없겠습니다. 2025 10.14 (r1*r3) / (r1+r3) 에서 원래라면 분자(r1*r3)에서 하나의 변수를 선택하여 그것을 기준으로 분모를 나누고 몫과 나머지로 분리하여 표현하는 것이 기본 원칙입니다만, 결과가 단항인 분수식일 경우 분자가 두 변수의 곱으로 표현되더라도 그것이 더 간단한 표현인 것으로 보고 그대로 두는 듯 합니다. 하지만 마지막 예시에서 보이는 것처럼 +1만 붙는 간단한 형식일지라도 다항식이 되는 순간 원래의 기본 원칙대로 대수의 나눗셈(r1*r3를 (r1+r3)로 나눔)이 강제 진행되어버리고 이를 막을 수 없는 듯 합니다. 2025 10.14 낮에 TV에서 영화 '말모이' 해주더라구요. 그래서 한번 물어 봤습니다. 2025 10.10