일이 조금 있어서 네이버 카페의 크롤링 코드를 만들어야했다. 여러가지 글을 종합해서 처리할게 있었다. 가장 궁금했던건 어떻게 OTP인증이나 User-Agent가 브라우저가 아닌 요청이 Allow될지 였는데, 역시나 Selenium을 통해서 하면 User의 Action을 구사해서 할 수있었다.(Python 짱짱맨) 아래는 코드이다.
import time
from selenium import webdriver
import pandas as pd
from bs4 import BeautifulSoup as bs
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
if __name__ == "__main__" :
### 로그인 프로세스
login_url='https://nid.naver.com/nidlogin.login'
user_id="<USER ID>"
user_pw="<USER PW>"
browser=webdriver.Chrome(ChromeDriverManager().install())
browser.get(login_url)
browser.implicitly_wait(2)
browser.execute_script("document.getElementsByName('id')[0].value=\'"+ user_id + "\'")
browser.execute_script("document.getElementsByName('pw')[0].value=\'"+ user_pw + "\'")
browser.find_element(by=By.XPATH,value='//*[@id="log.login"]').click()
time.sleep(1)
### 크롤링 Target Url
baseurl=''
browser.get(baseurl)
pageNum = 0while(True) :
time.sleep(1)
pageNum +=1print(pageNum)
browser.get(baseurl +'&search.page='+ str(pageNum))
### 카페 메인 게시클 화면이 iframe으로 구성되어있음. iframe id가 cafe_main
browser.switch_to.frame('cafe_main')
soup = bs(browser.page_source ,'html.parser')
soup = soup.find_all(class_ = 'article-board m-tcol-c')[1]
datas = soup.select("#main-area > div:nth-child(4) > table > tbody > tr")
for data in datas:
### article 은 한줄입니다. 원하는 속성 get 후 처리
article = data.find(class_= "article")
print('Finish')
위와 같이 다른 언어에서의 변수 선언 시 type을 같이 지정해 주어야 하는 재래식 언어와는 많은 차별점을 둔다.
다만 이런 Python의 장점은 코드의 규모가 커지고 방대해질 수록 많은 문제를 야기하며, 프로그램의 동작상에서 동작하는 Runtime level의 문제라기보다는, 프로그래머 사이 작성되는 코드 혹은 과거의 나와 싸우고 있는 프로그래머들에게 Type의 힌트를 줄 필요성이 생겼다.
<최솟값을 찾는 함수 : JAVA의 경우>
// 최소값을 찾는 JAVA함수, int를 반환하고 ArrayList<int>를 받는다는 것을 함수에서 알 수 있다. public int findMinimumNumber(ArrayList<int> arr){ int result = arr[0]; for(int a : arr) if(result > a) result=a; return result; }
<최솟값을 찾는 함수 : Python의 경우>
### 내장함수 min에 의해 처리될 수 있는 value를 입력으로 받고 그의 원소값을 반환 ### 어떤형의 parameter를 받고 반환하는지 알 수 없다. def find_minimum(value) : return min(value)
위와 같은 문제들을 해결하기 위해 함수에 주석을 달거나 하는 프로그래머 개개인의 노력을 이용했다.
### param : list ret : int def find_minimum(value) : return min(value)
Python도 이 문제를 인식한 듯 Type Annotation을 제공한다. 다음과 같다.
deffind_minimum(value : list) -> int :returnmin(value)
사용법은 간단한다.
변수명 뒤 콜론(:)을 붙이고 type명을 기술 type명에는 클래스도 들어갈 수 있다.
함수의 반환은 화살표(->)을 붙이고 type명을 기술 당연하게도 여기도 클래스가 들어갈 수 있다.
단! 이렇게 적는 type annotation은 주석의 확장으로 밖에 여겨지지 않으며, 인터프리터는 해석 시 type annotation을 염두하지 않는다.
CVE_SCRAPPER를 만들고, 다음 목표는 이제 한물간 시장인 비트코인이다. 자동매매 프로그램을 올릴 거냐고? 물론 당연하다. 단 필자는 금융지식이 뛰어난 사람은 아니기 때문에 일단은 할 수 있는 장만 만들어 보려고 한다. 매도/매수 알고리즘은 돌리는 사람이 짜는 걸로 해야 되지 않을까 싶다. 그렇게 만들려면 으흠; 뭐 잘 만들면 되겠지
CveMain은 다음과 같이 실행된다. vendor의 목록은 cve_list directory에서 긁어온다.
Make Report로 보고서를 만들 수 있다. Exported?가 True인 행은 Information dialog가 띄워지며 export가 안된다. exported 된 여부 판단은 export_cve directory에 해당 cve보고서가 존재하는지 여부로 판단한다.
짧은 프로젝트였다. 정식으로 뿌리는 것도 아니고, 디자인을 하나도 안 한 프로젝트였다. 찾아보니 TISTORY API가 있는 거 같은데, 이거 자동화해서 블로그에 보고서를 올리면 좋을 거 같다. 크롤링 코드와 gui를 연습할 수 있는 좋은 경험이었던 거 같다. fpdf를 사용하다 보니 편하다는 것을 느꼈다. body부분의 글자별 스타일 적용이 어렵다는 느낌은 받았지만 다음 자동화 프로젝트도 fpdf로 출력할 거 같다.
파이선에서 날짜에 대한 연산을 도와주는 calendar라는 모듈이다. 현실세계의 날짜 연산에서 사용될 수 있는 계산 함수들을 제공한다. 하나하나 알아보자
Calendar 객체
모든 날짜 연산은 캘린더 객체에서 이루어 진다. 객체는 다음과 같이 생성한다.
>>> my_cal = calendar.Calendar()
### Calendar(firstweekday=0)로 인자지정이 가능하다. firstweekday는 언제가 그 주의 시작요일인지 정하는 것이다)
Calendar객체가 제공하는 연산은 다음과 같다.
iterweekdays() : 0~6까지의 요일 인덱스를 담고 있는 iterator를 반환한다. firstweekday가 지정되어있으면 시작 순서가 바뀐다.
itermonthdays(year,month) : year년도의 month동안의 iterator를 반환한다. 그니까 itermonthdays(2020,12)면 2020년 12월의 일을 포함한 iterator를 반환하는 건데, 달력에 표기하기 위한 만큼의 넘어가는주와 넘어오는주를 포함해서 반환한다. 그때 값은 0이다.
itermonthdays2(year,month) : itermonthdays와 같은 범위이나, (일, 요일)의 튜플형태의 iterator를 반환한다.