구글·네이버 자동완성으로 "사람들이 실제로 치는 문장" 모으기 — 두 곳 모두 나오는 것만 믿었다

베리체·2026년 10월 6일
post-thumbnail

글 주제를 고를 때 늘 감에 의존했다. "이런 걸 궁금해하겠지" 싶어서 쓴 글이 아무도 찾지 않는 제목을 달고 있는 경우가 많았다. 검색량 도구는 계정이 필요하거나 유료인 경우가 많아서, 우선 누구나 볼 수 있는 신호부터 모아 보기로 했다. 검색창 자동완성이다.

자동완성은 검색량 숫자를 알려주지 않는다. 대신 많은 사람이 실제로 이어서 친 문장을 보여 준다. 구글과 네이버 두 곳에서 모두 나오는 문장이라면, 적어도 한쪽 검색엔진만의 우연은 아니라고 봤다.

1. 자동완성을 가져오는 두 요청

두 엔진 모두 브라우저가 쓰는 자동완성 주소가 있다. 공식 API가 아니라서 언제든 바뀔 수 있고, 몇십 개 단어를 가끔 확인하는 용도로만 썼다. 요청 사이에는 간격을 뒀다.

import json, time, urllib.request, urllib.parse

UA = {'User-Agent': 'Mozilla/5.0'}

def get_json(u):
    req = urllib.request.Request(u, headers=UA)
    raw = urllib.request.urlopen(req, timeout=15).read()
    return json.loads(raw.decode('utf-8', 'ignore'))

def google(q):
    u = ('https://suggestqueries.google.com/complete/search'
         '?client=firefox&hl=ko&gl=kr&q=' + urllib.parse.quote(q))
    try:
        return get_json(u)[1]
    except Exception:
        return []

def naver(q):
    u = ('https://ac.search.naver.com/nx/ac?q=%s&con=0&frm=nv&ans=2'
         '&r_format=json&r_enc=UTF-8&r_unicode=0&t_koreng=1'
         '&run=2&rev=4&q_enc=UTF-8&st=100' % urllib.parse.quote(q))
    try:
        d = get_json(u)
        return [x[0] for x in d.get('items', [[]])[0]]
    except Exception:
        return []

client=firefox로 받으면 구글은 [입력어, [후보들]] 모양의 단순한 JSON을 준다. 네이버는 items[0] 안에 후보가 한 겹 더 감싸져 있다.

2. "두 곳 모두"를 어떻게 비교할까

처음엔 문자열이 똑같은지로 비교했는데 거의 안 겹쳤다. 구글은 리디 캐시 환불, 네이버는 리디캐시 환불처럼 띄어쓰기가 달랐다. 공백을 빼고 비교하니 제대로 겹쳤다.

def both(g, n):
    ns = {x.replace(' ', '') for x in n}
    return [x for x in g if x.replace(' ', '') in ns]

for seed in SEEDS:
    g, n = google(seed), naver(seed)
    common = both(g, n)
    ...
    time.sleep(0.4)

씨앗어 25개를 넣었더니 두 곳 모두에 나온 문장이 56개였다. 네이버 쿠키 환불, esta 신청 비용, 계좌 지급정지 해제, 사업자 조회 방법 같은 것들이다. 이 목록이 생기고 나서야 글 제목을 사람들이 치는 말로 다시 다듬을 수 있었다.

3. 겪은 노이즈 세 가지

씨앗어가 쪼개졌다. 명령줄로 python keyword_demand.py 중고거래 사기 신고 스미싱처럼 넣었더니, 셸이 공백마다 인자를 나눠서 중고거래, 사기, 신고가 따로 들어갔다. 결과에 사기꾼들, 신곡, 신과함께 같은 엉뚱한 문장이 섞였다. 여러 단어짜리 씨앗어는 따옴표로 묶거나 파일로 넘겨야 한다.

짧은 단어는 전혀 다른 뜻으로 튄다. 차지백을 넣었더니 네이버에서 차지 백아절현, 현대차 지배구조가 나왔다. 1372는 1372번 버스까지 끌고 왔다. 두 엔진 공통만 남기는 필터가 이런 걸 상당히 걸러 줬지만, 1372번 버스는 양쪽에 다 있어서 살아남았다. 결국 마지막엔 사람이 한 번 훑어야 한다.

없는 게 아니라 안 나오는 것. 쇼핑몰 환불 안해줌, 유튜브 광고 쇼핑몰은 두 엔진 모두 후보가 거의 없었다. 수요가 없다는 뜻인지, 사람들이 다른 표현을 쓰는지는 자동완성만으로는 알 수 없다. 이런 건 표현을 바꿔 다시 넣어 봤다.

4. 이걸로 무엇을 바꿨나

가장 쓸모 있었던 건 이미 쓴 글의 제목이었다. "중고거래 직거래 사기"라고 달아 둔 글이 있었는데, 정작 사람들은 중고거래 사기 신고를 친다. 제목에 그 말이 한 번도 없었다. 본문이 그 내용을 다루는지 확인한 뒤 제목만 고쳤다. 본문이 받쳐 주지 않는 검색어는 수요가 있어도 넣지 않았다. 제목이 약속한 걸 본문이 안 주면 오히려 역효과라서다.

새 글도 하나 생겼다. 사기계좌 조회, 사기번호 조회가 두 엔진 모두에서 강하게 나왔는데, 막상 공식 조회 화면을 열어 보니 "최근 3개월 동안 3회 이상 신고된 번호만" 보여 준다고 적혀 있었다. 조회해서 안 나와도 안전하다는 뜻이 아니라는 점을 정리한 글을 따로 썼다.
https://veriche.co.kr/verify/scam-account-check.html

마치며

자동완성은 검색량 도구의 대체품은 아니다. 숫자가 없으니 "얼마나"는 모른다. 그래도 "사람들이 어떤 말로 묻는가"는 꽤 정확히 알려 준다. 두 엔진이 같은 문장을 내놓으면 그 문장으로 제목을 쓰고, 한쪽에만 있으면 한 번 더 의심하고, 튀는 결과는 사람이 거른다. 이 세 줄이 이번 작업에서 남은 규칙이다.

profile
공개 데이터로 온라인 거래 피해를 기록합니다. 크롤링·DNS·데이터 정리 이야기를 씁니다.

0개의 댓글