파이썬 코딩했는데 너무 for문 남발한 건가요?
글쓴이: lhm7877 / 작성시간: 수, 2016/03/02 - 1:13오전
어떤 사이트에 검색 결과 내용을 beautifulsoup를 이용해 파싱해오는 소스인데
소스 설명을 간단히 해드리자면
1. keyword_matrix라는 리스트에 00부터 99까지의 숫자를 넣고
2. 그 숫자들을
http://newnovel.aks.ac.kr/Search?keyword="+j+"&page=1"
ㄴ 이곳에 j에다 넣어서 각각의 페이지 수를 구하고(j는 검색어 , '00'을 검색하였을 때)
3. j 검색 시 페이지 수를 구할때마다 검색 페이지에 1페이지부터 for문으로 각각의 html을 가져오는데
4. 그 안에서 for문으로 테이블을 파싱한다.
이런 방식인데 for문을 남발해서 속도가 느린것 같습니다.
혹은 파싱하려는 사이트가 원할하지 않아 느릴수도 있고요.
제 코딩 방식이 비효율적인 소스인가요?
#-*- coding: utf-8 -*- #if 명령어 수정 #2차 keyword검색 import csv # csv 파일로 저장하기 위한 모듈 import urllib # http 연결용 모듈 import requests # http 연결용 모듈 from bs4 import BeautifulSoup # HTML 문서 파싱라이브러리 keyword_matrix = [] for r in range(100): keyword_matrix.append('%02i' % r) def get_pages(url): src = requests.get(url).text # url에 해당하는 웹페이지를 읽어서 소스코드를 문자열에 저장 if src.find(">>")!=-1: num = src[src.find("=",src.find(">>")-10)+1:src.find(">>")-2] else: num = 0; # .find() 는 문자열 내에 특정한 문자, 문자열이 있는지를 찾습니다. # .find("=", 10) 은 11번째 글자부터 "="가 있는지를 찾고, "="의 인덱스를 리턴합니다. # 없으면 -1이 리턴됩니다. # 위 코드는 # ">>" 가 있는 곳의 앞 9글자 위치부터 "="를 찾아서, "="의 바로 다음 글자부터, # ">>" 가 있는 곳의 바로 앞 2글자전까지 잘라냅니다. # 엄청복잡하네요 ㅎㅎ 이런 부분은 정규식으로 하면 좀 편합니다. # 그 문자열이 숫자인가 보군요. 정수형으로 변환해서 리턴합니다. return int(num) # with open() as f: 이 구문은 # f = open( ... ) # .... # f.close() # # 를 좀 더 예쁘고 안전하게 쓰는 코드입니다. # 궁금하시면 context manager 라고 검색해보시면 됩니다. with open('listing_second.csv', 'wb') as f: # csv 포맷으로 각 라인을 저장해주는 모듈을 파일 핸들러를 이용해서 초기화합니다. writer = csv.writer(f) # 1 ... 위에서 구한 숫자값 범위를 반복합니다. for j in keyword_matrix: #print j.encode('utf-8') pages = get_pages("http://newnovel.aks.ac.kr/Search?keyword="+j+"&page=1") print pages for i in range(1,pages+1): # url을 합성하고, url = "http://newnovel.aks.ac.kr/Search?keyword="+j+"&page="+str(i) print url # 그 url의 데이터를 받아와서, html 이라는 이름을 붙입니다. u = urllib.urlopen(url) try: html = u.read() finally: u.close() # 받아온 데이터를 BeautifulSoup를 이용해서 파싱합니다. # 이때 파서 모듈은 "lxml"을 씁니다. soup=BeautifulSoup(html, "lxml") # BeautifulSoup의 자세한 내용은 라이브러리 문서를 확인하세요. # 아마 한글로 제공할겁니다. # html 중 특정 클래스가 있는 TABLE 요소를 찾습니다. table=soup.find("table", {"class":"table table-striped table-hover oldkorean"}) # 테이블의 세번째 TR 요소부터, for tr in table.find_all('tr')[2:]: # 각 줄의 TD 요소를 얻고, 다시 tds = tr.find_all('td') # 각 TD의 내부 텍스트(text node)를 이어서 리스트로 만듭니다. row = [elem.text.encode('utf-8') for elem in tds] # 4번째 열의 문자열이 "_"를 포함하고 있으면, # 이를 _ 중심으로 쪼개서 4번째 열은 그 왼쪽 것을 # 오른쪽 나머지는 맨 마지막으로 붙입니다. # 그리고 이 행을 csv 파일에 씁니다. if "_" in row[3]:#문자열 내에 특정 글자가 있는지 검사 left, right = row[3].split("_", 1) row[3] = left row.append(right) writer.writerow(row)
Forums:
스크립트는 시간 잡아먹을만한 부분도 눈에 띄지 않고
스크립트는 시간 잡아먹을만한 부분도 눈에 띄지 않고 for 문도 많지 않네요.
키워드별, 페이지수별, TR갯수별, TD갯수별 룹이 들어간 셈이니 적당히 구성된 셈이죠.
원인은 그냥 웹사이트의 응답시간 자체가 느린 것입니다.
간단히 살펴보니 00 ~ 99 까지의 키워드중에서
어떤 키워드는 페이지수가 6667이고 어떤 키워드는 몇십 페이지인데,
페이지수가 많은 키워드일수록 한 페이지 뜨는 시간이 길어지네요.
페이지수 6667인 키워드 00은 한 페이지 뜨는 데 14초 정도 걸리고
페이지수가 90인 키워드 09는 1초 정도 걸리는군요.
키워드 00만 처리하려고 해도, 14초 * 6667페이지 = 93338초 = 약 26시간 걸릴테니
모든 키워드 다 처리하려면 쉬지않고 돌려도 며칠 걸릴 것입니다.
결론은, 해당 웹사이트의 내부 DB처리를 개선하지 않으면 해결되지 않는 문제입니다.
아니면 한 페이지에 출력되는 기본형 갯수를 지금처럼 15개로 고정시키지 말고
임의의 갯수로 지정할 수 있게만 해줘도 뭉텅뭉텅 처리해서 시간을 크게 줄일 수 있겠네요.
답변 감사합니다
답변 감사합니다
기본형 갯수는 사이트에서 15개씩 출력해주고 거기서 파싱해오는 방법이라서 일단은 15개씩 하는쪽으로 해야할꺼같아요 ㅎㅎ
댓글 달기