파이썬으로 월별 통계 내기...

익명 사용자의 이미지

좋은 아이디어를 가지고 월별통계를 볼 수 있는 프로그램으로 파이썬과 wget으로 만들어보았습니다.
wget으로 만든 이유는 이런걸 하는 전용 프로그램이 있는데 굳이 파이썬의 urllib같은걸로 삽질할 필요가 없을 것 같아서 입니다.
Julian Date 모듈은 웹에서 찾아보니 쓸만한게 있더군요.(y,m,d형태로 형식만 바꿨습니다.)

또한 UTF-8환경에서 구동시키려면 iconv를 사용하여 이래저래 컨버전이 필요하더군요.

=======================================================
#!/usr/bin/python
import julian

def date_process(process_dt):
year,month,day=julian.DateToYMD(process_dt)
month+=1
if (month>12):
year+=1
month=1
gm_date=(year,month,day,0,0,0,0,0,0)
return "20" + time.strftime("%y%m%d",gm_date)

if __name__ == '__main__':
import os,sys,re,time
if len(sys.argv) < 4:
print 'Usage: ' + sys.argv[0] + 'from_dt(20050201) to_dt(20050301) keyword'
sys.exit()
start_time = time.mktime(time.strptime(sys.argv[1][2:], "%y%m%d"))+24*60*60/2
end_time = time.mktime(time.strptime(sys.argv[2][2:], "%y%m%d"))+24*60*60/2
keyword = sys.argv[3]
print keyword + " 에 대한 " + sys.argv[1] + "~" + sys.argv[2] + "까지의 검색인덱스 월별 건수"
while(start_time <= end_time) :
query_dt = "20" + time.strftime("%y%m%d",time.gmtime(start_time))
from_dt=julian.Julian(query_dt)
to_dt_time=date_process(query_dt)
to_dt=julian.Julian(to_dt_time)
query = "'http://www.google.com/search?hl=ko&num=10&q=\"" +keyword+'\" daterange:'+`from_dt`+'-'+`to_dt` + "'"
print query
ret_val = os.popen("echo " + query + " | iconv -f utf-8 -t cp949 | wget -i - -U 'Mozilla' -q -O - | iconv -f cp949 -t utf-8").read()
p=re.compile("<b>[0-9].*</b>개")
try:
count=p.search(ret_val).group()[3:][:-7] print `julian.JulianToYearMonthDay(from_dt)` + "~" + `julian.JulianToYearMonthDay(to_dt)` + "=" + count
except AttributeError:
print "Error or 0"
start_time = time.mktime(time.strptime(to_dt_time[2:], "%y%m%d")) + 24*60*60/2
==================================================================

julian.py
==================================================================
def NumDaysInMonth(year, month):
if month == 2:
if IsLeapYear(year):
return 29
else:
return 28
elif month == 9 or month == 4 or month == 6 or month == 11:
return 30
elif month == 1 or month == 3 or month == 5 or month == 7 or \
month == 8 or month == 10 or month == 12:
return 31
else:
raise "Bad month"

def JulianToYearMonthDay(julian_day):
if julian_day < 0: raise "Bad input value"
jd = julian_day + 0.5
Z = int(jd)
F = jd - Z
A = Z
if Z >= 2299161:
alpha = int((Z - 1867216.26)/36254.25)
A = Z + 1 + alpha - int(alpha/4)
B = A + 1524
C = int((B - 122.1)/365.25)
D = int(365.25 * C)
E = int((B - D)/30.6001)
day = B - D - int(30.6001 * E) + F
if E < 13.5:
month = int(E - 1)
else:
month = int(E - 13)
else:
month = int(E - 13)
if month > 2.5:
year = int(C - 4716)
else:
year = int(C - 4715)
return year, month, int(day)

def DayOfYear(year, month, day):
if IsLeapYear(year):
n = int((275*month)/9 - ((month + 9)/12) + int(day) - 30)
else:
n = int((275*month)/9 - 2*((month + 9)/12) + int(day) - 30)
if n < 1 or n > 366: raise "Internal error"
return n

def DayOfWeek(year, month, day):
julian = int(JulianAstro(month, int(day), year) + 1.5)
return julian % 7

def IsLeapYear(year):
if (year % 400 == 0) or (year % 4 == 0 and year % 100 != 0):
return 1
else:
return 0

def IsValidDate(year, month, day):
'''Returns true if the year is later than 1752 and the month and day
numbers are valid.
'''
if month < 1 or month > 12: return 0
'''
if month < 1 or month > 12: return 0
if int(month) != month : return 0
if year < 1753 : return 0
if day < 1.0 : return 0
if int(day) != day:
if month == 2:
if IsLeapYear(year):
if day >= 30.0: return 0
else:
if day >= 29.0: return 0
elif month == 9 or month == 4 or month == 6 or month == 11:
if day >= 31.0 : return 0
else:
if day >= 32.0 : return 0
else:
if month == 2:
if IsLeapYear(year):
if day >= 29 : return 0
else:
if day >= 28 : return 0
elif month == 9 or month == 4 or month == 6 or month == 11:
if day >= 30 : return 0
else:
if day >= 31 : return 0
return 1

def JulianAstro(year, month, day):
"Note that day can be either an integer or a float."
if month < 3:
year = year - 1
month = month + 12
year = year - 1
month = month + 12
julian = int(365.25*year) + int(30.6001*(month+1)) + day + 1720994.5
tmp = year + month / 100.0 + day / 10000.0
if tmp >= 1582.1015:
A = year / 100
B = 2 - A + A/4
julian = julian + B
return julian * 1.0

def Julian(year, month, day):
return int(JulianAstro(year, month, day) + 0.55)

def DateToYMD(date):
import string
year=string.atoi(date[0:4])
month=string.atoi(date[4:6])
day=string.atoi(date[6:8])
return year,month,day

def Julian(date):
year,month,day=DateToYMD(date)
return int(JulianAstro(year,month,day) + 0.55)

if __name__ == "__main__":
Test()

Forums: 
익명 사용자의 이미지

lifthrasiir의 이미지

code를 써서 indentation을 보존하시는 게 좋을 것 같습니다.

#!/usr/bin/python
import julian

def date_process(process_dt):
    year,month,day=julian.DateToYMD(process_dt)
    month+=1
    if (month>12):
        year+=1
        month=1
    gm_date=(year,month,day,0,0,0,0,0,0)
    return "20" + time.strftime("%y%m%d",gm_date)

if __name__ == '__main__':
    import os,sys,re,time
    if len(sys.argv) < 4:
        print 'Usage: ' + sys.argv[0] + 'from_dt(20050201) to_dt(20050301) keyword'
        sys.exit()
    start_time = time.mktime(time.strptime(sys.argv[1][2:], "%y%m%d"))+24*60*60/2
    end_time = time.mktime(time.strptime(sys.argv[2][2:], "%y%m%d"))+24*60*60/2
    keyword = sys.argv[3]
    print keyword + " 에 대한 " + sys.argv[1] + "~" + sys.argv[2] + "까지의 검색인덱스 월별 건수"
    while(start_time <= end_time) :
        query_dt = "20" + time.strftime("%y%m%d",time.gmtime(start_time))
        from_dt=julian.Julian(query_dt)
        to_dt_time=date_process(query_dt)
        to_dt=julian.Julian(to_dt_time)
        query = "'http://www.google.com/search?hl=ko&num=10&q=\"" +keyword+'\" daterange:'+`from_dt`+'-'+`to_dt` + "'"
        print query
        ret_val = os.popen("echo " + query + " | iconv -f utf-8 -t cp949 | wget -i - -U 'Mozilla' -q -O - | iconv -f cp949 -t utf-8").read()
        p=re.compile("<b>[0-9].*</b>개")
        try:
            count=p.search(ret_val).group()[3:][:-7]             print `julian.JulianToYearMonthDay(from_dt)` + "~" + `julian.JulianToYearMonthDay(to_dt)` + "=" + count
        except AttributeError:
            print "Error or 0"
        start_time = time.mktime(time.strptime(to_dt_time[2:], "%y%m%d")) + 24*60*60/2
==================================================================


julian.py
==================================================================
def NumDaysInMonth(year, month):
    if month == 2:
        if IsLeapYear(year):
            return 29
        else:
            return 28
    elif month == 9 or month == 4 or month == 6 or month == 11:
        return 30
    elif month == 1 or month == 3 or month == 5 or month == 7 or \
         month == 8 or month == 10 or month == 12:
        return 31
    else:
        raise "Bad month"

def JulianToYearMonthDay(julian_day):
    if julian_day < 0:  raise "Bad input value"
    jd = julian_day + 0.5
    Z = int(jd)
    F = jd - Z
    A = Z
    if Z >= 2299161:
        alpha = int((Z - 1867216.26)/36254.25)
        A = Z + 1 + alpha - int(alpha/4)
    B = A + 1524
    C = int((B - 122.1)/365.25)
    D = int(365.25 * C)
    E = int((B - D)/30.6001)
    day = B - D - int(30.6001 * E) + F
    if E < 13.5:
        month = int(E - 1)
    else:
        month = int(E - 13)
    else:
        month = int(E - 13)
    if month > 2.5:
        year = int(C - 4716)
    else:
        year = int(C - 4715)
    return year, month, int(day)

def DayOfYear(year, month, day):
    if IsLeapYear(year):
        n = int((275*month)/9 -   ((month + 9)/12) + int(day) - 30)
    else:
        n = int((275*month)/9 - 2*((month + 9)/12) + int(day) - 30)
    if n < 1 or n > 366:  raise "Internal error"
    return n

def DayOfWeek(year, month, day):
    julian = int(JulianAstro(month, int(day), year) + 1.5)
    return julian % 7

def IsLeapYear(year):
    if (year % 400 == 0) or (year % 4 == 0 and year % 100 != 0):
        return 1
    else:
        return 0

def IsValidDate(year, month, day):
    '''Returns true if the year is later than 1752 and the month and day
    numbers are valid.
    '''
    if month < 1 or month > 12: return 0
    '''
    if month < 1 or month > 12: return 0
    if int(month) != month    : return 0
    if year < 1753            : return 0
    if day  < 1.0             : return 0
    if int(day) != day:
        if month == 2:
            if IsLeapYear(year):
                if day >= 30.0: return 0
            else:
                if day >= 29.0: return 0
        elif month == 9 or month == 4 or month == 6 or month == 11:
            if day >= 31.0    : return 0
        else:
            if day >= 32.0    : return 0
    else:
        if month == 2:
            if IsLeapYear(year):
                if day >= 29  : return 0
            else:
                if day >= 28  : return 0
        elif month == 9 or month == 4 or month == 6 or month == 11:
            if day >= 30      : return 0
        else:
            if day >= 31      : return 0
    return 1

def JulianAstro(year, month, day):
    "Note that day can be either an integer or a float."
    if month < 3:
        year  = year - 1
        month = month + 12
        year  = year - 1
        month = month + 12
    julian = int(365.25*year) + int(30.6001*(month+1)) + day + 1720994.5
    tmp = year + month / 100.0 + day / 10000.0
    if tmp >= 1582.1015:
        A = year / 100
        B = 2 - A + A/4
        julian = julian + B
    return julian * 1.0

def Julian(year, month, day):
    return int(JulianAstro(year, month, day) + 0.55)

def DateToYMD(date):
    import string
    year=string.atoi(date[0:4])
    month=string.atoi(date[4:6])
    day=string.atoi(date[6:8])
    return year,month,day


def Julian(date):
    year,month,day=DateToYMD(date)
    return int(JulianAstro(year,month,day) + 0.55)

if __name__ == "__main__":
    Test()
lifthrasiir의 이미지

Julian Date가 기원전 4713년을 epoch로 하고는 있습니다만 실제 사용하기 위한 목적이라면 그런 거 다 무시하고 다음과 같은 코드를 쓰면 됩니다.

import datetime, time
def getjuliandate(y, m, d, h, i, s, tzoffset=None):
    if tzoffset is None: tzoffset = time.timezone
    ordinal = datetime.date(y, m, d).toordinal()
    return ordinal + (tzoffset + h*3600 + i*60 + s) / 86400. + 1721424.5

위의 코드는 기원후 1582년 이후에 대해서 모두 맞습니다. (Julian Calendar와 Gregorian Calendar 사이에는 최소 10일의 공백이 있습니다. 1920년대에 마지막으로 Gregorian Calendar로 바꾼 나라들은 15일인가까지 공백이 갔던 걸로 기억하네요.) 좀 더 신경써서 기원후 1년까지 다 맞게 하고 싶다면 다음과 같이 해도 되겠지요.
import datetime, time
def getjuliandate(y, m, d, h, i, s, tzoffset=None):
    if tzoffset is None: tzoffset = time.timezone
    ordinal = datetime.date(y, m, d).toordinal()
    if ordinal < 577726: ordinal += 10
    elif ordinal < 577736: raise ValueError
    return ordinal + (tzoffset + h*3600 + i*60 + s) / 86400. + 1721424.5

- 토끼군

perky의 이미지

좀 더 파이썬적으로 하시려면 iconv와 wget을 제거하시는 편이 에러 제어에나, 플랫폼 독립성, 의존성 여러 면에서 좋습니다.

iconv대신 파이썬 유니코드 코덱 (cp949는 Python 2.4이상 내장)을 사용하시면 되고, wget대신 urllib, urllib2, httplib (모두 파이썬 기본 라이브러리)를 사용하시면 됩니다.

You need Python

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.