모듈 설치
요청 및 응답 등의 통신을 위한 requests 모듈을 설치합니다.
pip install requests
(crawling_blog) PS C:\Users\Desktop\pyqt\Example\begin_for_blog\2> pip install requests
Collecting requests
Using cached requests-2.24.0-py2.py3-none-any.whl (61 kB)
Collecting idna<3,>=2.5
Using cached idna-2.10-py2.py3-none-any.whl (58 kB)
Collecting chardet<4,>=3.0.2
Using cached chardet-3.0.4-py2.py3-none-any.whl (133 kB)
Collecting urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1
Using cached urllib3-1.25.9-py2.py3-none-any.whl (126 kB)
Requirement already satisfied: certifi>=2017.4.17 in c:\users\.conda\envs\crawling_blog\lib\site-packages (from requests) (2020.6.20)
Installing collected packages: idna, chardet, urllib3, requests
Successfully installed chardet-3.0.4 idna-2.10 requests-2.24.0 urllib3-1.25.9
parsing 하여 tag 를 잡을 수 있게 해주는 BeautifulSoup 모듈을 설치합니다.
(crawling_blog) PS C:\Users\Desktop\pyqt\Example\begin_for_blog\2> pip install bs4
Processing c:\users\appdata\local\pip\cache\wheels\a0\b0\b2\4f80b9456b87abedbc0bf2d52235414c3467d8889be38dd472\bs4-0.0.1-cp36-none-any.whl
Collecting beautifulsoup4
Using cached beautifulsoup4-4.9.1-py3-none-any.whl (115 kB)
Collecting soupsieve>1.2
Using cached soupsieve-2.0.1-py3-none-any.whl (32 kB)
Installing collected packages: soupsieve, beautifulsoup4, bs4
Successfully installed beautifulsoup4-4.9.1 bs4-0.0.1 soupsieve-2.0.1
코드
크롤러 클래스의 전체 코드입니다.
import requests
from bs4 import BeautifulSoup as bs
class GoogleWeather():
url = 'https://www.google.com/search?q={}&rlz=1C1EJFA_enKR770KR770&oq=%EC%86%A1%ED%8C%8C%EA%B5%AC+%EB%82%A0%EC%94%A8&aqs=chrome..69i57.2835j0j8&sourceid=chrome&ie=UTF-8'
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36'
}
result = []
def __init__(self, keyword=None):
self.keyword = keyword
def set_keyword(self, keyword):
self.keyword = keyword
def run(self):
res = requests.get(self.url.format(self.keyword), headers=self.headers)
self.parse_html(res.text)
return res
def parse_html(self, text):
html = bs(text, 'html.parser')
loc = html.find('div', {'id': 'wob_loc'})
loc = loc.string if loc else loc
time = html.find('div', {'id': 'wob_dts'})
time = time.string if time else time
status = html.find('span', {'id': 'wob_dc'})
status = status.string if status else status
self.result.append({
'loc': loc,
'time': time,
'status': status
})
def get_result(self):
if self.result:
return self.result[-1]
else:
return None
if __name__ == '__main__':
crawler = GoogleWeather()
while True:
k = input('지역명 >> ')
crawler.set_keyword(k + ' 날씨')
crawler.run()
r = crawler.get_result()
for v in r.values(): print(v)
print('-'*50)
팁
개발자 도구를 열어서 이것 저것 확인을 해야합니다.
개발자 도구(F12) - Network - F15
통신방식(GET / POST)을 확인합니다.
GET 입니다.
res = requests.get(self.url.format(self.keyword), headers=self.headers)
Queary String Parameters 에는 요청시 파라미터들이 나와있고, 이 파라미터들을 url에 붙여서 요청하게 됩니다.
(지금은 '날씨' 와 기타 등등.)
requests.get(url, headers, params=params) 이러한 방식도 있습니다.
여기서는 쉽게 할 수 있는 방법을 소개합니다.
검색한 결과의 URL을 가져옵니다.
개발자 도구에 보면 다음과 같이 q 라는 파라미터에 키워드가 들어가는 것을 확인할 수 있습니다.
이렇게 하면 되겠죠.
마지막에 요청시에만 keyword를 저장한 변수로 문자열을 완성합니다.
url = 'https://www.google.com/search?q={}&rlz=1C1EJFA_enKR770KR770&oq=%EC%86%A1%ED%8C%8C%EA%B5%AC+%EB%82%A0%EC%94%A8&aqs=chrome..69i57.2835j0j8&sourceid=chrome&ie=UTF-8'
...
res = requests.get(self.url.format(self.keyword), headers=self.headers)
또한, 구글 검색은 headers의 user-agent 가 포함되야합니다.
Requests Headers 가 내가 요청시에 보낸 Headers 입니다.
그 안에 user-agent를 복사해서 가져옵니다.
코드로는 다음과 같겠습니다.
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36'
}
...
res = requests.get(self.url.format(self.keyword), headers=self.headers)
이렇게 받은 응답을 보면 200 정상적인 응답이라고 합니다.
다만, 200이라고 안의 컨텐츠들이 내가 원하는 컨텐츠라고 장담할 수는 없습니다.
(예를들어, 자동 로그인을 만드는데 정상 응답에 컨텐츠가 '잘못된 패스워드입니다' 일 수도 있습니다.)
if __name__ == '__main__':
crawler = GoogleWeather()
crawler.set_keyword('송파구 날씨')
r = crawler.run()
print(r)
print(type(r.text))
<Response [200]>
<class 'str'>
정상적으로 요청과 응답을 받았으면, 이제 내가 원하는 정보를 잡아야겠죠.
BeautifulSoup 을 이용해서 parsing 을 하면 태그를 잡을 수 있습니다.
def run(self):
res = requests.get(self.url.format(self.keyword), headers=self.headers)
self.parse_html(res.text)
return res
def parse_html(self, text):
html = bs(text, 'html.parser')
loc = html.find('div', {'id': 'wob_loc'})
loc = loc.string if loc else loc
time = html.find('div', {'id': 'wob_dts'})
time = time.string if time else time
status = html.find('span', {'id': 'wob_dc'})
status = status.string if status else status
self.result.append({
'loc': loc,
'time': time,
'status': status
})
원하는 정보에 우클릭하고 요소 보기를 하면 다음과 같이 태그, 속성들이 보입니다.
class, id 두 개다 사용할 수 있겠습니다.
보통 id 가 유일하게 식별될 확률이 높습니다.
다음 코드를 통해 해당 태그를 잡을 수 있고
loc = html.find('div', {'id': 'wob_loc'})
그 태그에서 text 만을 추출합니다. (비슷한 함수들이 있고 차이점도 존재합니다.)
loc.get_text()
loc.Text()
loc.string
에러가 발생하지 않도록, 태그에 접근이 가능할 때만 text를 추출할 수 있도록 처리합니다.
(태그가 접근이 불가하면 None을 반환)
loc = html.find('div', {'id': 'wob_loc'})
loc = loc.string if loc else loc
활용
이렇게 모듈화한 크롤러는 제가 주로 다루고 있는 파이큐티(PyQt5), 텔레그램 봇 으로도 활용이 쉬워집니다.
'Crawling > Basic' 카테고리의 다른 글
파이썬 다음-뉴스 댓글 크롤링 하기 -2 : 동적인 데이터를 수집하는 방법 (0) | 2020.08.09 |
---|---|
파이썬 다음-뉴스 크롤링 하기 -1 (0) | 2020.08.07 |
파이썬 크롤링할 범위를 구하는 방법 (0) | 2020.08.07 |
아이피 우회하여 크롤링하기 tor / requests[socks] (0) | 2020.08.03 |
정규표현식으로 태그 추출하기 (0) | 2020.07.27 |