python scrapper 디버깅 과정 1 - 검색속도느림 해결

YEONGHUN KO·2021년 11월 17일
0

PYTHON - SCRAPPER

목록 보기
13/17
post-thumbnail

스크래퍼가 느린 이유

scrapper기능과 디자인은 완성이 되었다. 그러나 여전히 아쉬운점이 존재했다.
결과 검색까지 오래 걸리는 이유를 총 3가지로 추릴 수 있다.

1.모든 결과값을 불러오기 때문

2.logo를 추출하기 위해 requests 함수를 2번 사용하기 때문

3.stackoverflow 사이트같은 경우 MAX_COUNT 가 2개의 for문 중 안쪽 for 문에 위치해있기 때문

그래서 위의 3가지 경우를 어떻게 해결했는지 서술하려 한다.

1. 모든값을 불러 오는 경우

이경우에, 결과값이 많으면 3분정도까지 걸리는 것 같다. 굉장히 긴 시간이다. 그 이유는 검색된 모든값을 저장하려고 한다는 점이다. 따라서 remote, stack, we-work 3개의 웹사이트에서 각각 50개씩만 결과를 불러들이도록 했다.

MAX_COUNT = 50 #MAX_COUNT라는 변수를 맨위에 보기쉽게 추가했다.

def get_job_data(keyword):
    print("remote job scrapping...")
    jobs = []
    # remote website doesn't support # and + character
    keyword = keyword.replace("+","plus").replace("#","sharp")
    url = f"https://remoteok.io/remote-{keyword}-jobs"
    result = requests.get(url, headers = headers)
    soup = BeautifulSoup(result.text, "html.parser")
    element = soup.find("table", {"id":"jobsboard"})
    if element:
        job_data = element.findAll("tr", {"class":"job"})
    else:
        print("not found")
        job_data = None
    if job_data:
        for ele in job_data:
            data = extract_job(ele)
            jobs.append(data)
            length = len(jobs) #그리고 jobs 리스트의 길이를 설정하고
            if length >= MAX_COUNT: # 길이가 MAX_COUNT보다 길경우 break하여 함수가 끝나도록 했다.
                break
            else:
                continue
    return jobs

MAX_COUNT 를 맨 위에 선언함으로써 강조하는 효과도 있고, 출력되는 값의 갯수를 변경하고 싶을때 신속하게 변경할 수 있게 하기 위함이다.

2. requests 함수를 2번 사용하기 때문

requests 함수는 url에 접속해서 -> 그 웹의 모든 정보를 불러들이기 때문에 시간이 오래걸린다. 왜 2번이나 사용했냐고 한다면, logo를 뽑아내기 위해서다. 검색하고 뜨는 웹창에서 검색을 눌러 logo를 추출하려 했으나 style="background-url("http:ww~~") 라고 되어있었기 때문에 괄호안에 logo url을 추출하는게 불가능하다고 생각했었다. 따라서 링크 url에 들어가서 거기서 logo를 추출하기로 했었던 것이다.
하지만 replace 함수를 통해 괄호밖에 있는 것을 strip하여 괄호안에있는것을 출력할 수 있음을 알아냈다.

(logo url이 괄호안에 묶여있다. 저 부분만 추출할 수는 없을까? 바로 replace를 사용하면 된다!)

try:
    logo = data.find("div", {"class":"flag-logo"})
    if logo:
        logo = logo["style"].replace("background-image:url(","").replace(")","") #그럼 background-image:url()이 빈공간으로 대체되면서 logo url 만 추출할 수 있다.     
except:
    logo = "no logo"

3. stackoverflow 사이트같은 경우 MAX_COUNT 가 2개의 for문 중 안쪽 for 문에 위치해있기 때문

이렇게 해서 다시 scrapper 사이트에들어가서 키워드를 검색했다.

remote scrapping...
we_work scrapping...

은 몇초만에 넘어갔으나 stackover scrapping..은 1분이상 걸렸다. MAX_COUNT/ replace를 통한 request중첩 제거 했는데도 뭐가 문제인지 살짝 짜증이 났다. stackover.py의 코드를 살펴보고 테스팅 해본 결과 MAX_COUNT/break가 2개의 for문중 안쪽 for문에만 있었기 때문에 그렇다는것을 알아냈다. 그래서 break 되더라도 바깥쪽 for문이 여전히 작동하기 때문에 완전히 break 되지 않은 것이다.

따라서, boolean을 변수를 설정하고 MAX_PAGE가 50이 되면 boolean이 TRUE가 되도록 하였다. 그리고 TRUE가 되면 바깥쪽 for 문도 break 되는걸로 코드를 짰다.

def extract_data(last_page, url):   
    jobs = [] 
    is_full_array = False # 초기 boolean 타입을 FALSE로 설정하였다.
    print("stack jobs scrapping...")
    for page in range(last_page):
        
        # print(f"Scrapping SO Page:{page}")
        result = requests.get(f"{url}&pg={page + 1}", headers = headers)
        soup = BeautifulSoup(result.text, "html.parser")
        results = soup.find_all("div", {"class":"-job"} )
        if results:
            job_data = soup.find_all("div", {"class":"-job"} )
        else:
            print("not found")
            job_data = None
        if job_data:
            for result in job_data:
                job = extract_job(result)
                jobs.append(job)
                length = len(jobs)
                if length >= MAX_COUNT:
                    is_full_array = True # 그리고 MAX_COUNT 를 넘으면 boolean의 값이 TRUE가 되도록 했다.
                    break
                else:
                    continue     
            if is_full_array: # 안쪽포문이 끝나고 boolean이 TRUE 면 break 되도록 바깥쪽 for문에 코드를 작성했다. 그래서 안쪽 for문이 중단되면서 동시에 바깥쪽 for 문도 중단되도록 설정했다.
                break

    return jobs

그 결과 검색결과까지 걸리는 시간이 길어 봤자 15초를 넘지 않는 것을 확인 할 수 있었다. 하지만 여전히 예외상황은 존재하였다. 바로 c#과 같은 특수문자를 입력했을때 remote 사이트에서 인지하지 못한다는 것이다. 그 예외처리는 다음 글에서 포스팅 하겠다.

profile
'과연 이게 최선일까?' 끊임없이 생각하기

0개의 댓글