본문 바로가기
Python

네이버 검색광고 크롤링 - 웹 크롤링 코드

by Basicer 2022. 12. 20.

문제 정의와 해결, 그리고 활용 방안

검색광고는 시장조사를 하기에 매우 유용하다. 어떤 이벤트를 진행하고 있으며, 제품의 어떤 점을 강조하고 있는지 소재를 통해 파악하기 쉽기 때문이다. 검색광고의 키워드 경쟁이 낮다면 수기로 정리하는 것도 괜찮지만, 경쟁이 높다면 검색 결과가 매우 많아 정리하기 어려움이 많다. 

나는 파이썬을 이용해 이런 문제를 해결하고자 했고, 나아가 수집된 정보를 바탕으로 제품개선에 필요한 아이디어를 얻고자 하였다. 코드만 조금 더 추가한다면 경쟁회사들의 시간대별 노출 위치도 파악할 수 있을 것이다.

만약, 마케팅 영역이 아닌 광고영역에서만 활용한다면 그리 큰 도움은 안될 것이라 생각한다. 여러 도메인에서 광고를 진행해보지는 않았지만 내 경험상 광고 성과에 영향을 주는 가장 큰 요소는 제품의 품질(서비스의 품질)이라고 생각하기 때문이다. 경쟁사의 소재를 참고하여 적용한다 하더라도 드라마틱한, 유의미한 결과를 얻기는 어려울 것이다. 차라리 순위를 높여 노출을 많이 시켜보는 것이 더 나을 수 있다.

그저 이 자료를 근거로 하여 제품을 개선할 방향을 제시하는 것을 추천한다. 결정권자에 의해서 의견이 무시당할 수도 있지만 괜찮다. 이력서에 한줄이라도 더 쓸 수 있는 경험이 발생하지 않았는가?

 

네이버 검색광고 크롤링

PC에서의 네이버 검색광고의 경우 url쿼리(pagingIndex)에 따라서 전체 광고 검색이 가능하여 requests를 이용하여 크롤링하였다.

먼저 전체 검색결과 수를 받아와서 페이지 수를 알아내고 페이지 수만큼 for문을 이용하여 검색 결과를 가져왔다.

 

총 검색결과 가져오기

def total_Web_search_count(keyword):
    base_url = "https://ad.search.naver.com/search.naver?" #베이스 url
    response = get(f"{base_url}query={keyword}&pagingIndex=1") #검색키워드의 첫번째 페이지

    if response.status_code != 200: #상태코드
        print("Can't request Web search naver")
    else:
        soup = BeautifulSoup(response.text, "html.parser")
        inner = soup.find_all('div', class_ = "inner")[0] #div의 첫번째 inner클래스에 총 검색결과가 들어있다.
        total_search = inner.find('span', class_="num_result").text #span의 num_result 클래스에서 총 검색결과 불러오기
        total = total_search.split('/')[1].strip("건") #검색결과에서 숫자만 불러오기
        search_count = int(total) #문자에서 숫자로 바꾸기
        return search_count

검색어를 입력받아 총 검색 결과값을 가져오는 코드이다. 나중에 for문을 활용하기 위해 숫자로 변환해주었다. if문은 상태 코드를 받아오기 위해서 넣긴 했지만 빼도 상관없다. 예외처리로 해주면 좋을듯한데 나는 아직 거기까지는 공부를 안 했다. 

 

전체 페이지수 계산하기

def page_count(keyword):
    page_count = math.ceil(total_Web_search_count(keyword)/25)
    return page_count

PC에서 한페이지당 노출되는 검색 결과는 25개이다. 위에서 구한 총 검색 결과에서 25를 나누어 총 페이지 수를 구하였다.

 

크롤링 값 저장하기

def extract_Web_naver(keyword):
    results = []
    search_page = page_count(keyword) #전체페이지수
    for page in range(1, search_page + 1): #1부터 전체 페이지 수만큼 돌리기
        base_url = "https://ad.search.naver.com/search.naver?" #베이스 url

        response = get(f"{base_url}query={keyword}&pagingIndex={page}") #각 페이지 url

        if response.status_code != 200: #응답코드, 빼도됨.
            print("Can't request Web search naver")
        else:
            soup = BeautifulSoup(response.text, "html.parser")
            inner = soup.find_all('div', class_ = "inner") # div inner클래스안에 검색결과값이 있다. 
            del inner[0] #첫번째 리스트는 검색수에 관한 값이므로 지워준다.
            for inner_list in inner:
                title = inner_list.find_all('span',class_ = "lnk_tit")
                bnk = 'empty'
                title_1 = title[0].text #노출되는 제목이 최대 3개. 1개 또는 2개일 경우 다른것으로 채워야함. 
                title_2 = bnk if len(title) == 1 else title[1].text
                title_3 = bnk if len(title) != 3 else title[2].text
                ad_url = inner_list.find('a', class_ = "url").string #url 가져오기, 경로가 명확해서 string 사용
                event = inner_list.find_all('p', class_ = "ad_dsc") #이벤트 내용 불러오기
                ad_promo = bnk if len(event) == 1 else event[0].text #이벤트값이 없으면 empty로 채우기
                ad_desc = event[0].text if len(event) == 1 else event[1].text
                ad_period = inner_list.find('em', class_="txt").text #광고집행기간 불러오기
                search_data = {
                    'title1' : my_eliminate(title_1),   #줄바꿈, 공백, 쉼표, 탭과 같은 파일변환시 문제되는 문자열 삭제함수
                    'title2' : my_eliminate(title_2),
                    'title3' : my_eliminate(title_3),
                    'ad_url' : ad_url,
                    'ad_event' : my_eliminate(ad_promo),
                    'ad_desc' : my_eliminate(ad_desc),
                    'ad_period': my_eliminate(ad_period)
                }
                results.append(search_data) #데이터 추가하기
    return results

검색광고에서 제목은 3개까지 노출되며 설정에 따라 랜덤 하게 노출된다. 제목을 불러올 때 리스트 형식으로 불러오게 되고 제목이 하나 또는 두 개일 경우 에러가 발생하여 각각 경우 비어있는 부분은 bnk("empty") 값을 넣어 모든 결과값이 같은 리스트 길이를 갖도록 하였다. 이벤트 또한 마찬가지 경우이다. 이벤트를 진행하는 곳은 검색 결과에 노출이 되지만 진행하지 않는 곳은 비어있기 때문에 이벤트를 진행하지 않아 값이 비어있는 곳은 위와 같은 방식으로 채워주었다. 각 결과값들은 딕셔너리 형태로 저장하고 각 페이지별로 for문을 통해 추가하도록 코드를 짜보았다. my_eliminate함수는 여기를 참고하면된다. 각 데이터에 쉼표가 들어가 있을 경우 csv파일로 변환할 때 문제가 발생하여 데이터를 전 처리하기 위해 만든 함수이다.

 

이상 끝.

 

댓글