앎을 경계하기

Programming/Python

FLASK 4 - 웹 크롤링 구글검색결과 웹 페이지에 표시하기

양갱맨 2020. 12. 21. 11:06

웹 크롤링을 하기 전, 필요한 라이브러리에 대해 설명한다.

  1. requests
    • 파이썬에서 HTTP 요청을 보내는 모듈이다.
  1. BeautifulSoup
    • HTML과 XML 문서를 파싱하기 위해 사용하는 파이썬 패키지
    • 페이지에 대한 구문 분석 트리를 제공한다.

위 두 가지 라이브러리를 사용하여 구글 검색 결과를 가져와보자.

google_keyword.py

import requests
from bs4 import BeautifulSoup

def get_search_count(keyword):
    url = "https://www.google.com/search?q={}".format(keyword)
    headers = {'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.62 Safari/537.36'}
    res = requests.get(url, headers=headers)

    soup = BeautifulSoup(res.text, 'lxml')
    number = soup.select_one('#result-stats').text
    print(number)
    number = number[number.find('약',)+2:number.rfind('개')]
    number = int(number.replace(',',''))
    return {'keyword':keyword, 'number':number}

if __name__== "__main__":
  print(get_search_count("apple"))

requests.get()으로 구글에 GET요청을 보낸다.

header에서 'user-agent'는 사용자가 어떤 운영체제, 앱, 브라우저에서 요청을 보냈는지 알 수 있다. 이 헤더를 같이 전달하지 않으면 페이지 접근 차단이 되는 경우가 있는 것 같다.

Get 요청으로 받은 응답을 출력해보면 다음과 같이 HTML 소스가 들어있는 것을 확인할 수 있다.

res = requests.get(url)
print(res.text)

이제는 BeautifulSoup를 사용해서 HTML 소스를 Python 객체로 변환한다.

soup = BeautifulSoup(res.text, 'lxml')

BeautifulSoup의 첫 번째 인자는 HTML 소스코드, 두 번째 인자는 사용할 parser를 넣어준다.

결과값을 가져오기 위해 select_one()을 사용한다.

select()select_one()을 사용하여 요소를 가져올 수 있는데 차이는 다음과 같다.

  • select_one 사용시
  • select 사용시

검색결과 약 3,760,000,000개 (0.54초) 라는 결과에서 개수만 남기기 위해 리스트를 슬라이싱한다.

number = number[number.find('약',)+2:numver.rfind('개')]
number = int(number.replace(',', ''))

검색어와 검색 결과 수에 대한 결과를 dictionary 형태로 반환한다.

return {'keyword':keyword, 'number':number}

반환값 {'keyword': 'apple', 'number': 3760000000}을 얻을 수 있다.


위에서 진행한 크롤링 검색 결과를 Flask에서 참조해보자

from flask import Flask, render_template, request # request 추가
import google_keyword #크롤링 파이썬 파일 import

app = Flask(__name__)

@app.route("/", methods=["GET", "POST"]) # 접속 url
def index():
		# page에서 두 개의 키워드 입력받음
    print(request.form.get('keyword1'))
    print(request.form.get('keyword2'))
    keyword1 = request.form.get('keyword1')
    keyword2 = request.form.get('keyword2')

    # 두 개의 키워드 모두 결과가 있을 때만 검색 결과 반환
    if keyword1 is not None and keyword2 is not None:
        data = {
            keyword1 : google_keyword.get_search_count(keyword1).get('number'),
            keyword2 : google_keyword.get_search_count(keyword2).get('number')
        }
        return render_template("index.html", data = data)
    else:
        return render_template("index.html")

if __name__=="__main__":
    app.run(host="127.0.0.1", port="1234", debug=True)

Flask는 jinja2 엔진을 사용하기 때문에 템플릿을 이용하여 html을 작성할 수 있다.

  • if 문법

    if 조건식, if의 끝으로 표현된다.

    {% if data %}
    {% endif %}
  • json(또는 dict) 반복하기

    python의 딕셔너리를 반복할 때와 비슷함.

    {% for k,v in data.items() %}
    {{k}} {{v}}
    {% endfor %}
  • loop.index 문법

    jinja2 템플릿 반복문에서 {{loop.index}}를 하면 자동으로 반복횟수가 들어간다. 카운트는 1부터 시작한다.

    {% for k,v in data.items() %}
    {{loop.index}}
    {% endfor %}
  • while space 제거

    아래와 같이 코드를 작성하면 HTML 자체에서 element 간격을 자동으로 4px 조정한다.

    {% for k,v in data.items() %}
    	<div class="box{{loop.index}}" vlaue="{{v}}">{{k}}</div>
    {% endfor %}

    이에 대한 간편한 해결책은 1줄로 코드를 작성해주면 된다.

    {% for k,v in data.items() %}<div class="box{{loop.index}}" vlaue="{{v}}">{{k}}</div>{% endfor %}

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>페이지 제목</title>
        <link rel='stylesheet' href="{{ url_for('static', filename='css/style.css')}}">
    </head>
    <body>
        <h1>H1 태그 사용</h1>
        
        <form action="/" method="get">
            <p><label for="keyword1"></label>Keyword1 : <input type="text" name="keyword1" id="keyword1"></p>
            <p><label for="keyword2"></label>Keyword2 : <input type="text" name="keyword2" id="keyword2"></p>
            
            <input type="submit" value="전송하기">
        </form>

        {% if data %}
        <div id="reuslt">
            {% for k, v in data.items() %}<div class="box{{loop.index}}" value="{{v}}">{{k}}</div>{% endfor%}
        </div>
        {% endif %}

        <script src="{{url_for('static', filename='js/index.js')}}"></script>
    </body>
</html>

<실행 결과>

css로 index.html에 표시되는 박스들의 스타일을 변경해준다.

.box{
    border:5px solid black;
    width : 200px;
    height: 100px;
    display: inline-block;
    box-sizing: border-box;
    margin : 0;
    color : white;
    font-weight: 900;
    text-align: center;
    line-height: 90px;
}

.box1{
    background-color: orange;
}

.box2{
    background-color : blue;
}