웹 크롤링을 하기 전, 필요한 라이브러리에 대해 설명한다.
- requests
- 파이썬에서 HTTP 요청을 보내는 모듈이다.
- 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;
}
Uploaded by Notion2Tistory v1.1.0