- 세상의 모든 계산기 자유(질문) 게시판 일반 ()
(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
결과

세상의모든계산기 님의 최근 댓글
엑셀 파일로 만드니 전체 160~200MB 정도 나옵니다. 읽고 / 저장하는데 한참 걸리네요. 컴 사양을 좀 탈 것 같습니다. 100만 개 단위로 끊어서 20MB 정도로 분할해 저장하는 편이 오히려 속 편할 것 같습니다. 2026 02.10 엑셀 / 행의 최대 개수, 열의 최대 개수, 셀의 최대 개수 엑셀의 행 개수 제한은 파일 형식에 따라 다르며, 최신 .xlsx 파일 형식은 시트당 최대 1,048,576행까지 지원하지만, 구형 .xls 파일은 65,536행으로 제한됩니다. 따라서 대용량 데이터를 다룰 때는 반드시 최신 파일 형식(.)으로 저장해야 하며, 행과 열의 총 수는 1,048,576행 x 16,384열이 최대입니다. 주요 행 개수 제한 사항: 최신 파일 형식 (.xlsx, .xlsm, .xlsb 등): 시트당 1,048,576행 (2^20). 구형 파일 형식 (.xls): 시트당 65,536행 (2^16). 그 외 알아두면 좋은 점: 최대 행 수: 1,048,576행 (100만여개) 최대 열 수: 16,384열 (XFD) 대용량 데이터 처리: 65,536행을 초과하는 데이터를 다루려면 반드시 .xlsx 형식으로 저장하고 사용해야 합니다. 문제 해결: 데이터가 많아 엑셀이 멈추거나 오류가 발생하면, 불필요한 빈 행을 정리하거나 Inquire 추가 기능을 활용하여 파일을 최적화할 수 있습니다. 2026 02.10 [일반계산기] 매출액 / 원가 / 마진율(=이익율)의 계산. https://allcalc.org/20806 2026 02.08 V2 갱신 (nonK / K-Type 통합형) 예전에는 직접 코드작성 + AI 보조 하여 프로그램 만들었었는데, 갈수록 복잡해져서 손 놓고 있었습니다. 이번에 antigravity 설치하고, 테스트 겸 새로 V2를 올렸습니다. 직접 코드작성하는 일은 전혀 없었고, 바이브 코딩으로 전체 작성했습니다. "잘 했다 / 틀렸다 / 계산기와 다르다." "어떤 방향에서 코드 수정해 봐라." AI가 실물 계산기 각정 버튼의 작동 방식에 대한 정확한 이해는 없는 상태라서, V1을 바탕으로 여러차례 수정해야 했습니다만, 예전과 비교하면 일취월장 했고, 훨씬 쉬워졌습니다. 2026 02.04 A) 1*3*5*7*9 = 계산 945 B) √ 12번 누름 ㄴ 12회 해도 되고, 14회 해도 되는데, 횟수 기억해야 함. ㄴ 횟수가 너무 적으면 오차가 커짐 ㄴ 결과가 1에 매우 가까운 숫자라면 된 겁니다. 1.0016740522338 C) - 1 ÷ 5 + 1 = 1.0003348104468 D) × = 을 (n세트) 반복해 입력 ㄴ 여기서 n세트는, B에서 '루트버튼 누른 횟수' 3.9398949655688 빨간 부분 숫자에 오차 있음. (소숫점 둘째 자리 정도까지만 반올림 해서 답안 작성) 참 값 = 3.9362834270354... 2026 02.04